From noreply at buildbot.pypy.org Wed May 1 00:13:31 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 00:13:31 +0200 (CEST) Subject: [pypy-commit] pypy py3k: skip this test on ascii or similar fsencodings Message-ID: <20130430221331.1FF961C0246@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63778:2a5856d48bbf Date: 2013-04-30 15:03 -0700 http://bitbucket.org/pypy/pypy/changeset/2a5856d48bbf/ Log: skip this test on ascii or similar fsencodings diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py --- a/pypy/module/cpyext/test/test_unicodeobject.py +++ b/pypy/module/cpyext/test/test_unicodeobject.py @@ -297,8 +297,11 @@ assert s == "12ሴ" def test_encode_fsdefault(self, space, api): - w_u = space.wrap(u'sp\udcc3\udca4m') + w_u = space.wrap(u'sp�m') w_s = api.PyUnicode_EncodeFSDefault(w_u) + if w_s is None: + api.PyErr_Clear() + py.test.skip("Requires a unicode-aware fsencoding") with rffi.scoped_str2charp(space.str_w(w_s)) as encoded: w_decoded = api.PyUnicode_DecodeFSDefaultAndSize(encoded, space.len_w(w_s)) assert space.eq_w(w_decoded, w_u) From noreply at buildbot.pypy.org Wed May 1 00:52:48 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 00:52:48 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix under appdirect Message-ID: <20130430225248.3D64C1C0334@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63779:52baabd4e81f Date: 2013-04-30 15:52 -0700 http://bitbucket.org/pypy/pypy/changeset/52baabd4e81f/ Log: fix under appdirect diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py --- a/pypy/objspace/std/test/test_obj.py +++ b/pypy/objspace/std/test/test_obj.py @@ -9,11 +9,8 @@ from pypy.interpreter import gateway import sys - cpython_behavior = (not option.runappdirect - or not hasattr(sys, 'pypy_translation_info')) - space = cls.space - cls.w_cpython_behavior = space.wrap(cpython_behavior) + cls.w_cpython_behavior = space.wrap(not option.runappdirect) cls.w_cpython_version = space.wrap(tuple(sys.version_info)) cls.w_appdirect = space.wrap(option.runappdirect) cls.w_cpython_apptest = space.wrap(option.runappdirect and not hasattr(sys, 'pypy_translation_info')) From noreply at buildbot.pypy.org Wed May 1 03:19:24 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 03:19:24 +0200 (CEST) Subject: [pypy-commit] pypy default: cleanup imports Message-ID: <20130501011924.E481B1C0246@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63780:3b9de8a7eec4 Date: 2013-04-30 17:43 -0700 http://bitbucket.org/pypy/pypy/changeset/3b9de8a7eec4/ Log: cleanup imports diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -1,30 +1,23 @@ +"""The builtin bytearray implementation""" + +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter.signature import Signature +from pypy.objspace.std import stringobject +from pypy.objspace.std.bytearraytype import ( + getbytevalue, makebytearraydata_w, new_bytearray) +from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.listobject import get_list_index, get_positive_index +from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject -from rpython.rlib.rarithmetic import intmask -from rpython.rlib.rstring import StringBuilder -from rpython.rlib.debug import check_annotation -from pypy.objspace.std import stringobject -from pypy.objspace.std.intobject import W_IntObject -from pypy.objspace.std.listobject import get_positive_index, get_list_index +from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.strutil import ParseStringError -from pypy.objspace.std.strutil import string_to_float from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject -from pypy.objspace.std import slicetype -from pypy.interpreter import gateway -from pypy.interpreter.buffer import RWBuffer -from pypy.interpreter.signature import Signature -from pypy.objspace.std.bytearraytype import ( - makebytearraydata_w, getbytevalue, - new_bytearray -) -from rpython.tool.sourcetools import func_with_new_name +from rpython.rlib.rstring import StringBuilder class W_BytearrayObject(W_Object): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -1,25 +1,24 @@ -from pypy.objspace.std.model import registerimplementation, W_Object +"""The builtin str implementation""" + +from pypy.interpreter.buffer import StringBuffer +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.objspace.std import newformat, slicetype +from pypy.objspace.std.formatting import mod_format +from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.model import W_Object, registerimplementation +from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter import gateway +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.stringtype import ( + joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) +from pypy.objspace.std.tupleobject import W_TupleObject +from rpython.rlib import jit +from rpython.rlib.objectmodel import ( + compute_hash, compute_unique_id, specialize) from rpython.rlib.rarithmetic import ovfcheck -from rpython.rlib.objectmodel import we_are_translated, compute_hash, specialize -from rpython.rlib.objectmodel import compute_unique_id -from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype, newformat -from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.noneobject import W_NoneObject -from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib.rstring import StringBuilder, split -from pypy.interpreter.buffer import StringBuffer -from rpython.rlib import jit -from pypy.objspace.std.stringtype import sliced, wrapstr, wrapchar, \ - stringendswith, stringstartswith, joined2 - -from pypy.objspace.std.formatting import mod_format class W_AbstractStringObject(W_Object): __slots__ = () diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -1,24 +1,26 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +"""The builtin unicode implementation""" + +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.module.unicodedata import unicodedb +from pypy.objspace.std import newformat, slicetype +from pypy.objspace.std.formatting import mod_format +from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.std.stringobject import W_StringObject, make_rsplit_with_delim from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype, newformat +from pypy.objspace.std.stringobject import ( + W_StringObject, make_rsplit_with_delim) +from pypy.objspace.std.stringtype import stringendswith, stringstartswith +from pypy.objspace.std.register_all import register_all from pypy.objspace.std.tupleobject import W_TupleObject -from rpython.rlib.rarithmetic import intmask, ovfcheck -from rpython.rlib.objectmodel import compute_hash, specialize -from rpython.rlib.objectmodel import compute_unique_id +from rpython.rlib import jit +from rpython.rlib.rarithmetic import ovfcheck +from rpython.rlib.objectmodel import ( + compute_hash, compute_unique_id, specialize) from rpython.rlib.rstring import UnicodeBuilder from rpython.rlib.runicode import make_unicode_escape_function -from pypy.module.unicodedata import unicodedb from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib import jit -from pypy.objspace.std.formatting import mod_format -from pypy.objspace.std.stringtype import stringstartswith, stringendswith class W_AbstractUnicodeObject(W_Object): __slots__ = () From noreply at buildbot.pypy.org Wed May 1 03:19:26 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 03:19:26 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130501011926.4D2D31C0246@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63781:6a38c7006aed Date: 2013-04-30 18:18 -0700 http://bitbucket.org/pypy/pypy/changeset/6a38c7006aed/ Log: merge default diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -37,15 +37,16 @@ return '%s #%d %s' % (reprs, next_instr, name) def get_jitcell_at(next_instr, is_being_profiled, bytecode): - return bytecode.jit_cells.get((next_instr, is_being_profiled), None) + # use only uints as keys in the jit_cells dict, rather than + # a tuple (next_instr, is_being_profiled) + key = (next_instr << 1) | r_uint(intmask(is_being_profiled)) + return bytecode.jit_cells.get(key, None) def set_jitcell_at(newcell, next_instr, is_being_profiled, bytecode): - bytecode.jit_cells[next_instr, is_being_profiled] = newcell + key = (next_instr << 1) | r_uint(intmask(is_being_profiled)) + bytecode.jit_cells[key] = newcell -def can_never_inline(next_instr, is_being_profiled, bytecode): - return False - def should_unroll_one_iteration(next_instr, is_being_profiled, bytecode): return (bytecode.co_flags & CO_GENERATOR) != 0 @@ -57,7 +58,6 @@ pypyjitdriver = PyPyJitDriver(get_printable_location = get_printable_location, get_jitcell_at = get_jitcell_at, set_jitcell_at = set_jitcell_at, - can_never_inline = can_never_inline, should_unroll_one_iteration = should_unroll_one_iteration, name='pypyjit') diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -1,28 +1,21 @@ +"""The builtin bytearray implementation""" + +from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.objspace.std import stringobject +from pypy.objspace.std.bytearraytype import new_bytearray from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.listobject import get_list_index, get_positive_index +from pypy.objspace.std.longobject import W_LongObject +from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject -from rpython.rlib.rarithmetic import intmask +from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.sliceobject import W_SliceObject +from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.stringtype import getbytevalue, makebytesdata_w +from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib.rstring import StringBuilder -from rpython.rlib.debug import check_annotation -from pypy.objspace.std import stringobject -from pypy.objspace.std.intobject import W_IntObject -from pypy.objspace.std.longobject import W_LongObject -from pypy.objspace.std.listobject import get_positive_index, get_list_index -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.strutil import ParseStringError -from pypy.objspace.std.strutil import string_to_float -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.unicodeobject import W_UnicodeObject -from pypy.objspace.std import slicetype -from pypy.interpreter import gateway -from pypy.interpreter.buffer import RWBuffer -from pypy.objspace.std.stringtype import makebytesdata_w, getbytevalue -from pypy.objspace.std.bytearraytype import new_bytearray -from rpython.tool.sourcetools import func_with_new_name class W_BytearrayObject(W_Object): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -1,24 +1,24 @@ -from pypy.objspace.std.model import registerimplementation, W_Object +"""The builtin bytes implementation""" + +from pypy.interpreter.buffer import StringBuffer +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.objspace.std import slicetype +from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.longobject import W_LongObject +from pypy.objspace.std.model import W_Object, registerimplementation +from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter import gateway +from pypy.objspace.std.sliceobject import W_SliceObject +from pypy.objspace.std.stringtype import ( + joined2, sliced, stringendswith, stringstartswith, wrapstr) +from pypy.objspace.std.tupleobject import W_TupleObject +from rpython.rlib import jit +from rpython.rlib.objectmodel import ( + compute_hash, compute_unique_id, specialize) from rpython.rlib.rarithmetic import ovfcheck -from rpython.rlib.objectmodel import we_are_translated, compute_hash, specialize -from rpython.rlib.objectmodel import compute_unique_id -from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype, newformat -from pypy.objspace.std.longobject import W_LongObject -from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.noneobject import W_NoneObject -from pypy.objspace.std.tupleobject import W_TupleObject -from rpython.rlib.rstring import StringBuilder, split -from pypy.interpreter.buffer import StringBuffer -from rpython.rlib import jit +from rpython.rlib.rstring import StringBuilder -from pypy.objspace.std.stringtype import sliced, wrapstr, wrapchar, \ - stringendswith, stringstartswith, joined2 class W_AbstractStringObject(W_Object): __slots__ = () diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -1,24 +1,25 @@ -from pypy.objspace.std.model import registerimplementation, W_Object +"""The builtin str implementation""" + +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.module.unicodedata import unicodedb +from pypy.objspace.std import newformat, slicetype +from pypy.objspace.std.formatting import mod_format +from pypy.objspace.std.model import W_Object, registerimplementation +from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.noneobject import W_NoneObject +from pypy.objspace.std.sliceobject import W_SliceObject +from pypy.objspace.std.stringobject import make_rsplit_with_delim +from pypy.objspace.std.stringtype import stringendswith, stringstartswith from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.objspace.std.stringobject import W_StringObject, make_rsplit_with_delim -from pypy.objspace.std.noneobject import W_NoneObject -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype, newformat from pypy.objspace.std.tupleobject import W_TupleObject -from rpython.rlib.rarithmetic import intmask, ovfcheck -from rpython.rlib.objectmodel import compute_hash, specialize -from rpython.rlib.objectmodel import compute_unique_id +from rpython.rlib import jit +from rpython.rlib.rarithmetic import ovfcheck +from rpython.rlib.objectmodel import ( + compute_hash, compute_unique_id, specialize) from rpython.rlib.rstring import UnicodeBuilder from rpython.rlib.runicode import make_unicode_escape_function -from pypy.module.unicodedata import unicodedb from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib import jit -from pypy.objspace.std.formatting import mod_format -from pypy.objspace.std.stringtype import stringstartswith, stringendswith class W_AbstractUnicodeObject(W_Object): __slots__ = () diff --git a/rpython/rlib/types.py b/rpython/rlib/types.py --- a/rpython/rlib/types.py +++ b/rpython/rlib/types.py @@ -7,6 +7,10 @@ return model.s_None +def impossible(): + return model.s_ImpossibleValue + + def float(): return model.SomeFloat() diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -934,8 +934,8 @@ if tp is lltype.SingleFloat: return 4 if tp is lltype.LongFloat: - import ctypes # :-/ - return ctypes.sizeof(ctypes.c_longdouble) + # :-/ + return sizeof_c_type("long double") assert isinstance(tp, lltype.Number) if tp is lltype.Signed: return LONG_BIT/8 diff --git a/rpython/translator/cli/test/test_list.py b/rpython/translator/cli/test/test_list.py --- a/rpython/translator/cli/test/test_list.py +++ b/rpython/translator/cli/test/test_list.py @@ -13,6 +13,9 @@ def test_getitem_exc_2(self): py.test.skip('fixme!') + def test_reversed(self): + py.test.skip("unsupported") + def test_list_unsigned(self): def fn(x): lst = [r_uint(0), r_uint(1)] diff --git a/rpython/translator/jvm/test/test_list.py b/rpython/translator/jvm/test/test_list.py --- a/rpython/translator/jvm/test/test_list.py +++ b/rpython/translator/jvm/test/test_list.py @@ -15,6 +15,9 @@ def test_r_short_list(self): py.test.skip('fixme!') + def test_reversed(self): + py.test.skip("unsupported") + def test_zeroed_list(self): def fn(): lst = [0] * 16 diff --git a/rpython/translator/oosupport/test/test_treebuilder.py b/rpython/translator/oosupport/test/test_treebuilder.py --- a/rpython/translator/oosupport/test/test_treebuilder.py +++ b/rpython/translator/oosupport/test/test_treebuilder.py @@ -13,7 +13,7 @@ t = TranslationContext() t.buildannotator().build_types(func, argtypes) t.buildrtyper(type_system='ootype').specialize() - + if backendopt: backend_optimizations(t, merge_if_blocks=True) return t @@ -121,4 +121,5 @@ return interp.eval_graph(graph, args) class TestBuildTreeList(BuildTreeRtypingTest, BaseTestRlist): - pass + def test_reversed(self): + py.test.skip("unsupported on ootype") diff --git a/rpython/translator/platform/arm.py b/rpython/translator/platform/arm.py --- a/rpython/translator/platform/arm.py +++ b/rpython/translator/platform/arm.py @@ -18,9 +18,13 @@ class ARM(Linux): name = "arm" - available_includedirs = (SB2 + '/usr/include', '/tmp') + available_librarydirs = [SB2 + '/usr/lib/arm-linux-gnueabi/', + SB2 + '/usr/lib/arm-linux-gnueabihf/'] + available_includedirs = [SB2 + '/usr/include/arm-linux-gnueabi/', + SB2 + '/usr/include/arm-linux-gnueabihf/'] copied_cache = {} + def _invent_new_name(self, basepath, base): pth = basepath.join(base) num = 0 @@ -47,12 +51,13 @@ return ExecutionResult(returncode, stdout, stderr) def include_dirs_for_libffi(self): - return [SB2 + '/usr/include/arm-linux-gnueabi/', - SB2 + '/usr/include/arm-linux-gnueabihf/'] + return self.available_includedirs def library_dirs_for_libffi(self): - return [SB2 + '/usr/lib/arm-linux-gnueabi/', - SB2 + '/usr/lib/arm-linux-gnueabihf/'] + return self.available_librarydirs + + def _preprocess_library_dirs(self, library_dirs): + return list(library_dirs) + self.available_librarydirs def execute_makefile(self, path_to_makefile, extra_opts=[]): if isinstance(path_to_makefile, GnuMakefile): diff --git a/rpython/translator/sandbox/rsandbox.py b/rpython/translator/sandbox/rsandbox.py --- a/rpython/translator/sandbox/rsandbox.py +++ b/rpython/translator/sandbox/rsandbox.py @@ -100,7 +100,7 @@ else: raise RuntimeError - at signature(types.str(), returns=types.none()) + at signature(types.str(), returns=types.impossible()) def not_implemented_stub(msg): STDERR = 2 buf = rffi.str2charp(msg + '\n') From noreply at buildbot.pypy.org Wed May 1 03:42:19 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 03:42:19 +0200 (CEST) Subject: [pypy-commit] pypy default: refactor Message-ID: <20130501014219.064B21C33BB@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63782:ba2b2f2160e8 Date: 2013-04-30 18:34 -0700 http://bitbucket.org/pypy/pypy/changeset/ba2b2f2160e8/ Log: refactor diff --git a/lib-python/2.7/distutils/command/install.py b/lib-python/2.7/distutils/command/install.py --- a/lib-python/2.7/distutils/command/install.py +++ b/lib-python/2.7/distutils/command/install.py @@ -474,8 +474,8 @@ def select_scheme (self, name): # it's the caller's problem if they supply a bad name! - if hasattr(sys, 'pypy_version_info') and not ( - name.endswith('_user') or name.endswith('_home')): + if (hasattr(sys, 'pypy_version_info') and + not name.endswith(('_user', '_home'))): name = 'pypy' scheme = INSTALL_SCHEMES[name] for key in SCHEME_KEYS: From noreply at buildbot.pypy.org Wed May 1 03:42:20 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 03:42:20 +0200 (CEST) Subject: [pypy-commit] pypy py3k: apply the home/user distutils scheme fix from default (5b253d146851) Message-ID: <20130501014220.6518B1C33BC@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63783:1e656277959b Date: 2013-04-30 18:41 -0700 http://bitbucket.org/pypy/pypy/changeset/1e656277959b/ Log: apply the home/user distutils scheme fix from default (5b253d146851) diff --git a/lib-python/3/distutils/command/install.py b/lib-python/3/distutils/command/install.py --- a/lib-python/3/distutils/command/install.py +++ b/lib-python/3/distutils/command/install.py @@ -489,7 +489,8 @@ def select_scheme(self, name): """Sets the install directories by applying the install schemes.""" # it's the caller's problem if they supply a bad name! - if hasattr(sys, 'pypy_version_info'): + if (hasattr(sys, 'pypy_version_info') and + not name.endswith(('_user', '_home'))): name = 'pypy' scheme = INSTALL_SCHEMES[name] for key in SCHEME_KEYS: diff --git a/lib-python/3/distutils/sysconfig_pypy.py b/lib-python/3/distutils/sysconfig_pypy.py --- a/lib-python/3/distutils/sysconfig_pypy.py +++ b/lib-python/3/distutils/sysconfig_pypy.py @@ -9,6 +9,7 @@ PREFIX = os.path.normpath(sys.prefix) +EXEC_PREFIX = os.path.normpath(sys.exec_prefix) project_base = os.path.dirname(os.path.abspath(sys.executable)) python_build = False @@ -94,6 +95,9 @@ else: _config_vars = {} + _config_vars['prefix'] = PREFIX + _config_vars['exec_prefix'] = EXEC_PREFIX + if args: vals = [] for name in args: diff --git a/lib-python/3/distutils/tests/test_install.py b/lib-python/3/distutils/tests/test_install.py --- a/lib-python/3/distutils/tests/test_install.py +++ b/lib-python/3/distutils/tests/test_install.py @@ -6,7 +6,7 @@ import unittest import site -from test.support import captured_stdout, check_impl_detail, run_unittest +from test.support import captured_stdout, run_unittest from distutils import sysconfig from distutils.command.install import install @@ -58,15 +58,14 @@ expected = os.path.normpath(expected) self.assertEqual(got, expected) - if check_impl_detail(): - libdir = os.path.join(destination, "lib", "python") - check_path(cmd.install_lib, libdir) - check_path(cmd.install_platlib, libdir) - check_path(cmd.install_purelib, libdir) - check_path(cmd.install_headers, - os.path.join(destination, "include", "python", "foopkg")) - check_path(cmd.install_scripts, os.path.join(destination, "bin")) - check_path(cmd.install_data, destination) + libdir = os.path.join(destination, "lib", "python") + check_path(cmd.install_lib, libdir) + check_path(cmd.install_platlib, libdir) + check_path(cmd.install_purelib, libdir) + check_path(cmd.install_headers, + os.path.join(destination, "include", "python", "foopkg")) + check_path(cmd.install_scripts, os.path.join(destination, "bin")) + check_path(cmd.install_data, destination) def test_user_site(self): # test install with --user From noreply at buildbot.pypy.org Wed May 1 10:45:35 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 1 May 2013 10:45:35 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Python version 2.7.2 -> 2.7.3. Message-ID: <20130501084535.169F51C01C2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r404:32e07e8a122c Date: 2013-05-01 10:45 +0200 http://bitbucket.org/pypy/pypy.org/changeset/32e07e8a122c/ Log: Python version 2.7.2 -> 2.7.3. diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -46,7 +46,7 @@

Python compatibility

-

PyPy implements the Python language version 2.7.2. It supports all of the core +

PyPy implements the Python language version 2.7.3. It supports all of the core language, passing Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python standard library modules; details below.

diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -55,7 +55,7 @@
  • Memory usage: large, memory-hungry Python programs might end up taking less space than they do in CPython.
  • Compatibility: PyPy is highly compatible with existing python code. -It supports ctypes and can run popular python libraries like twisted +It supports ctypes and can run popular python libraries like twisted and django.
  • Sandboxing: PyPy provides the ability to run untrusted code in a fully secure way.
  • diff --git a/source/compat.txt b/source/compat.txt --- a/source/compat.txt +++ b/source/compat.txt @@ -3,7 +3,7 @@ title: Python compatibility --- -PyPy implements the Python language version 2.7.2. It supports all of the core +PyPy implements the Python language version 2.7.3. It supports all of the core language, passing Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python `standard library modules`_; details below. diff --git a/source/index.txt b/source/index.txt --- a/source/index.txt +++ b/source/index.txt @@ -40,10 +40,10 @@ .. _`(What is a JIT compiler?)`: http://en.wikipedia.org/wiki/Just-in-time_compilation .. _`run untrusted code`: features.html#sandboxing .. _`compliant`: compat.html -.. _`Python docs`: http://docs.python.org/release/2.7.2/ +.. _`Python docs`: http://docs.python.org/release/2.7.3/ .. _`twisted`: http://twistedmatrix.com/ .. _`django`: http://www.djangoproject.com/ -.. _`ctypes`: http://docs.python.org/release/2.7.2/library/ctypes.html +.. _`ctypes`: http://docs.python.org/release/2.7.3/library/ctypes.html .. _`features`: features.html .. _`less space`: http://morepypy.blogspot.com/2009/10/gc-improvements.html .. _`highly compatible`: compat.html From noreply at buildbot.pypy.org Wed May 1 11:16:22 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 1 May 2013 11:16:22 +0200 (CEST) Subject: [pypy-commit] benchmarks default: Fix for runs that only end up doing 1 iteration (e.g. hexiom2 with --fast). Message-ID: <20130501091622.5F2321C105A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r209:f7abffc04667 Date: 2013-05-01 11:15 +0200 http://bitbucket.org/pypy/benchmarks/changeset/f7abffc04667/ Log: Fix for runs that only end up doing 1 iteration (e.g. hexiom2 with --fast). diff --git a/unladen_swallow/perf.py b/unladen_swallow/perf.py --- a/unladen_swallow/perf.py +++ b/unladen_swallow/perf.py @@ -167,7 +167,10 @@ """ assert len(sample1) == len(sample2) error = PooledSampleVariance(sample1, sample2) / len(sample1) - return (avg(sample1) - avg(sample2)) / math.sqrt(error * 2) + try: + return (avg(sample1) - avg(sample2)) / math.sqrt(error * 2) + except ZeroDivisionError: + return 0.0 def IsSignificant(sample1, sample2): From noreply at buildbot.pypy.org Wed May 1 11:16:23 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 1 May 2013 11:16:23 +0200 (CEST) Subject: [pypy-commit] benchmarks default: merge heads Message-ID: <20130501091623.DB8D91C1190@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r210:18190ecf74c9 Date: 2013-05-01 11:16 +0200 http://bitbucket.org/pypy/benchmarks/changeset/18190ecf74c9/ Log: merge heads diff --git a/unladen_swallow/perf.py b/unladen_swallow/perf.py --- a/unladen_swallow/perf.py +++ b/unladen_swallow/perf.py @@ -448,7 +448,7 @@ base_python: path to the reference Python binary. changed_python: path to the experimental Python binary. options: optparse.Values instance. - *args, **kwargs: will be passed through to benchmark_function. + *args, **kwargs: will be passed through to benchmark_function. Returns: An object representing differences between the two benchmark runs. @@ -671,7 +671,12 @@ A string summarizing the difference between the runs, suitable for human consumption. """ - assert len(base_times) == len(changed_times) + if len(base_times) != len(changed_times): + print "Base:" + print base_times + print "Changed:" + print changed_times + raise Exception("length did not match") if options.no_statistics: return RawResult(base_times, changed_times) if len(base_times) == 1: @@ -746,7 +751,7 @@ Returns: (stdout, mem_usage), where stdout is the captured stdout as a string; mem_usage is a list of memory usage samples in kilobytes (if - track_memory is False, mem_usage is None). + track_memory is False, mem_usage is None). Raises: RuntimeError: if the command failed. The value of the exception will @@ -761,7 +766,9 @@ future = MemoryUsageFuture(subproc.pid) result, err = subproc.communicate() if subproc.returncode != 0: - raise RuntimeError("Benchmark died: " + err) + print result + raise RuntimeError("Benchmark died (returncode: %d): %s" % + (subproc.returncode, err)) if track_memory: mem_usage = future.GetMemoryUsage() return result, mem_usage @@ -1443,7 +1450,7 @@ BENCH_FUNCS = _FindAllBenchmarks(globals()) # Benchmark groups. The "default" group is what's run if no -b option is -# specified. +# specified. # If you update the default group, be sure to update the module docstring, too. # An "all" group which includes every benchmark perf.py knows about is generated # automatically. @@ -1571,7 +1578,7 @@ " Valid benchmarks are: " + ", ".join(bench_groups.keys() + all_benchmarks))) parser.add_option("--inherit_env", metavar="ENVVARS", type="string", action="callback", - callback=ParseEnvVars, default=[], + callback=ParseEnvVars, default=[], help=("Comma-separated list of environment variable names" " that are inherited from the parent environment" " when running benchmarking subprocesses.")) From noreply at buildbot.pypy.org Wed May 1 14:33:23 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 1 May 2013 14:33:23 +0200 (CEST) Subject: [pypy-commit] pypy default: add more paths to librarydirs Message-ID: <20130501123323.0BB981C0246@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63784:08b293dd08d2 Date: 2013-05-01 14:32 +0200 http://bitbucket.org/pypy/pypy/changeset/08b293dd08d2/ Log: add more paths to librarydirs diff --git a/rpython/translator/platform/arm.py b/rpython/translator/platform/arm.py --- a/rpython/translator/platform/arm.py +++ b/rpython/translator/platform/arm.py @@ -18,8 +18,11 @@ class ARM(Linux): name = "arm" - available_librarydirs = [SB2 + '/usr/lib/arm-linux-gnueabi/', + available_librarydirs = [SB2 + '/lib/arm-linux-gnueabi/', + SB2 + '/lib/arm-linux-gnueabihf/', + SB2 + '/usr/lib/arm-linux-gnueabi/', SB2 + '/usr/lib/arm-linux-gnueabihf/'] + available_includedirs = [SB2 + '/usr/include/arm-linux-gnueabi/', SB2 + '/usr/include/arm-linux-gnueabihf/'] copied_cache = {} From noreply at buildbot.pypy.org Wed May 1 19:33:43 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 1 May 2013 19:33:43 +0200 (CEST) Subject: [pypy-commit] pypy default: A version of zip() specialized for two arguments. It is more than Message-ID: <20130501173343.29C5E1C01C2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63785:ffe6fdf3a875 Date: 2013-05-01 19:33 +0200 http://bitbucket.org/pypy/pypy/changeset/ffe6fdf3a875/ Log: A version of zip() specialized for two arguments. It is more than four times faster (tested with lists of 10 items). diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py --- a/pypy/module/__builtin__/app_functional.py +++ b/pypy/module/__builtin__/app_functional.py @@ -203,7 +203,29 @@ Return a list of tuples, where each tuple contains the i-th element from each of the argument sequences. The returned list is truncated in length to the length of the shortest argument sequence.""" - if not sequences: + l = len(sequences) + if l == 2: + # This is functionally the same as the code below, but more + # efficient because it unrolls the loops over 'sequences'. + # Only for two arguments, which is the most common case. + seq0 = sequences[0] + seq1 = sequences[1] + iter0 = iter(seq0) + iter1 = iter(seq1) + hint = min(100000000, # max 100M + operator._length_hint(seq0, 0), + operator._length_hint(seq1, 0)) + + with _ManagedNewlistHint(hint) as result: + while True: + try: + item0 = next(iter0) + item1 = next(iter1) + except StopIteration: + return result + result.append((item0, item1)) + + if l == 0: return [] # Gather the iterators and guess the result length (the min of the diff --git a/pypy/module/__builtin__/test/test_zip.py b/pypy/module/__builtin__/test/test_zip.py --- a/pypy/module/__builtin__/test/test_zip.py +++ b/pypy/module/__builtin__/test/test_zip.py @@ -13,6 +13,12 @@ def test_one_list(self): assert zip([1, 2, 3]) == [(1,), (2,), (3,)] + def test_two_lists(self): + # uses a different code path + assert zip([1, 2, 3], [3, 4, 5]) == [(1, 3), (2, 4), (3, 5)] + assert zip([1, 2, 3], [3, 4]) == [(1, 3), (2, 4)] + assert zip([1, 2], [3, 4, 5]) == [(1, 3), (2, 4)] + def test_three_lists_same_size(self): assert zip([1, 2, 3], [3, 4, 5], [6, 7, 8]) == ( [(1, 3, 6), (2, 4, 7), (3, 5, 8)]) From noreply at buildbot.pypy.org Wed May 1 20:54:29 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 20:54:29 +0200 (CEST) Subject: [pypy-commit] pypy default: refine usage, it now resembles CPython's Message-ID: <20130501185429.D56551C0334@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63786:94039754471f Date: 2013-05-01 11:53 -0700 http://bitbucket.org/pypy/pypy/changeset/94039754471f/ Log: refine usage, it now resembles CPython's diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -1,20 +1,39 @@ #! /usr/bin/env python # App-level version of py.py. # See test/test_app_main. + +# Missing vs CPython: -B, -d, -OO, -t, -v, -x, -3 +"""\ +Options and arguments (and corresponding environment variables): +-c cmd : program passed in as string (terminates option list) +-E : ignore PYTHON* environment variables (such as PYTHONPATH) +-h : print this help message and exit (also --help) +-i : inspect interactively after running script; forces a prompt even + if stdin does not appear to be a terminal; also PYTHONINSPECT=x +-m mod : run library module as a script (terminates option list) +-O : dummy optimization flag for compatibility with CPython +-R : ignored (see http://bugs.python.org/issue14621) +-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew +-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE +-S : don't imply 'import site' on initialization +-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x +-V : print the Python version number and exit (also --version) +-W arg : warning control; arg is action:message:category:module:lineno + also PYTHONWARNINGS=arg +file : program read from script file +- : program read from stdin (default; interactive mode if a tty) +arg ...: arguments passed to program in sys.argv[1:] +PyPy options and arguments: +--info : print translation information about this PyPy executable """ -options: - -i inspect interactively after running script - -O dummy optimization flag for compatibility with C Python - -c cmd program passed in as CMD (terminates option list) - -S do not 'import site' on initialization - -u unbuffered binary stdout and stderr - -h, --help show this help message and exit - -m mod library module to be run as a script (terminates option list) - -W arg warning control (arg is action:message:category:module:lineno) - -E ignore environment variables (such as PYTHONPATH) - -R ignored (see http://bugs.python.org/issue14621) - --version print the PyPy version - --info print translation information about this PyPy executable +USAGE1 = __doc__ +# Missing vs CPython: PYTHONHOME, PYTHONCASEOK +USAGE2 = """ +Other environment variables: +PYTHONSTARTUP: file executed on interactive startup (no default) +PYTHONPATH : %r-separated list of directories prefixed to the + default module search path. The result is sys.path. +PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr. """ import sys @@ -136,12 +155,13 @@ raise SystemExit def print_help(*args): - print 'usage: %s [options] [-c cmd|-m mod|file.py|-] [arg...]' % ( + import os + print 'usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...' % ( sys.executable,) - print __doc__.rstrip() + print USAGE1, if 'pypyjit' in sys.builtin_module_names: - print " --jit OPTIONS advanced JIT options: try 'off' or 'help'" - print + print "--jit options: advanced JIT options: try 'off' or 'help'" + print (USAGE2 % (os.pathsep,)), raise SystemExit def _print_jit_help(): diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test2/test_app_main.py --- a/pypy/interpreter/test2/test_app_main.py +++ b/pypy/interpreter/test2/test_app_main.py @@ -264,7 +264,8 @@ # test that -h prints the usage, including the name of the executable # which should be /full/path/to/app_main.py in this case child = self.spawn(['-h']) - child.expect(r'usage: .*app_main.py \[options\]') + child.expect(r'usage: .*app_main.py \[option\]') + child.expect('PyPy options and arguments:') def test_run_script(self): child = self.spawn([demo_script]) From noreply at buildbot.pypy.org Wed May 1 21:52:50 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 21:52:50 +0200 (CEST) Subject: [pypy-commit] pypy default: we support -B Message-ID: <20130501195250.0B2771C0334@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63787:1208c73d38ba Date: 2013-05-01 12:52 -0700 http://bitbucket.org/pypy/pypy/changeset/1208c73d38ba/ Log: we support -B diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -2,9 +2,10 @@ # App-level version of py.py. # See test/test_app_main. -# Missing vs CPython: -B, -d, -OO, -t, -v, -x, -3 +# Missing vs CPython: -d, -OO, -t, -v, -x, -3 """\ Options and arguments (and corresponding environment variables): +-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x -c cmd : program passed in as string (terminates option list) -E : ignore PYTHON* environment variables (such as PYTHONPATH) -h : print this help message and exit (also --help) From noreply at buildbot.pypy.org Wed May 1 22:21:57 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 22:21:57 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130501202157.EC42F1C0246@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63788:8c0da4a921de Date: 2013-05-01 13:05 -0700 http://bitbucket.org/pypy/pypy/changeset/8c0da4a921de/ Log: merge default diff --git a/lib-python/2.7/distutils/command/install.py b/lib-python/2.7/distutils/command/install.py --- a/lib-python/2.7/distutils/command/install.py +++ b/lib-python/2.7/distutils/command/install.py @@ -474,8 +474,8 @@ def select_scheme (self, name): # it's the caller's problem if they supply a bad name! - if hasattr(sys, 'pypy_version_info') and not ( - name.endswith('_user') or name.endswith('_home')): + if (hasattr(sys, 'pypy_version_info') and + not name.endswith(('_user', '_home'))): name = 'pypy' scheme = INSTALL_SCHEMES[name] for key in SCHEME_KEYS: diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -1,25 +1,42 @@ #! /usr/bin/env python # App-level version of py.py. # See test/test_app_main. + +# Missing vs CPython: -B, -d, -OO, -t, -v, -x, -3 +"""\ +Options and arguments (and corresponding environment variables): +-c cmd : program passed in as string (terminates option list) +-E : ignore PYTHON* environment variables (such as PYTHONPATH) +-h : print this help message and exit (also --help) +-i : inspect interactively after running script; forces a prompt even + if stdin does not appear to be a terminal; also PYTHONINSPECT=x +-m mod : run library module as a script (terminates option list) +-O : dummy optimization flag for compatibility with CPython +-R : ignored (see http://bugs.python.org/issue14621) +-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew +-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE +-S : don't imply 'import site' on initialization +-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x +-V : print the Python version number and exit (also --version) +-W arg : warning control; arg is action:message:category:module:lineno + also PYTHONWARNINGS=arg +file : program read from script file +- : program read from stdin (default; interactive mode if a tty) +arg ...: arguments passed to program in sys.argv[1:] +PyPy options and arguments: +--info : print translation information about this PyPy executable """ -options: - -i inspect interactively after running script - -O dummy optimization flag for compatibility with C Python - -c cmd program passed in as CMD (terminates option list) - -S do not 'import site' on initialization - -u unbuffered binary stdout and stderr - -h, --help show this help message and exit - -m mod library module to be run as a script (terminates option list) - -W arg warning control (arg is action:message:category:module:lineno) - -X opt set implementation-specific option - -E ignore environment variables (such as PYTHONPATH) - -R ignored (see http://bugs.python.org/issue14621) - --version print the PyPy version - --info print translation information about this PyPy executable +from __future__ import print_function, unicode_literals +USAGE1 = __doc__ +# Missing vs CPython: PYTHONHOME, PYTHONCASEOK +USAGE2 = """ +Other environment variables: +PYTHONSTARTUP: file executed on interactive startup (no default) +PYTHONPATH : %r-separated list of directories prefixed to the + default module search path. The result is sys.path. +PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr. """ -from __future__ import print_function, unicode_literals - try: from __pypy__ import hidden_applevel except ImportError: @@ -133,13 +150,14 @@ raise SystemExit def print_help(*args): + import os initstdio() - print('usage: %s [options] [-c cmd|-m mod|file.py|-] [arg...]' % ( + print('usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...' % ( sys.executable,)) - print(__doc__.rstrip()) + print(USAGE1, end='') if 'pypyjit' in sys.builtin_module_names: - print(" --jit OPTIONS advanced JIT options: try 'off' or 'help'") - print() + print("--jit options: advanced JIT options: try 'off' or 'help'") + print(USAGE2 % (os.pathsep,), end='') raise SystemExit def _print_jit_help(): diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test2/test_app_main.py --- a/pypy/interpreter/test2/test_app_main.py +++ b/pypy/interpreter/test2/test_app_main.py @@ -273,7 +273,8 @@ # test that -h prints the usage, including the name of the executable # which should be /full/path/to/app_main.py in this case child = self.spawn(['-h']) - child.expect(r'usage: .*app_main.py \[options\]') + child.expect(r'usage: .*app_main.py \[option\]') + child.expect('PyPy options and arguments:') def test_run_script(self, demo_script): child = self.spawn([demo_script]) diff --git a/pypy/module/__builtin__/test/test_zip.py b/pypy/module/__builtin__/test/test_zip.py --- a/pypy/module/__builtin__/test/test_zip.py +++ b/pypy/module/__builtin__/test/test_zip.py @@ -13,6 +13,12 @@ def test_one_list(self): assert list(zip([1, 2, 3])) == [(1,), (2,), (3,)] + def test_two_lists(self): + # uses a different code path + assert zip([1, 2, 3], [3, 4, 5]) == [(1, 3), (2, 4), (3, 5)] + assert zip([1, 2, 3], [3, 4]) == [(1, 3), (2, 4)] + assert zip([1, 2], [3, 4, 5]) == [(1, 3), (2, 4)] + def test_three_lists_same_size(self): assert list(zip([1, 2, 3], [3, 4, 5], [6, 7, 8])) == ( [(1, 3, 6), (2, 4, 7), (3, 5, 8)]) diff --git a/rpython/translator/platform/arm.py b/rpython/translator/platform/arm.py --- a/rpython/translator/platform/arm.py +++ b/rpython/translator/platform/arm.py @@ -18,8 +18,11 @@ class ARM(Linux): name = "arm" - available_librarydirs = [SB2 + '/usr/lib/arm-linux-gnueabi/', + available_librarydirs = [SB2 + '/lib/arm-linux-gnueabi/', + SB2 + '/lib/arm-linux-gnueabihf/', + SB2 + '/usr/lib/arm-linux-gnueabi/', SB2 + '/usr/lib/arm-linux-gnueabihf/'] + available_includedirs = [SB2 + '/usr/include/arm-linux-gnueabi/', SB2 + '/usr/include/arm-linux-gnueabihf/'] copied_cache = {} From noreply at buildbot.pypy.org Wed May 1 22:21:59 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 22:21:59 +0200 (CEST) Subject: [pypy-commit] pypy py3k: update to py3's usage Message-ID: <20130501202159.61C0A1C0246@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63789:9c0f75fa4f77 Date: 2013-05-01 13:15 -0700 http://bitbucket.org/pypy/pypy/changeset/9c0f75fa4f77/ Log: update to py3's usage diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -2,9 +2,10 @@ # App-level version of py.py. # See test/test_app_main. -# Missing vs CPython: -B, -d, -OO, -t, -v, -x, -3 +# Missing vs CPython: -b, -d, -OO, -v, -x, -3 """\ Options and arguments (and corresponding environment variables): +-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x -c cmd : program passed in as string (terminates option list) -E : ignore PYTHON* environment variables (such as PYTHONPATH) -h : print this help message and exit (also --help) @@ -12,14 +13,15 @@ if stdin does not appear to be a terminal; also PYTHONINSPECT=x -m mod : run library module as a script (terminates option list) -O : dummy optimization flag for compatibility with CPython +-q : don't print version and copyright messages on interactive startup -R : ignored (see http://bugs.python.org/issue14621) --Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew -s : don't add user site directory to sys.path; also PYTHONNOUSERSITE -S : don't imply 'import site' on initialization -u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x -V : print the Python version number and exit (also --version) -W arg : warning control; arg is action:message:category:module:lineno also PYTHONWARNINGS=arg +-X opt : set implementation-specific option file : program read from script file - : program read from stdin (default; interactive mode if a tty) arg ...: arguments passed to program in sys.argv[1:] From noreply at buildbot.pypy.org Wed May 1 22:22:00 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 22:22:00 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill the duplicate Message-ID: <20130501202200.AC90E1C0246@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63790:7ca550ea2870 Date: 2013-05-01 13:17 -0700 http://bitbucket.org/pypy/pypy/changeset/7ca550ea2870/ Log: kill the duplicate diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -358,7 +358,6 @@ 's': (simple_option, 'no_user_site'), 'S': (simple_option, 'no_site'), 'u': (simple_option, 'unbuffered'), - 'b': (simple_option, 'bytes_warning'), 'v': (simple_option, 'verbose'), 'q': (simple_option, 'quiet'), # more complex options From noreply at buildbot.pypy.org Wed May 1 22:22:01 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 1 May 2013 22:22:01 +0200 (CEST) Subject: [pypy-commit] pypy py3k: add a maybe helpful error message Message-ID: <20130501202201.EC9A31C0246@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63791:fa91fc59b6da Date: 2013-05-01 13:20 -0700 http://bitbucket.org/pypy/pypy/changeset/fa91fc59b6da/ Log: add a maybe helpful error message diff --git a/pypy/objspace/std/test/test_unicodeobject.py b/pypy/objspace/std/test/test_unicodeobject.py --- a/pypy/objspace/std/test/test_unicodeobject.py +++ b/pypy/objspace/std/test/test_unicodeobject.py @@ -355,6 +355,14 @@ assert 'ab'.startswith('b', 1) is True assert 'abc'.startswith('bc', 1, 2) is False assert 'abc'.startswith('c', -1, 4) is True + try: + 'hello'.startswith(['o']) + except TypeError as e: + msg = str(e) + assert 'str' in msg + assert 'tuple' in msg + else: + assert False, 'Expected TypeError' def test_startswith_tuples(self): assert 'hello'.startswith(('he', 'ha')) @@ -393,6 +401,14 @@ assert 'abc'.endswith('bc', 1) is True assert 'abc'.endswith('bc', 2) is False assert 'abc'.endswith('b', -3, -1) is True + try: + 'hello'.endswith(['o']) + except TypeError as e: + msg = str(e) + assert 'str' in msg + assert 'tuple' in msg + else: + assert False, 'Expected TypeError' def test_endswith_tuple(self): assert not 'hello'.endswith(('he', 'ha')) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -454,11 +454,22 @@ space, len(self), w_start, w_end, upper_bound) return (self, start, end) +def unicode_endswith__Unicode_ANY_ANY_ANY(space, w_self, w_substr, w_start, w_end): + typename = space.type(w_substr).getname(space) + msg = "endswith first arg must be str or a tuple of str, not %s" % typename + raise OperationError(space.w_TypeError, space.wrap(msg)) + def unicode_endswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): self, start, end = _convert_idx_params(space, w_self, w_start, w_end, True) return space.newbool(stringendswith(self, w_substr._value, start, end)) +def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_self, w_substr, w_start, w_end): + typename = space.type(w_substr).getname(space) + msg = ("startswith first arg must be str or a tuple of str, not %s" % + typename) + raise OperationError(space.w_TypeError, space.wrap(msg)) + def unicode_startswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): self, start, end = _convert_idx_params(space, w_self, w_start, w_end, True) # XXX this stuff can be waaay better for ootypebased backends if From noreply at buildbot.pypy.org Wed May 1 23:31:52 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 1 May 2013 23:31:52 +0200 (CEST) Subject: [pypy-commit] pypy default: implement and use ldm/stm to store several registers to the jitframe Message-ID: <20130501213152.E55F71C01C2@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63792:e2231ee466f7 Date: 2013-05-01 21:52 +0200 http://bitbucket.org/pypy/pypy/changeset/e2231ee466f7/ Log: implement and use ldm/stm to store several registers to the jitframe diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -360,11 +360,9 @@ regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - # XXX use STMDB ops here - for i, gpr in enumerate(regs): - if gpr in ignored_regs: - continue - self.store_reg(mc, gpr, r.fp, base_ofs + i * WORD) + mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) + mc.STM(r.ip.value, [reg.value for reg in regs + if reg not in ignored_regs]) if withfloats: if callee_only: regs = VFPRegisterManager.save_around_call_regs @@ -385,12 +383,9 @@ regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - # XXX use LDMDB ops here - for i, gpr in enumerate(regs): - if gpr in ignored_regs: - continue - ofs = i * WORD + base_ofs - self.load_reg(mc, gpr, r.fp, ofs) + mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) + mc.LDM(r.ip.value, [reg.value for reg in regs + if reg not in ignored_regs]) if withfloats: # Pop all XMM regs if callee_only: diff --git a/rpython/jit/backend/arm/codebuilder.py b/rpython/jit/backend/arm/codebuilder.py --- a/rpython/jit/backend/arm/codebuilder.py +++ b/rpython/jit/backend/arm/codebuilder.py @@ -49,6 +49,26 @@ instr = self._encode_reg_list(cond << 28 | 0x92D << 16, regs) self.write32(instr) + def STM(self, base, regs, write_back=False, cond=cond.AL): + assert len(regs) > 0 + instr = (cond << 28 + | 0x11 << 23 + | (1 if write_back else 0) << 21 + | (base & 0xF) << 16) + instr = self._encode_reg_list(instr, regs) + self.write32(instr) + + def LDM(self, base, regs, write_back=False, cond=cond.AL): + assert len(regs) > 0 + instr = (cond << 28 + | 0x11 << 23 + | (1 if write_back else 0) << 21 + | 1 << 20 + | (base & 0xF) << 16) + instr = self._encode_reg_list(instr, regs) + self.write32(instr) + + def VPUSH(self, regs, cond=cond.AL): nregs = len(regs) assert nregs > 0 and nregs <= 16 diff --git a/rpython/jit/backend/arm/test/test_instr_codebuilder.py b/rpython/jit/backend/arm/test/test_instr_codebuilder.py --- a/rpython/jit/backend/arm/test/test_instr_codebuilder.py +++ b/rpython/jit/backend/arm/test/test_instr_codebuilder.py @@ -139,6 +139,14 @@ def test_push_raises_sp(self): assert py.test.raises(AssertionError, 'self.cb.PUSH([r.sp.value])') + def test_stm(self): + self.cb.STM(r.fp.value, [reg.value for reg in r.caller_resp], cond=conditions.AL) + self.assert_equal('STM fp, {r0, r1, r2, r3}') + + def test_ldm(self): + self.cb.LDM(r.fp.value, [reg.value for reg in r.caller_resp], cond=conditions.AL) + self.assert_equal('LDM fp, {r0, r1, r2, r3}') + def test_pop(self): self.cb.POP([reg.value for reg in r.caller_resp], cond=conditions.AL) self.assert_equal('POP {r0, r1, r2, r3}') From noreply at buildbot.pypy.org Wed May 1 23:31:54 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 1 May 2013 23:31:54 +0200 (CEST) Subject: [pypy-commit] pypy default: implement and use VSTM and VLDM for loading and storing several floating point regs Message-ID: <20130501213154.2AE521C01C2@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63793:9e6a292cd425 Date: 2013-05-01 23:28 +0200 http://bitbucket.org/pypy/pypy/changeset/9e6a292cd425/ Log: implement and use VSTM and VLDM for loading and storing several floating point regs diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -368,12 +368,10 @@ regs = VFPRegisterManager.save_around_call_regs else: regs = VFPRegisterManager.all_regs - for i, vfpr in enumerate(regs): - if vfpr in ignored_regs: - continue - ofs = len(CoreRegisterManager.all_regs) * WORD - ofs += i * DOUBLE_WORD + base_ofs - self.store_reg(mc, vfpr, r.fp, ofs) + ofs = len(CoreRegisterManager.all_regs) * WORD + mc.ADD_ri(r.ip.value, r.ip.value, ofs) + mc.VSTM(r.ip.value, [vfpr.value for vfpr in regs + if vfpr not in ignored_regs]) def _pop_all_regs_from_jitframe(self, mc, ignored_regs, withfloats, callee_only=False): @@ -392,12 +390,10 @@ regs = VFPRegisterManager.save_around_call_regs else: regs = VFPRegisterManager.all_regs - for i, vfpr in enumerate(regs): - if vfpr in ignored_regs: - continue - ofs = len(CoreRegisterManager.all_regs) * WORD - ofs += i * DOUBLE_WORD + base_ofs - self.load_reg(mc, vfpr, r.fp, ofs) + ofs = len(CoreRegisterManager.all_regs) * WORD + mc.ADD_ri(r.ip.value, r.ip.value, ofs) + mc.VLDM(r.ip.value, [vfpr.value for vfpr in regs + if vfpr not in ignored_regs]) def _build_failure_recovery(self, exc, withfloats=False): mc = InstrBuilder(self.cpu.cpuinfo.arch_version) diff --git a/rpython/jit/backend/arm/codebuilder.py b/rpython/jit/backend/arm/codebuilder.py --- a/rpython/jit/backend/arm/codebuilder.py +++ b/rpython/jit/backend/arm/codebuilder.py @@ -68,6 +68,50 @@ instr = self._encode_reg_list(instr, regs) self.write32(instr) + def VSTM(self, base, regs, write_back=False, cond=cond.AL): + # encoding T1 + P = 0 + U = 1 + nregs = len(regs) + assert nregs > 0 and nregs <= 16 + freg = regs[0] + D = (freg & 0x10) >> 4 + Dd = (freg & 0xF) + nregs *= 2 + instr = (cond << 28 + | 3 << 26 + | P << 24 + | U << 23 + | D << 22 + | (1 if write_back else 0) << 21 + | (base & 0xF) << 16 + | Dd << 12 + | 0xB << 8 + | nregs) + self.write32(instr) + + def VLDM(self, base, regs, write_back=False, cond=cond.AL): + # encoding T1 + P = 0 + U = 1 + nregs = len(regs) + assert nregs > 0 and nregs <= 16 + freg = regs[0] + D = (freg & 0x10) >> 4 + Dd = (freg & 0xF) + nregs *= 2 + instr = (cond << 28 + | 3 << 26 + | P << 24 + | U << 23 + | D << 22 + | (1 if write_back else 0) << 21 + | 1 << 20 + | (base & 0xF) << 16 + | Dd << 12 + | 0xB << 8 + | nregs) + self.write32(instr) def VPUSH(self, regs, cond=cond.AL): nregs = len(regs) diff --git a/rpython/jit/backend/arm/test/test_instr_codebuilder.py b/rpython/jit/backend/arm/test/test_instr_codebuilder.py --- a/rpython/jit/backend/arm/test/test_instr_codebuilder.py +++ b/rpython/jit/backend/arm/test/test_instr_codebuilder.py @@ -147,6 +147,14 @@ self.cb.LDM(r.fp.value, [reg.value for reg in r.caller_resp], cond=conditions.AL) self.assert_equal('LDM fp, {r0, r1, r2, r3}') + def test_vstm(self): + self.cb.VSTM(r.fp.value, [reg.value for reg in r.caller_vfp_resp], cond=conditions.AL) + self.assert_equal('VSTM fp, {d0, d1, d2, d3, d4, d5, d6, d7}') + + def test_vldm(self): + self.cb.VLDM(r.fp.value, [reg.value for reg in r.caller_vfp_resp], cond=conditions.AL) + self.assert_equal('VLDM fp, {d0, d1, d2, d3, d4, d5, d6, d7}') + def test_pop(self): self.cb.POP([reg.value for reg in r.caller_resp], cond=conditions.AL) self.assert_equal('POP {r0, r1, r2, r3}') From noreply at buildbot.pypy.org Wed May 1 23:31:55 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 1 May 2013 23:31:55 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130501213155.8A51B1C01C2@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63794:6fc3fb8cd5cc Date: 2013-05-01 23:31 +0200 http://bitbucket.org/pypy/pypy/changeset/6fc3fb8cd5cc/ Log: merge heads diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -1,20 +1,40 @@ #! /usr/bin/env python # App-level version of py.py. # See test/test_app_main. + +# Missing vs CPython: -d, -OO, -t, -v, -x, -3 +"""\ +Options and arguments (and corresponding environment variables): +-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x +-c cmd : program passed in as string (terminates option list) +-E : ignore PYTHON* environment variables (such as PYTHONPATH) +-h : print this help message and exit (also --help) +-i : inspect interactively after running script; forces a prompt even + if stdin does not appear to be a terminal; also PYTHONINSPECT=x +-m mod : run library module as a script (terminates option list) +-O : dummy optimization flag for compatibility with CPython +-R : ignored (see http://bugs.python.org/issue14621) +-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew +-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE +-S : don't imply 'import site' on initialization +-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x +-V : print the Python version number and exit (also --version) +-W arg : warning control; arg is action:message:category:module:lineno + also PYTHONWARNINGS=arg +file : program read from script file +- : program read from stdin (default; interactive mode if a tty) +arg ...: arguments passed to program in sys.argv[1:] +PyPy options and arguments: +--info : print translation information about this PyPy executable """ -options: - -i inspect interactively after running script - -O dummy optimization flag for compatibility with C Python - -c cmd program passed in as CMD (terminates option list) - -S do not 'import site' on initialization - -u unbuffered binary stdout and stderr - -h, --help show this help message and exit - -m mod library module to be run as a script (terminates option list) - -W arg warning control (arg is action:message:category:module:lineno) - -E ignore environment variables (such as PYTHONPATH) - -R ignored (see http://bugs.python.org/issue14621) - --version print the PyPy version - --info print translation information about this PyPy executable +USAGE1 = __doc__ +# Missing vs CPython: PYTHONHOME, PYTHONCASEOK +USAGE2 = """ +Other environment variables: +PYTHONSTARTUP: file executed on interactive startup (no default) +PYTHONPATH : %r-separated list of directories prefixed to the + default module search path. The result is sys.path. +PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr. """ import sys @@ -136,12 +156,13 @@ raise SystemExit def print_help(*args): - print 'usage: %s [options] [-c cmd|-m mod|file.py|-] [arg...]' % ( + import os + print 'usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...' % ( sys.executable,) - print __doc__.rstrip() + print USAGE1, if 'pypyjit' in sys.builtin_module_names: - print " --jit OPTIONS advanced JIT options: try 'off' or 'help'" - print + print "--jit options: advanced JIT options: try 'off' or 'help'" + print (USAGE2 % (os.pathsep,)), raise SystemExit def _print_jit_help(): diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test2/test_app_main.py --- a/pypy/interpreter/test2/test_app_main.py +++ b/pypy/interpreter/test2/test_app_main.py @@ -264,7 +264,8 @@ # test that -h prints the usage, including the name of the executable # which should be /full/path/to/app_main.py in this case child = self.spawn(['-h']) - child.expect(r'usage: .*app_main.py \[options\]') + child.expect(r'usage: .*app_main.py \[option\]') + child.expect('PyPy options and arguments:') def test_run_script(self): child = self.spawn([demo_script]) From noreply at buildbot.pypy.org Thu May 2 01:35:08 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 2 May 2013 01:35:08 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix on 32bit Message-ID: <20130501233508.2ACDB1C0334@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63795:6619b75d5bd7 Date: 2013-05-01 16:20 -0700 http://bitbucket.org/pypy/pypy/changeset/6619b75d5bd7/ Log: fix on 32bit 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 @@ -66,7 +66,7 @@ for overflow. """ num = space.bigint_w(w_long) - return num.ulonglongmask() + return num.uintmask() @cpython_api([PyObject], lltype.Signed, error=-1) def PyLong_AsLong(space, w_long): From noreply at buildbot.pypy.org Thu May 2 01:35:09 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 2 May 2013 01:35:09 +0200 (CEST) Subject: [pypy-commit] pypy py3k: skip this for now as it relies on ctypes py_object w/ strs Message-ID: <20130501233509.783571C0334@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63796:c98e1e170a2a Date: 2013-05-01 16:30 -0700 http://bitbucket.org/pypy/pypy/changeset/c98e1e170a2a/ Log: skip this for now as it relies on ctypes py_object w/ strs diff --git a/lib-python/3/test/test_unicode.py b/lib-python/3/test/test_unicode.py --- a/lib-python/3/test/test_unicode.py +++ b/lib-python/3/test/test_unicode.py @@ -1609,14 +1609,16 @@ self.assertEqual("{}".format(s), '__str__ overridden') # Test PyUnicode_FromFormat() + @unittest.skipIf(support.check_impl_detail(pypy=True), + "https://bugs.pypy.org/issue1233") def test_from_format(self): support.import_module('ctypes') from ctypes import pythonapi, py_object, c_int - if sys.maxunicode == 65535: - name = "PyUnicodeUCS2_FromFormat" - else: - name = "PyUnicodeUCS4_FromFormat" - _PyUnicode_FromFormat = getattr(pythonapi, name) + #if sys.maxunicode == 65535: + # name = "PyUnicodeUCS2_FromFormat" + #else: + # name = "PyUnicodeUCS4_FromFormat" + _PyUnicode_FromFormat = getattr(pythonapi, 'PyUnicode_FromFormat') _PyUnicode_FromFormat.restype = py_object def PyUnicode_FromFormat(format, *args): From noreply at buildbot.pypy.org Thu May 2 12:10:42 2013 From: noreply at buildbot.pypy.org (bivab) Date: Thu, 2 May 2013 12:10:42 +0200 (CEST) Subject: [pypy-commit] pypy default: a test running stm/ldm Message-ID: <20130502101042.84A471C02DA@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63797:2409ad4fbde7 Date: 2013-05-02 12:06 +0200 http://bitbucket.org/pypy/pypy/changeset/2409ad4fbde7/ Log: a test running stm/ldm diff --git a/rpython/jit/backend/arm/test/test_assembler.py b/rpython/jit/backend/arm/test/test_assembler.py --- a/rpython/jit/backend/arm/test/test_assembler.py +++ b/rpython/jit/backend/arm/test/test_assembler.py @@ -11,6 +11,10 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.jit.metainterp.history import JitCellToken from rpython.jit.backend.model import CompiledLoopToken +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi +from rpython.rtyper.annlowlevel import llhelper +from rpython.rlib.objectmodel import specialize +from rpython.rlib.debug import ll_assert CPU = getcpuclass() @@ -247,7 +251,33 @@ self.a.mc.ADD_ri(r.sp.value, r.sp.value, 8) self.a.gen_func_epilog() assert run_asm(self.a) == x + + def test_stm(self): + container = lltype.malloc(lltype.Array(lltype.Signed, hints={'nolength': True}), 10, flavor='raw') + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, container)) + for x in range(10): + self.a.mc.gen_load_int(x, x) + self.a.mc.STM(r.ip.value, [x for x in range(10)]) + self.a.gen_func_epilog() + run_asm(self.a) + for x in range(10): + assert container[x] == x + lltype.free(container, flavor='raw') + def test_ldm(self): + container = lltype.malloc(lltype.Array(lltype.Signed, hints={'nolength': True}), 10, flavor='raw') + for x in range(10): + container[x] = x + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, container)) + self.a.mc.LDM(r.ip.value, [x for x in range(10)]) + for x in range(1, 10): + self.a.mc.ADD_ri(0, 0, x) + self.a.gen_func_epilog() + res = run_asm(self.a) + assert res == sum(range(10)) + lltype.free(container, flavor='raw') def callme(inp): i = inp + 10 From noreply at buildbot.pypy.org Thu May 2 12:10:43 2013 From: noreply at buildbot.pypy.org (bivab) Date: Thu, 2 May 2013 12:10:43 +0200 (CEST) Subject: [pypy-commit] pypy default: revert change using stm/ldm for now Message-ID: <20130502101043.C6C2C1C0328@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63798:a46161c73bae Date: 2013-05-02 12:07 +0200 http://bitbucket.org/pypy/pypy/changeset/a46161c73bae/ Log: revert change using stm/ldm for now diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -360,18 +360,22 @@ regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) - mc.STM(r.ip.value, [reg.value for reg in regs - if reg not in ignored_regs]) + # XXX use STMDB ops here + for i, gpr in enumerate(regs): + if gpr in ignored_regs: + continue + self.store_reg(mc, gpr, r.fp, base_ofs + i * WORD) if withfloats: if callee_only: regs = VFPRegisterManager.save_around_call_regs else: regs = VFPRegisterManager.all_regs - ofs = len(CoreRegisterManager.all_regs) * WORD - mc.ADD_ri(r.ip.value, r.ip.value, ofs) - mc.VSTM(r.ip.value, [vfpr.value for vfpr in regs - if vfpr not in ignored_regs]) + for i, vfpr in enumerate(regs): + if vfpr in ignored_regs: + continue + ofs = len(CoreRegisterManager.all_regs) * WORD + ofs += i * DOUBLE_WORD + base_ofs + self.store_reg(mc, vfpr, r.fp, ofs) def _pop_all_regs_from_jitframe(self, mc, ignored_regs, withfloats, callee_only=False): @@ -381,19 +385,24 @@ regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) - mc.LDM(r.ip.value, [reg.value for reg in regs - if reg not in ignored_regs]) + # XXX use LDMDB ops here + for i, gpr in enumerate(regs): + if gpr in ignored_regs: + continue + ofs = i * WORD + base_ofs + self.load_reg(mc, gpr, r.fp, ofs) if withfloats: # Pop all XMM regs if callee_only: regs = VFPRegisterManager.save_around_call_regs else: regs = VFPRegisterManager.all_regs - ofs = len(CoreRegisterManager.all_regs) * WORD - mc.ADD_ri(r.ip.value, r.ip.value, ofs) - mc.VLDM(r.ip.value, [vfpr.value for vfpr in regs - if vfpr not in ignored_regs]) + for i, vfpr in enumerate(regs): + if vfpr in ignored_regs: + continue + ofs = len(CoreRegisterManager.all_regs) * WORD + ofs += i * DOUBLE_WORD + base_ofs + self.load_reg(mc, vfpr, r.fp, ofs) def _build_failure_recovery(self, exc, withfloats=False): mc = InstrBuilder(self.cpu.cpuinfo.arch_version) From noreply at buildbot.pypy.org Thu May 2 12:37:10 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 2 May 2013 12:37:10 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: add a blog draft Message-ID: <20130502103710.05C621C304F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r4966:c58b878fb310 Date: 2013-05-02 12:36 +0200 http://bitbucket.org/pypy/extradoc/changeset/c58b878fb310/ Log: add a blog draft diff --git a/blog/draft/pypy-alpha-arm.rst b/blog/draft/pypy-alpha-arm.rst new file mode 100644 --- /dev/null +++ b/blog/draft/pypy-alpha-arm.rst @@ -0,0 +1,128 @@ +====================== +PyPy 2.0 alpha for ARM +====================== + +Hello. + +We're pleased to announce an alpha release of PyPy 2.0 for ARM. This is mostly +a technology preview, as we know the JIT is not yet stable enough for the +full release. However please try your stuff on ARM and report back. + +This is the first release that supports a range of ARM devices - anything +with ARMv6 (that supports VFP, like raspberry pi) or ARMv7 (soft- or hard-float) +should work. + +This release comes with a list of limitations, consider it alpha quality, +not suitable for production: + +* stackless support does not work + +* assembler produced is not always correct, but we successfully managed to + run our extensive benchmark suite, so most stuff should work + +You can download the PyPy 2.0 alpha ARM release here: + + http://pypy.org/download.html + +Part of the work was sponsored by the `Raspberry Pi foundation`_. + +.. _`Raspberry Pi foundation`: http://www.raspberrypi.org/ + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7.3. It's fast due to its integrated tracing JIT compiler. + +This release supports ARM machines running Linux 32bit. Both ``armel`` +and ``armhf`` builds are provided. + +Benchmarks +========== + +Everybody loves benchmarks. Here is a table of our benchmark suite (we don't +provide it yet on http://speed.pypy.org, unfortunately). + +This is a comparison of Cortex A9 processor with 4M cache and Xeon XXX fill in + ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| Benchmark | PyPy vs CPython (arm) | PyPy vs CPython (x86) | x86 vs arm (pypy) | x86 vs arm (cpython) | relative speedup | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| ai | 3.61 | 3.16 | 7.70 | 8.82 | 0.87 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| bm_mako | 3.41 | 2.11 | 8.56 | 13.82 | 0.62 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| chaos | 21.82 | 17.80 | 6.93 | 8.50 | 0.82 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| crypto_pyaes | 22.53 | 19.48 | 6.53 | 7.56 | 0.86 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| django | 13.43 | 11.16 | 7.90 | 9.51 | 0.83 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| eparse | 1.43 | 1.17 | 6.61 | 8.12 | 0.81 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| fannkuch | 6.22 | 5.36 | 6.18 | 7.16 | 0.86 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| float | 5.22 | 6.00 | 9.68 | 8.43 | 1.15 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| go | 4.72 | 3.34 | 5.91 | 8.37 | 0.71 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| hexiom2 | 8.70 | 7.00 | 7.69 | 9.56 | 0.80 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| html5lib | 2.35 | 2.13 | 6.59 | 7.26 | 0.91 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| json_bench | 1.12 | 0.93 | 7.19 | 8.68 | 0.83 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| meteor-contest | 2.13 | 1.68 | 5.95 | 7.54 | 0.79 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| nbody_modified | 8.19 | 7.78 | 6.08 | 6.40 | 0.95 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| pidigits | 1.27 | 0.95 | 14.67 | 19.66 | 0.75 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| pyflate-fast | 3.30 | 3.57 | 10.64 | 9.84 | 1.08 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| raytrace-simple | 46.41 | 29.00 | 5.14 | 8.23 | 0.62 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| richards | 31.48 | 28.51 | 6.95 | 7.68 | 0.91 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| slowspitfire | 1.28 | 1.14 | 5.91 | 6.61 | 0.89 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| spambayes | 1.93 | 1.27 | 4.15 | 6.30 | 0.66 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| sphinx | 1.01 | 1.05 | 7.76 | 7.45 | 1.04 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| spitfire | 1.55 | 1.58 | 5.62 | 5.49 | 1.02 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| spitfire_cstringio | 9.61 | 5.74 | 5.43 | 9.09 | 0.60 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| sympy_expand | 1.42 | 0.97 | 3.86 | 5.66 | 0.68 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| sympy_integrate | 1.60 | 0.95 | 4.24 | 7.12 | 0.60 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| sympy_str | 0.72 | 0.48 | 3.68 | 5.56 | 0.66 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| sympy_sum | 1.99 | 1.19 | 3.83 | 6.38 | 0.60 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| telco | 14.28 | 9.36 | 3.94 | 6.02 | 0.66 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| twisted_iteration | 11.60 | 7.33 | 6.04 | 9.55 | 0.63 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| twisted_names | 3.68 | 2.83 | 5.01 | 6.50 | 0.77 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ +| twisted_pb | 4.94 | 3.02 | 5.10 | 8.34 | 0.61 | ++--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ + +XXX some stuff + +How to use PyPy? +================ + +We suggest using PyPy from a `virtualenv`_. Once you have a virtualenv +installed, you can follow instructions from `pypy documentation`_ on how +to proceed. This document also covers other `installation schemes`_. + +.. _`pypy documentation`: http://doc.pypy.org/en/latest/getting-started.html#installing-using-virtualenv +.. _`virtualenv`: http://www.virtualenv.org/en/latest/ +.. _`installation schemes`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy +.. _`PyPy and pip`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy + +XXXX more diff --git a/blog/draft/so_you_want.rst b/blog/draft/so_you_want.rst --- a/blog/draft/so_you_want.rst +++ b/blog/draft/so_you_want.rst @@ -25,9 +25,9 @@ since the introduction of `cffi`_, the ecosystem of PyPy-compatible software has been growing. Things I know are written with PyPy in mind: - * the new version of `PyOpenSSL`_ will support PyPy via cffi + * the new version of `pyOpenSSL`_ will support PyPy via cffi - * `pgsql2cffi`_ is the most actively maintained postgres binding for PyPy, + * `psycopg2cffi`_ is the most actively maintained postgres binding for PyPy, with pg8000 reported working * mysql has a `ctypes based implementation`_ (although a cffi-based one would @@ -40,9 +40,23 @@ * `uWSGI`_, while working, is almost certainly not the best choice. Try `tornado`_, `twisted.web`_, `cyclone.io`_, `gunicorn`_ or `gevent`_ (note: gevent support for PyPy is not quite finished; will write about it - in a separate blog post) + in a separate blog post, but you can't just use the main branch of gevent) - * consult (and contribute to) `pypy compatibility wiki`_ for details + * consult (and contribute to) `pypy compatibility wiki`_ for details (note + that it's community maintained, might be out of date) + +.. _`pypy compatibility wiki`: https://bitbucket.org/pypy/compatibility/wiki/Home +.. _`cffi`: http://cffi.readthedocs.org +.. _`pyOpenSSL`: https://launchpad.net/pyopenssl +.. _`psycopg2cffi`: https://github.com/chtd/psycopg2cffi +.. _`ctypes based implementation`: https://github.com/quora/mysql-ctypes +.. _`lxml-cffi`: https://github.com/amauryfa/lxml/tree/lxml-cffi +.. _`uWSGI`: https://github.com/unbit/uwsgi-docs +.. _`tornado`: http://www.tornadoweb.org/en/stable/ +.. _`twisted.web`: http://twistedmatrix.com/trac/wiki/TwistedWeb +.. _`cyclone.io`: http://cyclone.io/ +.. _`gunicorn`: http://gunicorn.org/ +.. _`gevent`: http://www.gevent.org/ * Have benchmarks. If you don't have benchmarks, then performance does not matter for you. Since PyPy's warm-up time is bad (and yes, we know, we're @@ -86,3 +100,8 @@ Cheers, fijal + +.. _`pypy-dev`: http://mail.python.org/mailman/listinfo/pypy-dev +.. _`jitviewer`: https://bitbucket.org/pypy/jitviewer +.. _`valgrind`: http://valgrind.org/ +.. _`lsprofcalltree`: https://bitbucket.org/pypy/pypy/src/default/rpython/tool/lsprofcalltree.py?at=default From noreply at buildbot.pypy.org Thu May 2 14:23:44 2013 From: noreply at buildbot.pypy.org (bivab) Date: Thu, 2 May 2013 14:23:44 +0200 (CEST) Subject: [pypy-commit] pypy default: add tests for vldm and vstm Message-ID: <20130502122344.BCA2A1C02DA@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63799:8cc8ee5b0f01 Date: 2013-05-02 14:17 +0200 http://bitbucket.org/pypy/pypy/changeset/8cc8ee5b0f01/ Log: add tests for vldm and vstm diff --git a/rpython/jit/backend/arm/test/test_assembler.py b/rpython/jit/backend/arm/test/test_assembler.py --- a/rpython/jit/backend/arm/test/test_assembler.py +++ b/rpython/jit/backend/arm/test/test_assembler.py @@ -6,6 +6,7 @@ from rpython.jit.backend.arm.test.support import run_asm from rpython.jit.backend.detect_cpu import getcpuclass from rpython.jit.metainterp.resoperation import rop +from rpython.jit.codewriter import longlong from rpython.rtyper.annlowlevel import llhelper from rpython.rtyper.lltypesystem import lltype, rffi @@ -273,12 +274,50 @@ self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, container)) self.a.mc.LDM(r.ip.value, [x for x in range(10)]) for x in range(1, 10): - self.a.mc.ADD_ri(0, 0, x) + self.a.mc.ADD_rr(0, 0, x) self.a.gen_func_epilog() - res = run_asm(self.a) + res = run_asm(self.a) assert res == sum(range(10)) lltype.free(container, flavor='raw') + def test_vstm(self): + n = 14 + source_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + target_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + for x in range(n): + source_container[x] = longlong.getfloatstorage(float("%d.%d" % (x,x))) + self.a.gen_func_prolog() + for x in range(n): + self.a.mc.ADD_ri(r.ip.value, r.ip.value, 8) + self.a.mc.VLDR(n, r.ip.value) + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, target_container)) + self.a.mc.VSTM(r.ip.value, [x for x in range(n)]) + self.a.gen_func_epilog() + run_asm(self.a) + for d in range(n): + res = longlong.getrealfloat(target_container[0]) == float("%d.%d" % (d,d)) + lltype.free(source_container, flavor='raw') + lltype.free(target_container, flavor='raw') + + def test_vldm(self): + n = 14 + container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + for x in range(n): + container[x] = longlong.getfloatstorage(float("%d.%d" % (x,x))) + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, container)) + self.a.mc.VLDM(r.ip.value, [x for x in range(n)]) + for x in range(1, n): + self.a.mc.VADD(0, 0, x) + self.a.mc.VSTR(r.d0.value, r.ip.value) + self.a.gen_func_epilog() + res = run_asm(self.a) + assert longlong.getrealfloat(container[0]) == sum([float("%d.%d" % (d,d)) for d in range(n)]) + lltype.free(container, flavor='raw') + def callme(inp): i = inp + 10 return i From noreply at buildbot.pypy.org Thu May 2 14:23:45 2013 From: noreply at buildbot.pypy.org (bivab) Date: Thu, 2 May 2013 14:23:45 +0200 (CEST) Subject: [pypy-commit] pypy default: add a test using both vldm and vstm Message-ID: <20130502122345.ED9FC1C02DA@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63800:a13c07067613 Date: 2013-05-02 14:20 +0200 http://bitbucket.org/pypy/pypy/changeset/a13c07067613/ Log: add a test using both vldm and vstm diff --git a/rpython/jit/backend/arm/test/test_assembler.py b/rpython/jit/backend/arm/test/test_assembler.py --- a/rpython/jit/backend/arm/test/test_assembler.py +++ b/rpython/jit/backend/arm/test/test_assembler.py @@ -318,6 +318,26 @@ assert longlong.getrealfloat(container[0]) == sum([float("%d.%d" % (d,d)) for d in range(n)]) lltype.free(container, flavor='raw') + def test_vstm_vldm_combined(self): + n = 14 + source_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + target_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + for x in range(n): + source_container[x] = longlong.getfloatstorage(float("%d.%d" % (x,x))) + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, source_container)) + self.a.mc.VLDM(r.ip.value, [x for x in range(n)]) + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, target_container)) + self.a.mc.VSTM(r.ip.value, [x for x in range(n)]) + self.a.gen_func_epilog() + run_asm(self.a) + for d in range(n): + res = longlong.getrealfloat(target_container[0]) == float("%d.%d" % (d,d)) + lltype.free(source_container, flavor='raw') + lltype.free(target_container, flavor='raw') + def callme(inp): i = inp + 10 return i From noreply at buildbot.pypy.org Thu May 2 14:43:02 2013 From: noreply at buildbot.pypy.org (bivab) Date: Thu, 2 May 2013 14:43:02 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: some fixes Message-ID: <20130502124302.940C91C02DA@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: extradoc Changeset: r4967:d4cba19b64b5 Date: 2013-05-02 14:42 +0200 http://bitbucket.org/pypy/extradoc/changeset/d4cba19b64b5/ Log: some fixes diff --git a/blog/draft/pypy-alpha-arm.rst b/blog/draft/pypy-alpha-arm.rst --- a/blog/draft/pypy-alpha-arm.rst +++ b/blog/draft/pypy-alpha-arm.rst @@ -8,9 +8,9 @@ a technology preview, as we know the JIT is not yet stable enough for the full release. However please try your stuff on ARM and report back. -This is the first release that supports a range of ARM devices - anything -with ARMv6 (that supports VFP, like raspberry pi) or ARMv7 (soft- or hard-float) -should work. +This is the first release that supports a range of ARM devices - anything with +ARMv6 (like the Raspberry Pi) or ARMv7 (like Beagleboard, Chromebook, +Cubieboard, etc) that supports VFPv3 should work. This release comes with a list of limitations, consider it alpha quality, not suitable for production: @@ -40,7 +40,7 @@ Benchmarks ========== -Everybody loves benchmarks. Here is a table of our benchmark suite (we don't +Everybody loves benchmarks. Here is a table of our benchmark suite (for ARM we don't provide it yet on http://speed.pypy.org, unfortunately). This is a comparison of Cortex A9 processor with 4M cache and Xeon XXX fill in From noreply at buildbot.pypy.org Thu May 2 19:20:36 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 2 May 2013 19:20:36 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: work on a draft Message-ID: <20130502172036.5AA941C0328@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r4968:ee64ee05d215 Date: 2013-05-02 19:20 +0200 http://bitbucket.org/pypy/extradoc/changeset/ee64ee05d215/ Log: work on a draft diff --git a/blog/draft/pypy-alpha-arm.rst b/blog/draft/pypy-alpha-arm.rst --- a/blog/draft/pypy-alpha-arm.rst +++ b/blog/draft/pypy-alpha-arm.rst @@ -40,10 +40,27 @@ Benchmarks ========== -Everybody loves benchmarks. Here is a table of our benchmark suite (for ARM we don't -provide it yet on http://speed.pypy.org, unfortunately). +Everybody loves benchmarks. Here is a table of our benchmark suite +(for ARM we don't provide it yet on http://speed.pypy.org, +unfortunately). -This is a comparison of Cortex A9 processor with 4M cache and Xeon XXX fill in +This is a comparison of Cortex A9 processor with 4M cache and Xeon W3580 with +8M of L3 cache. The set of benchmarks is a subset of what we run for +http://speed.pypy.org that finishes in reasonable time. The ARM machine +was provided by Calxeda. +Columns are respectively: + +* benchmark name + +* PyPy speedup over CPython on ARM + +* PyPy speedup over CPython on x86 + +* speedup on Xeon vs Cortex A9, as measured on CPython + +* speedup on Xeon vs Cortex A9, as measured on PyPy + +* relative speedup (how much bigger the x86 speedup is over ARM speedup) +--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ | Benchmark | PyPy vs CPython (arm) | PyPy vs CPython (x86) | x86 vs arm (pypy) | x86 vs arm (cpython) | relative speedup | @@ -111,7 +128,11 @@ | twisted_pb | 4.94 | 3.02 | 5.10 | 8.34 | 0.61 | +--------------------+-----------------------+-----------------------+-------------------+----------------------+------------------+ -XXX some stuff +It seems that Cortex A9, while significantly slower than Xeon, has higher +slowdowns with a large interpreter (CPython) than a JIT compiler (PyPy). This +comes as a surprise to me, especially that our ARM assembler is not nearly +as polished as our x86 assembler. As for the causes, various people mentioned +branch predictor, but I would not like to speculate without actually knowing. How to use PyPy? ================ @@ -125,4 +146,8 @@ .. _`installation schemes`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy .. _`PyPy and pip`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy -XXXX more +We would not recommend using PyPy on ARM just quite yet, however the day +of a stable PyPy ARM release is not far off. + +Cheers, +fijal, bivab, arigo and the whole PyPy team From noreply at buildbot.pypy.org Thu May 2 19:30:24 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 2 May 2013 19:30:24 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: make a pypy 2.0 final branch Message-ID: <20130502173024.9720F1C146E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: release-2.0.x Changeset: r63801:84c828b37f34 Date: 2013-05-02 19:29 +0200 http://bitbucket.org/pypy/pypy/changeset/84c828b37f34/ Log: make a pypy 2.0 final branch diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.3" /* PyPy version as a string */ -#define PYPY_VERSION "2.0.0-beta2" +#define PYPY_VERSION "2.0.0" /* Subversion Revision number of this file (not of the repository). * Empty since Mercurial migration. */ diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -11,7 +11,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (2, 0, 0, "beta", 2) #XXX # sync patchlevel.h +PYPY_VERSION = (2, 0, 0, "final", 0) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) From noreply at buildbot.pypy.org Thu May 2 20:53:07 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 2 May 2013 20:53:07 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: merge those from default Message-ID: <20130502185307.216C11C304F@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: release-2.0.x Changeset: r63803:4e35a19559a3 Date: 2013-05-02 20:52 +0200 http://bitbucket.org/pypy/pypy/changeset/4e35a19559a3/ Log: merge those from default diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-2.0.rst copy from pypy/doc/whatsnew-head.rst copy to pypy/doc/whatsnew-2.0.rst diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -1,140 +1,8 @@ ====================== -What's new in PyPy 2.0 +What's new in PyPy 2.1 ====================== -.. this is a revision shortly after release-2.0-beta1 -.. startrev: 0e6161a009c6 +.. this is a revision shortly after release-2.0 +.. startrev: a13c07067613 -.. branch: split-rpython -Split rpython and pypy into seperate directories -.. branch: callback-jit -Callbacks from C are now better JITted - -.. branch: fix-jit-logs - -.. branch: remove-globals-in-jit - -.. branch: length-hint -Implement __lenght_hint__ according to PEP 424 - -.. branch: numpypy-longdouble -Long double support for numpypy - -.. branch: numpypy-disable-longdouble -Since r_longdouble support is missing, disable all longdouble and derivative -dtypes using ENABLED_LONG_DOUBLE = False - -.. branch: numpypy-real-as-view -Convert real, imag from ufuncs to views. This involves the beginning of -view() functionality - -.. branch: indexing-by-array -Adds indexing by scalar, adds int conversion from scalar and single element array, -fixes compress, indexing by an array with a smaller shape and the indexed object. - -.. branch: str-dtype-improvement -Allow concatenation of str and numeric arrays - -.. branch: signatures -Improved RPython typing - -.. branch: rpython-bytearray -Rudimentary support for bytearray in RPython - -.. branch: refactor-call_release_gil -Fix a bug which caused cffi to return the wrong result when calling a C -function which calls a Python callback which forces the frames - -.. branch: virtual-raw-mallocs -JIT optimizations which make cffi calls even faster, by removing the need to -allocate a temporary buffer where to store the arguments. - -.. branch: improve-docs-2 -Improve documents and straighten out links - -.. branch: fast-newarray -Inline the fast path of newarray in the assembler. -Disabled on ARM until we fix issues. - -.. branch: reflex-support -Allow dynamic loading of a (Reflex) backend that implements the C-API needed -to provide reflection information - -.. branches we don't care about -.. branch: autoreds -.. branch: kill-faking -.. branch: improved_ebnfparse_error -.. branch: task-decorator -.. branch: fix-e4fa0b2 -.. branch: win32-fixes -.. branch: numpy-unify-methods -.. branch: fix-version-tool -.. branch: popen2-removal -.. branch: pickle-dumps -.. branch: scalar_get_set - -.. branch: release-2.0-beta1 - -.. branch: remove-PYPY_NOT_MAIN_FILE - -.. branch: missing-jit-operations - -.. branch: fix-lookinside-iff-oopspec -Fixed the interaction between two internal tools for controlling the JIT. - -.. branch: inline-virtualref-2 -Better optimized certain types of frame accesses in the JIT, particularly -around exceptions that escape the function they were raised in. - -.. branch: missing-ndarray-attributes -Some missing attributes from ndarrays - -.. branch: cleanup-tests -Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into -one directory for reduced confusion and so they all run nightly. - -.. branch: unquote-faster -.. branch: urlparse-unquote-faster - -.. branch: signal-and-thread -Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a -non-main thread to enable the processing of signal handlers in that thread. - -.. branch: coding-guide-update-rlib-refs -.. branch: rlib-doc-rpython-refs -.. branch: clean-up-remaining-pypy-rlib-refs - -.. branch: enumerate-rstr -Support enumerate() over rstr types. - -.. branch: cleanup-numpypy-namespace -Cleanup _numpypy and numpypy namespaces to more closely resemble numpy. - -.. branch: kill-flowobjspace -Random cleanups to hide FlowObjSpace from public view. - -.. branch: vendor-rename - -.. branch: jitframe-on-heap -Moves optimized JIT frames from stack to heap. As a side effect it enables -stackless to work well with the JIT on PyPy. Also removes a bunch of code from -the GC which fixes cannot find gc roots. - -.. branch: pycon2013-doc-fixes -Documentation fixes after going through the docs at PyCon 2013 sprint. - -.. branch: extregistry-refactor - -.. branch: remove-list-smm -.. branch: bridge-logging -.. branch: curses_cffi -cffi implementation of _curses - -.. branch: sqlite-cffi -cffi implementation of sqlite3 - -.. branch: release-2.0-beta2 -.. branch: unbreak-freebsd - -.. branch: virtualref-virtualizable From noreply at buildbot.pypy.org Thu May 2 20:53:05 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 2 May 2013 20:53:05 +0200 (CEST) Subject: [pypy-commit] pypy default: Shuffle whatsnew Message-ID: <20130502185305.E66A81C146E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63802:845da2d0e699 Date: 2013-05-02 20:52 +0200 http://bitbucket.org/pypy/pypy/changeset/845da2d0e699/ Log: Shuffle whatsnew diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-2.0.rst copy from pypy/doc/whatsnew-head.rst copy to pypy/doc/whatsnew-2.0.rst diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -1,140 +1,8 @@ ====================== -What's new in PyPy 2.0 +What's new in PyPy 2.1 ====================== -.. this is a revision shortly after release-2.0-beta1 -.. startrev: 0e6161a009c6 +.. this is a revision shortly after release-2.0 +.. startrev: a13c07067613 -.. branch: split-rpython -Split rpython and pypy into seperate directories -.. branch: callback-jit -Callbacks from C are now better JITted - -.. branch: fix-jit-logs - -.. branch: remove-globals-in-jit - -.. branch: length-hint -Implement __lenght_hint__ according to PEP 424 - -.. branch: numpypy-longdouble -Long double support for numpypy - -.. branch: numpypy-disable-longdouble -Since r_longdouble support is missing, disable all longdouble and derivative -dtypes using ENABLED_LONG_DOUBLE = False - -.. branch: numpypy-real-as-view -Convert real, imag from ufuncs to views. This involves the beginning of -view() functionality - -.. branch: indexing-by-array -Adds indexing by scalar, adds int conversion from scalar and single element array, -fixes compress, indexing by an array with a smaller shape and the indexed object. - -.. branch: str-dtype-improvement -Allow concatenation of str and numeric arrays - -.. branch: signatures -Improved RPython typing - -.. branch: rpython-bytearray -Rudimentary support for bytearray in RPython - -.. branch: refactor-call_release_gil -Fix a bug which caused cffi to return the wrong result when calling a C -function which calls a Python callback which forces the frames - -.. branch: virtual-raw-mallocs -JIT optimizations which make cffi calls even faster, by removing the need to -allocate a temporary buffer where to store the arguments. - -.. branch: improve-docs-2 -Improve documents and straighten out links - -.. branch: fast-newarray -Inline the fast path of newarray in the assembler. -Disabled on ARM until we fix issues. - -.. branch: reflex-support -Allow dynamic loading of a (Reflex) backend that implements the C-API needed -to provide reflection information - -.. branches we don't care about -.. branch: autoreds -.. branch: kill-faking -.. branch: improved_ebnfparse_error -.. branch: task-decorator -.. branch: fix-e4fa0b2 -.. branch: win32-fixes -.. branch: numpy-unify-methods -.. branch: fix-version-tool -.. branch: popen2-removal -.. branch: pickle-dumps -.. branch: scalar_get_set - -.. branch: release-2.0-beta1 - -.. branch: remove-PYPY_NOT_MAIN_FILE - -.. branch: missing-jit-operations - -.. branch: fix-lookinside-iff-oopspec -Fixed the interaction between two internal tools for controlling the JIT. - -.. branch: inline-virtualref-2 -Better optimized certain types of frame accesses in the JIT, particularly -around exceptions that escape the function they were raised in. - -.. branch: missing-ndarray-attributes -Some missing attributes from ndarrays - -.. branch: cleanup-tests -Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into -one directory for reduced confusion and so they all run nightly. - -.. branch: unquote-faster -.. branch: urlparse-unquote-faster - -.. branch: signal-and-thread -Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a -non-main thread to enable the processing of signal handlers in that thread. - -.. branch: coding-guide-update-rlib-refs -.. branch: rlib-doc-rpython-refs -.. branch: clean-up-remaining-pypy-rlib-refs - -.. branch: enumerate-rstr -Support enumerate() over rstr types. - -.. branch: cleanup-numpypy-namespace -Cleanup _numpypy and numpypy namespaces to more closely resemble numpy. - -.. branch: kill-flowobjspace -Random cleanups to hide FlowObjSpace from public view. - -.. branch: vendor-rename - -.. branch: jitframe-on-heap -Moves optimized JIT frames from stack to heap. As a side effect it enables -stackless to work well with the JIT on PyPy. Also removes a bunch of code from -the GC which fixes cannot find gc roots. - -.. branch: pycon2013-doc-fixes -Documentation fixes after going through the docs at PyCon 2013 sprint. - -.. branch: extregistry-refactor - -.. branch: remove-list-smm -.. branch: bridge-logging -.. branch: curses_cffi -cffi implementation of _curses - -.. branch: sqlite-cffi -cffi implementation of sqlite3 - -.. branch: release-2.0-beta2 -.. branch: unbreak-freebsd - -.. branch: virtualref-virtualizable From noreply at buildbot.pypy.org Thu May 2 21:25:14 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 2 May 2013 21:25:14 +0200 (CEST) Subject: [pypy-commit] pypy py3k: handle CRLF too for windows Message-ID: <20130502192514.C33FC1C146E@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63804:089736259e98 Date: 2013-05-02 12:21 -0700 http://bitbucket.org/pypy/pypy/changeset/089736259e98/ Log: handle CRLF too for windows diff --git a/pypy/tool/pytest/apptest.py b/pypy/tool/pytest/apptest.py --- a/pypy/tool/pytest/apptest.py +++ b/pypy/tool/pytest/apptest.py @@ -78,9 +78,10 @@ class ExceptionWrapper: pass def raises(exc, func, *args, **kwargs): + import os try: if isinstance(func, str): - if func.startswith(" ") or func.startswith("\n"): + if func.startswith((' ', os.linesep)): # it's probably an indented block, so we prefix if True: # to avoid SyntaxError func = "if True:\n" + func From noreply at buildbot.pypy.org Thu May 2 21:25:17 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 2 May 2013 21:25:17 +0200 (CEST) Subject: [pypy-commit] pypy py3k: not applicable to windows Message-ID: <20130502192517.1E6861C146E@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63805:f42b3a09594f Date: 2013-05-02 12:22 -0700 http://bitbucket.org/pypy/pypy/changeset/f42b3a09594f/ Log: not applicable to windows diff --git a/pypy/module/thread/test/test_lock.py b/pypy/module/thread/test/test_lock.py --- a/pypy/module/thread/test/test_lock.py +++ b/pypy/module/thread/test/test_lock.py @@ -1,4 +1,5 @@ from __future__ import with_statement +import py import sys from pypy.module.thread.test.support import GenericTestThread from rpython.translator.c.test.test_genc import compile @@ -149,6 +150,7 @@ class AppTestLockSignals(GenericTestThread): + pytestmark = py.test.mark.skipif("sys.platform != 'posix'") def setup_class(cls): cls.w_using_pthread_cond = cls.space.wrap(sys.platform == 'freebsd6') From noreply at buildbot.pypy.org Thu May 2 21:25:18 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 2 May 2013 21:25:18 +0200 (CEST) Subject: [pypy-commit] pypy py3k: 2to3 Message-ID: <20130502192518.A30071C146E@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63806:aeb541bf1ab8 Date: 2013-05-02 12:22 -0700 http://bitbucket.org/pypy/pypy/changeset/aeb541bf1ab8/ Log: 2to3 diff --git a/pypy/module/__builtin__/test/test_zip.py b/pypy/module/__builtin__/test/test_zip.py --- a/pypy/module/__builtin__/test/test_zip.py +++ b/pypy/module/__builtin__/test/test_zip.py @@ -15,9 +15,9 @@ def test_two_lists(self): # uses a different code path - assert zip([1, 2, 3], [3, 4, 5]) == [(1, 3), (2, 4), (3, 5)] - assert zip([1, 2, 3], [3, 4]) == [(1, 3), (2, 4)] - assert zip([1, 2], [3, 4, 5]) == [(1, 3), (2, 4)] + assert list(zip([1, 2, 3], [3, 4, 5])) == [(1, 3), (2, 4), (3, 5)] + assert list(zip([1, 2, 3], [3, 4])) == [(1, 3), (2, 4)] + assert list(zip([1, 2], [3, 4, 5])) == [(1, 3), (2, 4)] def test_three_lists_same_size(self): assert list(zip([1, 2, 3], [3, 4, 5], [6, 7, 8])) == ( From noreply at buildbot.pypy.org Thu May 2 22:15:47 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 2 May 2013 22:15:47 +0200 (CEST) Subject: [pypy-commit] pypy default: Add some failing tests: Message-ID: <20130502201547.66DDE1C0547@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63807:f81be71175fe Date: 2013-05-02 22:14 +0200 http://bitbucket.org/pypy/pypy/changeset/f81be71175fe/ Log: Add some failing tests: - singlefloat return values should be supported; the backend certainly supports them. - if the backend says it doesn't support some of the types, don't crash with a KeyError. diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -11,7 +11,7 @@ from rpython.rlib.jit_libffi import (types, CIF_DESCRIPTION, FFI_TYPE_PP, jit_ffi_call, jit_ffi_save_result) from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.rarithmetic import intmask, r_longlong +from rpython.rlib.rarithmetic import intmask, r_longlong, r_singlefloat from rpython.rlib.longlong2float import float2longlong def get_description(atypes, rtype): @@ -67,7 +67,11 @@ for avalue in unroll_avalues: TYPE = rffi.CArray(lltype.typeOf(avalue)) data = rffi.ptradd(exchange_buffer, ofs) - assert rffi.cast(lltype.Ptr(TYPE), data)[0] == avalue + got = rffi.cast(lltype.Ptr(TYPE), data)[0] + if lltype.typeOf(avalue) is lltype.SingleFloat: + got = float(got) + avalue = float(avalue) + assert got == avalue ofs += 16 if rvalue is not None: write_rvalue = rvalue @@ -128,6 +132,14 @@ b = r_longlong(maxint32) + 2 self._run([types.slonglong] * 2, types.slonglong, [a, b], a) + def test_simple_call_singlefloat_args(self): + self._run([types.float] * 2, types.double, [r_singlefloat(10.5), + r_singlefloat(31.5)], -4.5) + + def test_simple_call_singlefloat(self): + self._run([types.float] * 2, types.float, [r_singlefloat(10.5), + r_singlefloat(31.5)], -4.5) + def test_simple_call_longdouble(self): # longdouble is not supported, so we expect NOT to generate a call_release_gil self._run([types.longdouble] * 2, types.longdouble, [12.3, 45.6], 78.9, @@ -266,3 +278,24 @@ assert res == math.sin(1.23) lltype.free(atypes, flavor='raw') + + def _patch_cpuclass(self, **change): + def make_cpu(*args, **kwds): + cpu = CPUClass(*args, **kwds) + for key, value in change.items(): + setattr(cpu, key, value) + return cpu + CPUClass = self.CPUClass + self.CPUClass = make_cpu + + def test_simple_call_float_unsupported(self): + self._patch_cpuclass(supports_floats=False) + self.test_simple_call_float() + + def test_simple_call_longlong_unsupported(self): + self._patch_cpuclass(supports_longlong=False) + self.test_simple_call_longlong() + + def test_simple_call_singlefloat_unsupported(self): + self._patch_cpuclass(supports_singlefloats=False) + self.test_simple_call_singlefloat() From noreply at buildbot.pypy.org Thu May 2 23:01:13 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 2 May 2013 23:01:13 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix the failing tests added in f81be71175fe: Message-ID: <20130502210113.3B8C21C146E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63808:e23dbce85236 Date: 2013-05-02 23:00 +0200 http://bitbucket.org/pypy/pypy/changeset/e23dbce85236/ Log: Fix the failing tests added in f81be71175fe: - support for singlefloat return values - if the backend says it doesn't support some of the types, don't crash with a KeyError Moreover, avoids casting a real longlong temporarily into a float. This is frowned upon by now, because a small fraction of longlongs don't cast correctly to float and back. diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -1751,7 +1751,7 @@ def rewrite_op_jit_ffi_save_result(self, op): kind = op.args[0].value - assert kind in ('int', 'float') + assert kind in ('int', 'float', 'longlong', 'singlefloat') return SpaceOperation('libffi_save_result_%s' % kind, op.args[1:], None) def rewrite_op_jit_force_virtual(self, op): diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -1351,24 +1351,39 @@ def bhimpl_ll_read_timestamp(): return read_timestamp() - @arguments("cpu", "i", "i", "i") - def bhimpl_libffi_save_result_int(self, cif_description, exchange_buffer, result): - ARRAY = lltype.Ptr(rffi.CArray(lltype.Signed)) - cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) - exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP) + def _libffi_save_result(self, cif_description, exchange_buffer, result): + ARRAY = lltype.Ptr(rffi.CArray(lltype.typeOf(result))) + cast_int_to_ptr = self.cpu.cast_int_to_ptr + cif_description = cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) + exchange_buffer = cast_int_to_ptr(exchange_buffer, rffi.CCHARP) # data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result) rffi.cast(ARRAY, data_out)[0] = result + _libffi_save_result._annspecialcase_ = 'specialize:argtype(3)' - @arguments("cpu", "i", "i", "f") - def bhimpl_libffi_save_result_float(self, cif_description, exchange_buffer, result): + @arguments("self", "i", "i", "i") + def bhimpl_libffi_save_result_int(self, cif_description, + exchange_buffer, result): + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "f") + def bhimpl_libffi_save_result_float(self, cif_description, + exchange_buffer, result): result = longlong.getrealfloat(result) - ARRAY = lltype.Ptr(rffi.CArray(lltype.Float)) - cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) - exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP) - # - data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result) - rffi.cast(ARRAY, data_out)[0] = result + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "f") + def bhimpl_libffi_save_result_longlong(self, cif_description, + exchange_buffer, result): + # 32-bit only: 'result' is here a LongLong + assert longlong.is_longlong(lltype.typeOf(result)) + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "i") + def bhimpl_libffi_save_result_singlefloat(self, cif_description, + exchange_buffer, result): + result = longlong.int2singlefloat(result) + self._libffi_save_result(cif_description, exchange_buffer, result) # ---------- diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1190,8 +1190,8 @@ return self.metainterp.execute_and_record(rop.READ_TIMESTAMP, None) @arguments("box", "box", "box") - def opimpl_libffi_save_result_int(self, box_cif_description, box_exchange_buffer, - box_result): + def _opimpl_libffi_save_result(self, box_cif_description, + box_exchange_buffer, box_result): from rpython.rtyper.lltypesystem import llmemory from rpython.rlib.jit_libffi import CIF_DESCRIPTION_P from rpython.jit.backend.llsupport.ffisupport import get_arg_descr @@ -1208,10 +1208,14 @@ assert ofs % itemsize == 0 # alignment check (result) self.metainterp.history.record(rop.SETARRAYITEM_RAW, [box_exchange_buffer, - ConstInt(ofs // itemsize), box_result], + ConstInt(ofs // itemsize), + box_result], None, descr) - opimpl_libffi_save_result_float = opimpl_libffi_save_result_int + opimpl_libffi_save_result_int = _opimpl_libffi_save_result + opimpl_libffi_save_result_float = _opimpl_libffi_save_result + opimpl_libffi_save_result_longlong = _opimpl_libffi_save_result + opimpl_libffi_save_result_singlefloat = _opimpl_libffi_save_result # ------------------------------ diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -14,7 +14,10 @@ def _get_jitcodes(testself, CPUClass, func, values, type_system, - supports_longlong=False, translationoptions={}, **kwds): + supports_floats=True, + supports_longlong=False, + supports_singlefloats=False, + translationoptions={}, **kwds): from rpython.jit.codewriter import support class FakeJitCell(object): @@ -68,8 +71,9 @@ cw.debug = True testself.cw = cw policy = JitPolicy() - policy.set_supports_floats(True) + policy.set_supports_floats(supports_floats) policy.set_supports_longlong(supports_longlong) + policy.set_supports_singlefloats(supports_singlefloats) graphs = cw.find_all_graphs(policy) if kwds.get("backendopt"): backend_optimizations(rtyper.annotator.translator, graphs=graphs) diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -5,7 +5,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.annlowlevel import llhelper from rpython.jit.metainterp.test.support import LLJitMixin -from rpython.jit.codewriter.longlong import is_longlong +from rpython.jit.codewriter.longlong import is_longlong, is_64_bit from rpython.rlib import jit from rpython.rlib import jit_libffi from rpython.rlib.jit_libffi import (types, CIF_DESCRIPTION, FFI_TYPE_PP, @@ -45,7 +45,12 @@ class FfiCallTests(object): - def _run(self, atypes, rtype, avalues, rvalue, expected_call_release_gil=1): + def _run(self, atypes, rtype, avalues, rvalue, + expected_call_release_gil=1, + supports_floats=True, + supports_longlong=True, + supports_singlefloats=True): + cif_description = get_description(atypes, rtype) def verify(*args): @@ -100,17 +105,30 @@ data = rffi.ptradd(exbuf, ofs) res = rffi.cast(lltype.Ptr(TYPE), data)[0] lltype.free(exbuf, flavor='raw') + if lltype.typeOf(res) is lltype.SingleFloat: + res = float(res) return res + def matching_result(res, rvalue): + if rvalue is None: + return res == 654321 + if isinstance(rvalue, r_singlefloat): + rvalue = float(rvalue) + return res == rvalue + with FakeFFI(fake_call_impl_any): res = f() - assert res == rvalue or (res, rvalue) == (654321, None) - res = self.interp_operations(f, []) + assert matching_result(res, rvalue) + res = self.interp_operations(f, [], + supports_floats = supports_floats, + supports_longlong = supports_longlong, + supports_singlefloats = supports_singlefloats) if is_longlong(FUNC.RESULT): - # longlongs are passed around as floats inside the JIT, we - # need to convert it back before checking the value + # longlongs are returned as floats, but that's just + # an inconvenience of interp_operations(). Normally both + # longlong and floats are passed around as longlongs. res = float2longlong(res) - assert res == rvalue or (res, rvalue) == (654321, None) + assert matching_result(res, rvalue) self.check_operations_history(call_may_force=0, call_release_gil=expected_call_release_gil) @@ -123,22 +141,24 @@ [-123456*j for j in range(i)], -42434445) - def test_simple_call_float(self): - self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2) + def test_simple_call_float(self, **kwds): + self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2, **kwds) - def test_simple_call_longlong(self): + def test_simple_call_longlong(self, **kwds): maxint32 = 2147483647 a = r_longlong(maxint32) + 1 b = r_longlong(maxint32) + 2 - self._run([types.slonglong] * 2, types.slonglong, [a, b], a) + self._run([types.slonglong] * 2, types.slonglong, [a, b], a, **kwds) def test_simple_call_singlefloat_args(self): - self._run([types.float] * 2, types.double, [r_singlefloat(10.5), - r_singlefloat(31.5)], -4.5) + self._run([types.float] * 2, types.double, + [r_singlefloat(10.5), r_singlefloat(31.5)], + -4.5) - def test_simple_call_singlefloat(self): - self._run([types.float] * 2, types.float, [r_singlefloat(10.5), - r_singlefloat(31.5)], -4.5) + def test_simple_call_singlefloat(self, **kwds): + self._run([types.float] * 2, types.float, + [r_singlefloat(10.5), r_singlefloat(31.5)], + r_singlefloat(-4.5), **kwds) def test_simple_call_longdouble(self): # longdouble is not supported, so we expect NOT to generate a call_release_gil @@ -279,23 +299,19 @@ lltype.free(atypes, flavor='raw') - def _patch_cpuclass(self, **change): - def make_cpu(*args, **kwds): - cpu = CPUClass(*args, **kwds) - for key, value in change.items(): - setattr(cpu, key, value) - return cpu - CPUClass = self.CPUClass - self.CPUClass = make_cpu - def test_simple_call_float_unsupported(self): - self._patch_cpuclass(supports_floats=False) - self.test_simple_call_float() + self.test_simple_call_float(supports_floats=False, + expected_call_release_gil=0) def test_simple_call_longlong_unsupported(self): - self._patch_cpuclass(supports_longlong=False) - self.test_simple_call_longlong() + self.test_simple_call_longlong(supports_longlong=False, + expected_call_release_gil=is_64_bit) def test_simple_call_singlefloat_unsupported(self): - self._patch_cpuclass(supports_singlefloats=False) - self.test_simple_call_singlefloat() + self.test_simple_call_singlefloat(supports_singlefloats=False, + expected_call_release_gil=0) + + def test_simple_call_float_even_if_other_unsupported(self): + self.test_simple_call_float(supports_longlong=False, + supports_singlefloats=False) + # this is the default: expected_call_release_gil=1 diff --git a/rpython/rlib/jit_libffi.py b/rpython/rlib/jit_libffi.py --- a/rpython/rlib/jit_libffi.py +++ b/rpython/rlib/jit_libffi.py @@ -2,6 +2,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.rlib import clibffi, jit +from rpython.rlib.rarithmetic import r_longlong, r_singlefloat from rpython.rlib.nonconst import NonConstant @@ -107,12 +108,14 @@ reskind = types.getkind(cif_description.rtype) if reskind == 'v': jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer) - elif reskind == 'f' or reskind == 'L': # L is for longlongs, on 32bit - result = jit_ffi_call_impl_float(cif_description, func_addr, exchange_buffer) - jit_ffi_save_result('float', cif_description, exchange_buffer, result) elif reskind == 'i' or reskind == 'u': - result = jit_ffi_call_impl_int(cif_description, func_addr, exchange_buffer) - jit_ffi_save_result('int', cif_description, exchange_buffer, result) + _do_ffi_call_int(cif_description, func_addr, exchange_buffer) + elif reskind == 'f': + _do_ffi_call_float(cif_description, func_addr, exchange_buffer) + elif reskind == 'L': # L is for longlongs, on 32bit + _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer) + elif reskind == 'S': # SingleFloat + _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer) else: # the result kind is not supported: we disable the jit_ffi_call # optimization by calling directly jit_ffi_call_impl_any, so the JIT @@ -123,6 +126,30 @@ jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) +def _do_ffi_call_int(cif_description, func_addr, exchange_buffer): + result = jit_ffi_call_impl_int(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('int', cif_description, exchange_buffer, result) + +def _do_ffi_call_float(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support floats + result = jit_ffi_call_impl_float(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('float', cif_description, exchange_buffer, result) + +def _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support longlongs + result = jit_ffi_call_impl_longlong(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('longlong', cif_description, exchange_buffer, result) + +def _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support singlefloats + result = jit_ffi_call_impl_singlefloat(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('singlefloat', cif_description, exchange_buffer,result) + + # we must return a NonConstant else we get the constant -1 as the result of # the flowgraph, and the codewriter does not produce a box for the # result. Note that when not-jitted, the result is unused, but when jitted the @@ -139,6 +166,16 @@ return NonConstant(-1.0) @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") +def jit_ffi_call_impl_longlong(cif_description, func_addr, exchange_buffer): + jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) + return r_longlong(-1) + + at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") +def jit_ffi_call_impl_singlefloat(cif_description, func_addr, exchange_buffer): + jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) + return r_singlefloat(-1.0) + + at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") def jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer): jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) return None @@ -175,7 +212,7 @@ def compute_result_annotation(self, kind_s, *args_s): from rpython.annotator import model as annmodel assert isinstance(kind_s, annmodel.SomeString) - assert kind_s.const in ('int', 'float') + assert kind_s.const in ('int', 'float', 'longlong', 'singlefloat') def specialize_call(self, hop): hop.exception_cannot_occur() From noreply at buildbot.pypy.org Thu May 2 23:25:46 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 2 May 2013 23:25:46 +0200 (CEST) Subject: [pypy-commit] pypy default: I *think* this should skip tests when running from the backend/*/test Message-ID: <20130502212546.1B8021C0547@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63809:5afd0cd73c54 Date: 2013-05-02 23:24 +0200 http://bitbucket.org/pypy/pypy/changeset/5afd0cd73c54/ Log: I *think* this should skip tests when running from the backend/*/test directory and the tests require some more support that what the real cpu provides. diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -70,6 +70,12 @@ cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()]) cw.debug = True testself.cw = cw + if supports_floats and not cpu.supports_floats: + py.test.skip("this test requires supports_floats=True") + if supports_longlong and not cpu.supports_longlong: + py.test.skip("this test requires supports_longlong=True") + if supports_singlefloats and not cpu.supports_singlefloats: + py.test.skip("this test requires supports_singlefloats=True") policy = JitPolicy() policy.set_supports_floats(supports_floats) policy.set_supports_longlong(supports_longlong) From noreply at buildbot.pypy.org Fri May 3 00:35:28 2013 From: noreply at buildbot.pypy.org (mwhudson) Date: Fri, 3 May 2013 00:35:28 +0200 (CEST) Subject: [pypy-commit] benchmarks default: Be more tolerant of whitespace when parsing the --benchmarks command line Message-ID: <20130502223528.0B1AA1C0547@cobra.cs.uni-duesseldorf.de> Author: Michael Hudson-Doyle Branch: Changeset: r211:4e2d1eb469f0 Date: 2013-05-03 09:58 +1200 http://bitbucket.org/pypy/benchmarks/changeset/4e2d1eb469f0/ Log: Be more tolerant of whitespace when parsing the --benchmarks command line option. diff --git a/runner.py b/runner.py --- a/runner.py +++ b/runner.py @@ -258,7 +258,7 @@ options, args = parser.parse_args(argv) upload_options = get_upload_options(options) - benchmarks = options.benchmarks.split(',') + benchmarks = [benchmark.strip() for benchmark in options.benchmarks.split(',')] for benchmark in benchmarks: if benchmark not in BENCHMARK_SET: raise WrongBenchmark(benchmark) From noreply at buildbot.pypy.org Fri May 3 00:35:29 2013 From: noreply at buildbot.pypy.org (mwhudson) Date: Fri, 3 May 2013 00:35:29 +0200 (CEST) Subject: [pypy-commit] benchmarks default: Allow specifying the list of benchmarks to run in a file. Message-ID: <20130502223529.91ABF1C0547@cobra.cs.uni-duesseldorf.de> Author: Michael Hudson-Doyle Branch: Changeset: r212:0f491c14151b Date: 2013-05-03 10:08 +1200 http://bitbucket.org/pypy/benchmarks/changeset/0f491c14151b/ Log: Allow specifying the list of benchmarks to run in a file. diff --git a/runner.py b/runner.py --- a/runner.py +++ b/runner.py @@ -131,12 +131,15 @@ 'json file.')) benchmark_group.add_option( "-b", "--benchmarks", metavar="BM_LIST", - default=','.join(BENCHMARK_SET), help=("Comma-separated list of benchmarks to run" " Valid benchmarks are: %s" ". (default: Run all listed benchmarks)" ) % ", ".join(sorted(BENCHMARK_SET))) benchmark_group.add_option( + "-f", "--benchmarks-file", metavar="BM_FILE", + help=("Read the list of benchmarks to run from this file (one " + "benchmark name per line). Do not specify both this and -b.")) + benchmark_group.add_option( '-c', '--changed', default=sys.executable, help=('pypy-c or another modified python interpreter to run against. ' 'Also named the "changed" interpreter. (default: the python ' @@ -258,7 +261,28 @@ options, args = parser.parse_args(argv) upload_options = get_upload_options(options) - benchmarks = [benchmark.strip() for benchmark in options.benchmarks.split(',')] + if options.benchmarks is not None: + if options.benchmarks_file is not None: + parser.error( + '--benchmarks and --benchmarks-file are mutually exclusive') + else: + benchmarks = [benchmark.strip() + for benchmark in options.benchmarks.split(',')] + else: + if options.benchmarks_file is not None: + benchmarks = [] + try: + bm_file = open(options.benchmarks_file, 'rt') + except IOError as e: + parser.error('error opening benchmarks file: %s' % e) + try: + for line in bm_file: + benchmarks.append(line.strip()) + finally: + bm_file.close() + else: + benchmarks = list(BENCHMARK_SET) + for benchmark in benchmarks: if benchmark not in BENCHMARK_SET: raise WrongBenchmark(benchmark) From noreply at buildbot.pypy.org Fri May 3 00:58:59 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 3 May 2013 00:58:59 +0200 (CEST) Subject: [pypy-commit] benchmarks default: use the with statement Message-ID: <20130502225859.699E71C02DA@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r213:235ea28d5947 Date: 2013-05-02 15:58 -0700 http://bitbucket.org/pypy/benchmarks/changeset/235ea28d5947/ Log: use the with statement diff --git a/runner.py b/runner.py --- a/runner.py +++ b/runner.py @@ -275,11 +275,9 @@ bm_file = open(options.benchmarks_file, 'rt') except IOError as e: parser.error('error opening benchmarks file: %s' % e) - try: + with bm_file: for line in bm_file: benchmarks.append(line.strip()) - finally: - bm_file.close() else: benchmarks = list(BENCHMARK_SET) From noreply at buildbot.pypy.org Fri May 3 01:46:53 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 3 May 2013 01:46:53 +0200 (CEST) Subject: [pypy-commit] pypy py3k: skip on win Message-ID: <20130502234653.B68831C0547@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63810:79ba5da0ab7c Date: 2013-05-02 15:52 -0700 http://bitbucket.org/pypy/pypy/changeset/79ba5da0ab7c/ Log: skip on win diff --git a/pypy/module/thread/test/test_fork.py b/pypy/module/thread/test/test_fork.py --- a/pypy/module/thread/test/test_fork.py +++ b/pypy/module/thread/test/test_fork.py @@ -94,6 +94,9 @@ import os import time + if not hasattr(os, 'fork'): + skip("No fork on this platform") + def fork_with_import_lock(level): release = 0 in_child = False From noreply at buildbot.pypy.org Fri May 3 01:46:55 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 3 May 2013 01:46:55 +0200 (CEST) Subject: [pypy-commit] pypy py3k: special case windows unicode paths Message-ID: <20130502234655.93C641C0547@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63811:0a4ff9405074 Date: 2013-05-02 16:42 -0700 http://bitbucket.org/pypy/pypy/changeset/0a4ff9405074/ Log: special case windows unicode paths diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -15,9 +15,11 @@ from rpython.rlib.streamio import StreamErrors from rpython.rlib.objectmodel import we_are_translated, specialize from rpython.rlib.signature import signature -from rpython.rlib import types +from rpython.rlib import rposix, types from pypy.module.sys.version import PYPY_VERSION +_WIN32 = sys.platform == 'win32' + SEARCH_ERROR = 0 PY_SOURCE = 1 PY_COMPILED = 2 @@ -415,20 +417,30 @@ if space.is_true(w_loader): return w_loader +class _WIN32Path(object): + def __init__(self, path): + self.path = path + + def as_unicode(self): + return self.path class W_NullImporter(W_Root): def __init__(self, space): pass - @unwrap_spec(path='fsencode') - def descr_init(self, space, path): + def descr_init(self, space, w_path): + self._descr_init(space, w_path, _WIN32) + + @specialize.arg(3) + def _descr_init(self, space, w_path, win32): + path = space.unicode0_w(w_path) if win32 else space.fsencode_w(w_path) if not path: raise OperationError(space.w_ImportError, space.wrap( "empty pathname")) # Directory should not exist try: - st = os.stat(path) + st = rposix.stat(_WIN32Path(path) if win32 else path) except OSError: pass else: diff --git a/pypy/module/imp/test/support.py b/pypy/module/imp/test/support.py --- a/pypy/module/imp/test/support.py +++ b/pypy/module/imp/test/support.py @@ -7,7 +7,7 @@ testfn = u'test_tmp' testfn_unencodable = None - if sys.platform == 'nt': + if sys.platform == 'win32': testfn_unencodable = testfn + u"-\u5171\u0141\u2661\u0363\uDC80" elif sys.platform != 'darwin': try: From noreply at buildbot.pypy.org Fri May 3 02:04:43 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 3 May 2013 02:04:43 +0200 (CEST) Subject: [pypy-commit] pypy default: simplify Message-ID: <20130503000443.CFDEE1C304F@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63812:15827dd3d414 Date: 2013-05-02 17:03 -0700 http://bitbucket.org/pypy/pypy/changeset/15827dd3d414/ Log: simplify diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -16,6 +16,8 @@ from rpython.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION +_WIN32 = sys.platform == 'win32' + SEARCH_ERROR = 0 PY_SOURCE = 1 PY_COMPILED = 2 @@ -27,12 +29,8 @@ # PY_CODERESOURCE = 8 IMP_HOOK = 9 -if sys.platform == 'win32': - SO = ".pyd" -else: - SO = ".so" +SO = '.pyd' if _WIN32 else '.so' DEFAULT_SOABI = 'pypy-%d%d' % PYPY_VERSION[:2] -CHECK_FOR_PYW = sys.platform == 'win32' @specialize.memo() def get_so_extension(space): @@ -64,7 +62,7 @@ return PY_SOURCE, ".py", "U" # on Windows, also check for a .pyw file - if CHECK_FOR_PYW: + if _WIN32: pyfile = filepart + ".pyw" if file_exists(pyfile): return PY_SOURCE, ".pyw", "U" From noreply at buildbot.pypy.org Fri May 3 02:04:45 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 3 May 2013 02:04:45 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130503000445.7D0A71C304F@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63813:dbaf0bdc00d4 Date: 2013-05-02 17:04 -0700 http://bitbucket.org/pypy/pypy/changeset/dbaf0bdc00d4/ Log: merge default diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-2.0.rst copy from pypy/doc/whatsnew-head.rst copy to pypy/doc/whatsnew-2.0.rst diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -1,140 +1,8 @@ ====================== -What's new in PyPy 2.0 +What's new in PyPy 2.1 ====================== -.. this is a revision shortly after release-2.0-beta1 -.. startrev: 0e6161a009c6 +.. this is a revision shortly after release-2.0 +.. startrev: a13c07067613 -.. branch: split-rpython -Split rpython and pypy into seperate directories -.. branch: callback-jit -Callbacks from C are now better JITted - -.. branch: fix-jit-logs - -.. branch: remove-globals-in-jit - -.. branch: length-hint -Implement __lenght_hint__ according to PEP 424 - -.. branch: numpypy-longdouble -Long double support for numpypy - -.. branch: numpypy-disable-longdouble -Since r_longdouble support is missing, disable all longdouble and derivative -dtypes using ENABLED_LONG_DOUBLE = False - -.. branch: numpypy-real-as-view -Convert real, imag from ufuncs to views. This involves the beginning of -view() functionality - -.. branch: indexing-by-array -Adds indexing by scalar, adds int conversion from scalar and single element array, -fixes compress, indexing by an array with a smaller shape and the indexed object. - -.. branch: str-dtype-improvement -Allow concatenation of str and numeric arrays - -.. branch: signatures -Improved RPython typing - -.. branch: rpython-bytearray -Rudimentary support for bytearray in RPython - -.. branch: refactor-call_release_gil -Fix a bug which caused cffi to return the wrong result when calling a C -function which calls a Python callback which forces the frames - -.. branch: virtual-raw-mallocs -JIT optimizations which make cffi calls even faster, by removing the need to -allocate a temporary buffer where to store the arguments. - -.. branch: improve-docs-2 -Improve documents and straighten out links - -.. branch: fast-newarray -Inline the fast path of newarray in the assembler. -Disabled on ARM until we fix issues. - -.. branch: reflex-support -Allow dynamic loading of a (Reflex) backend that implements the C-API needed -to provide reflection information - -.. branches we don't care about -.. branch: autoreds -.. branch: kill-faking -.. branch: improved_ebnfparse_error -.. branch: task-decorator -.. branch: fix-e4fa0b2 -.. branch: win32-fixes -.. branch: numpy-unify-methods -.. branch: fix-version-tool -.. branch: popen2-removal -.. branch: pickle-dumps -.. branch: scalar_get_set - -.. branch: release-2.0-beta1 - -.. branch: remove-PYPY_NOT_MAIN_FILE - -.. branch: missing-jit-operations - -.. branch: fix-lookinside-iff-oopspec -Fixed the interaction between two internal tools for controlling the JIT. - -.. branch: inline-virtualref-2 -Better optimized certain types of frame accesses in the JIT, particularly -around exceptions that escape the function they were raised in. - -.. branch: missing-ndarray-attributes -Some missing attributes from ndarrays - -.. branch: cleanup-tests -Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into -one directory for reduced confusion and so they all run nightly. - -.. branch: unquote-faster -.. branch: urlparse-unquote-faster - -.. branch: signal-and-thread -Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a -non-main thread to enable the processing of signal handlers in that thread. - -.. branch: coding-guide-update-rlib-refs -.. branch: rlib-doc-rpython-refs -.. branch: clean-up-remaining-pypy-rlib-refs - -.. branch: enumerate-rstr -Support enumerate() over rstr types. - -.. branch: cleanup-numpypy-namespace -Cleanup _numpypy and numpypy namespaces to more closely resemble numpy. - -.. branch: kill-flowobjspace -Random cleanups to hide FlowObjSpace from public view. - -.. branch: vendor-rename - -.. branch: jitframe-on-heap -Moves optimized JIT frames from stack to heap. As a side effect it enables -stackless to work well with the JIT on PyPy. Also removes a bunch of code from -the GC which fixes cannot find gc roots. - -.. branch: pycon2013-doc-fixes -Documentation fixes after going through the docs at PyCon 2013 sprint. - -.. branch: extregistry-refactor - -.. branch: remove-list-smm -.. branch: bridge-logging -.. branch: curses_cffi -cffi implementation of _curses - -.. branch: sqlite-cffi -cffi implementation of sqlite3 - -.. branch: release-2.0-beta2 -.. branch: unbreak-freebsd - -.. branch: virtualref-virtualizable diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -31,12 +31,8 @@ # PY_CODERESOURCE = 8 IMP_HOOK = 9 -if sys.platform == 'win32': - SO = ".pyd" -else: - SO = ".so" +SO = '.pyd' if _WIN32 else '.so' DEFAULT_SOABI = 'pypy-%d%d' % PYPY_VERSION[:2] -CHECK_FOR_PYW = sys.platform == 'win32' PYC_TAG = 'pypy-%d%d' % PYPY_VERSION[:2] @@ -70,7 +66,7 @@ return PY_SOURCE, ".py", "U" # on Windows, also check for a .pyw file - if CHECK_FOR_PYW: + if _WIN32: pyfile = filepart + ".pyw" if file_exists(pyfile): return PY_SOURCE, ".pyw", "U" diff --git a/rpython/jit/backend/arm/codebuilder.py b/rpython/jit/backend/arm/codebuilder.py --- a/rpython/jit/backend/arm/codebuilder.py +++ b/rpython/jit/backend/arm/codebuilder.py @@ -49,6 +49,70 @@ instr = self._encode_reg_list(cond << 28 | 0x92D << 16, regs) self.write32(instr) + def STM(self, base, regs, write_back=False, cond=cond.AL): + assert len(regs) > 0 + instr = (cond << 28 + | 0x11 << 23 + | (1 if write_back else 0) << 21 + | (base & 0xF) << 16) + instr = self._encode_reg_list(instr, regs) + self.write32(instr) + + def LDM(self, base, regs, write_back=False, cond=cond.AL): + assert len(regs) > 0 + instr = (cond << 28 + | 0x11 << 23 + | (1 if write_back else 0) << 21 + | 1 << 20 + | (base & 0xF) << 16) + instr = self._encode_reg_list(instr, regs) + self.write32(instr) + + def VSTM(self, base, regs, write_back=False, cond=cond.AL): + # encoding T1 + P = 0 + U = 1 + nregs = len(regs) + assert nregs > 0 and nregs <= 16 + freg = regs[0] + D = (freg & 0x10) >> 4 + Dd = (freg & 0xF) + nregs *= 2 + instr = (cond << 28 + | 3 << 26 + | P << 24 + | U << 23 + | D << 22 + | (1 if write_back else 0) << 21 + | (base & 0xF) << 16 + | Dd << 12 + | 0xB << 8 + | nregs) + self.write32(instr) + + def VLDM(self, base, regs, write_back=False, cond=cond.AL): + # encoding T1 + P = 0 + U = 1 + nregs = len(regs) + assert nregs > 0 and nregs <= 16 + freg = regs[0] + D = (freg & 0x10) >> 4 + Dd = (freg & 0xF) + nregs *= 2 + instr = (cond << 28 + | 3 << 26 + | P << 24 + | U << 23 + | D << 22 + | (1 if write_back else 0) << 21 + | 1 << 20 + | (base & 0xF) << 16 + | Dd << 12 + | 0xB << 8 + | nregs) + self.write32(instr) + def VPUSH(self, regs, cond=cond.AL): nregs = len(regs) assert nregs > 0 and nregs <= 16 diff --git a/rpython/jit/backend/arm/test/test_assembler.py b/rpython/jit/backend/arm/test/test_assembler.py --- a/rpython/jit/backend/arm/test/test_assembler.py +++ b/rpython/jit/backend/arm/test/test_assembler.py @@ -6,11 +6,16 @@ from rpython.jit.backend.arm.test.support import run_asm from rpython.jit.backend.detect_cpu import getcpuclass from rpython.jit.metainterp.resoperation import rop +from rpython.jit.codewriter import longlong from rpython.rtyper.annlowlevel import llhelper from rpython.rtyper.lltypesystem import lltype, rffi from rpython.jit.metainterp.history import JitCellToken from rpython.jit.backend.model import CompiledLoopToken +from rpython.rtyper.lltypesystem import lltype, llmemory, rffi +from rpython.rtyper.annlowlevel import llhelper +from rpython.rlib.objectmodel import specialize +from rpython.rlib.debug import ll_assert CPU = getcpuclass() @@ -247,7 +252,91 @@ self.a.mc.ADD_ri(r.sp.value, r.sp.value, 8) self.a.gen_func_epilog() assert run_asm(self.a) == x + + def test_stm(self): + container = lltype.malloc(lltype.Array(lltype.Signed, hints={'nolength': True}), 10, flavor='raw') + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, container)) + for x in range(10): + self.a.mc.gen_load_int(x, x) + self.a.mc.STM(r.ip.value, [x for x in range(10)]) + self.a.gen_func_epilog() + run_asm(self.a) + for x in range(10): + assert container[x] == x + lltype.free(container, flavor='raw') + def test_ldm(self): + container = lltype.malloc(lltype.Array(lltype.Signed, hints={'nolength': True}), 10, flavor='raw') + for x in range(10): + container[x] = x + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, container)) + self.a.mc.LDM(r.ip.value, [x for x in range(10)]) + for x in range(1, 10): + self.a.mc.ADD_rr(0, 0, x) + self.a.gen_func_epilog() + res = run_asm(self.a) + assert res == sum(range(10)) + lltype.free(container, flavor='raw') + + def test_vstm(self): + n = 14 + source_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + target_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + for x in range(n): + source_container[x] = longlong.getfloatstorage(float("%d.%d" % (x,x))) + self.a.gen_func_prolog() + for x in range(n): + self.a.mc.ADD_ri(r.ip.value, r.ip.value, 8) + self.a.mc.VLDR(n, r.ip.value) + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, target_container)) + self.a.mc.VSTM(r.ip.value, [x for x in range(n)]) + self.a.gen_func_epilog() + run_asm(self.a) + for d in range(n): + res = longlong.getrealfloat(target_container[0]) == float("%d.%d" % (d,d)) + lltype.free(source_container, flavor='raw') + lltype.free(target_container, flavor='raw') + + def test_vldm(self): + n = 14 + container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + for x in range(n): + container[x] = longlong.getfloatstorage(float("%d.%d" % (x,x))) + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, container)) + self.a.mc.VLDM(r.ip.value, [x for x in range(n)]) + for x in range(1, n): + self.a.mc.VADD(0, 0, x) + self.a.mc.VSTR(r.d0.value, r.ip.value) + self.a.gen_func_epilog() + res = run_asm(self.a) + assert longlong.getrealfloat(container[0]) == sum([float("%d.%d" % (d,d)) for d in range(n)]) + lltype.free(container, flavor='raw') + + def test_vstm_vldm_combined(self): + n = 14 + source_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + target_container = lltype.malloc(lltype.Array(longlong.FLOATSTORAGE, + hints={'nolength': True}), n, flavor='raw') + for x in range(n): + source_container[x] = longlong.getfloatstorage(float("%d.%d" % (x,x))) + self.a.gen_func_prolog() + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, source_container)) + self.a.mc.VLDM(r.ip.value, [x for x in range(n)]) + self.a.mc.gen_load_int(r.ip.value, rffi.cast(lltype.Signed, target_container)) + self.a.mc.VSTM(r.ip.value, [x for x in range(n)]) + self.a.gen_func_epilog() + run_asm(self.a) + for d in range(n): + res = longlong.getrealfloat(target_container[0]) == float("%d.%d" % (d,d)) + lltype.free(source_container, flavor='raw') + lltype.free(target_container, flavor='raw') def callme(inp): i = inp + 10 diff --git a/rpython/jit/backend/arm/test/test_instr_codebuilder.py b/rpython/jit/backend/arm/test/test_instr_codebuilder.py --- a/rpython/jit/backend/arm/test/test_instr_codebuilder.py +++ b/rpython/jit/backend/arm/test/test_instr_codebuilder.py @@ -139,6 +139,22 @@ def test_push_raises_sp(self): assert py.test.raises(AssertionError, 'self.cb.PUSH([r.sp.value])') + def test_stm(self): + self.cb.STM(r.fp.value, [reg.value for reg in r.caller_resp], cond=conditions.AL) + self.assert_equal('STM fp, {r0, r1, r2, r3}') + + def test_ldm(self): + self.cb.LDM(r.fp.value, [reg.value for reg in r.caller_resp], cond=conditions.AL) + self.assert_equal('LDM fp, {r0, r1, r2, r3}') + + def test_vstm(self): + self.cb.VSTM(r.fp.value, [reg.value for reg in r.caller_vfp_resp], cond=conditions.AL) + self.assert_equal('VSTM fp, {d0, d1, d2, d3, d4, d5, d6, d7}') + + def test_vldm(self): + self.cb.VLDM(r.fp.value, [reg.value for reg in r.caller_vfp_resp], cond=conditions.AL) + self.assert_equal('VLDM fp, {d0, d1, d2, d3, d4, d5, d6, d7}') + def test_pop(self): self.cb.POP([reg.value for reg in r.caller_resp], cond=conditions.AL) self.assert_equal('POP {r0, r1, r2, r3}') diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -1751,7 +1751,7 @@ def rewrite_op_jit_ffi_save_result(self, op): kind = op.args[0].value - assert kind in ('int', 'float') + assert kind in ('int', 'float', 'longlong', 'singlefloat') return SpaceOperation('libffi_save_result_%s' % kind, op.args[1:], None) def rewrite_op_jit_force_virtual(self, op): diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -1351,24 +1351,39 @@ def bhimpl_ll_read_timestamp(): return read_timestamp() - @arguments("cpu", "i", "i", "i") - def bhimpl_libffi_save_result_int(self, cif_description, exchange_buffer, result): - ARRAY = lltype.Ptr(rffi.CArray(lltype.Signed)) - cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) - exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP) + def _libffi_save_result(self, cif_description, exchange_buffer, result): + ARRAY = lltype.Ptr(rffi.CArray(lltype.typeOf(result))) + cast_int_to_ptr = self.cpu.cast_int_to_ptr + cif_description = cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) + exchange_buffer = cast_int_to_ptr(exchange_buffer, rffi.CCHARP) # data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result) rffi.cast(ARRAY, data_out)[0] = result + _libffi_save_result._annspecialcase_ = 'specialize:argtype(3)' - @arguments("cpu", "i", "i", "f") - def bhimpl_libffi_save_result_float(self, cif_description, exchange_buffer, result): + @arguments("self", "i", "i", "i") + def bhimpl_libffi_save_result_int(self, cif_description, + exchange_buffer, result): + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "f") + def bhimpl_libffi_save_result_float(self, cif_description, + exchange_buffer, result): result = longlong.getrealfloat(result) - ARRAY = lltype.Ptr(rffi.CArray(lltype.Float)) - cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) - exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP) - # - data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result) - rffi.cast(ARRAY, data_out)[0] = result + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "f") + def bhimpl_libffi_save_result_longlong(self, cif_description, + exchange_buffer, result): + # 32-bit only: 'result' is here a LongLong + assert longlong.is_longlong(lltype.typeOf(result)) + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "i") + def bhimpl_libffi_save_result_singlefloat(self, cif_description, + exchange_buffer, result): + result = longlong.int2singlefloat(result) + self._libffi_save_result(cif_description, exchange_buffer, result) # ---------- diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1190,8 +1190,8 @@ return self.metainterp.execute_and_record(rop.READ_TIMESTAMP, None) @arguments("box", "box", "box") - def opimpl_libffi_save_result_int(self, box_cif_description, box_exchange_buffer, - box_result): + def _opimpl_libffi_save_result(self, box_cif_description, + box_exchange_buffer, box_result): from rpython.rtyper.lltypesystem import llmemory from rpython.rlib.jit_libffi import CIF_DESCRIPTION_P from rpython.jit.backend.llsupport.ffisupport import get_arg_descr @@ -1208,10 +1208,14 @@ assert ofs % itemsize == 0 # alignment check (result) self.metainterp.history.record(rop.SETARRAYITEM_RAW, [box_exchange_buffer, - ConstInt(ofs // itemsize), box_result], + ConstInt(ofs // itemsize), + box_result], None, descr) - opimpl_libffi_save_result_float = opimpl_libffi_save_result_int + opimpl_libffi_save_result_int = _opimpl_libffi_save_result + opimpl_libffi_save_result_float = _opimpl_libffi_save_result + opimpl_libffi_save_result_longlong = _opimpl_libffi_save_result + opimpl_libffi_save_result_singlefloat = _opimpl_libffi_save_result # ------------------------------ diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -14,7 +14,10 @@ def _get_jitcodes(testself, CPUClass, func, values, type_system, - supports_longlong=False, translationoptions={}, **kwds): + supports_floats=True, + supports_longlong=False, + supports_singlefloats=False, + translationoptions={}, **kwds): from rpython.jit.codewriter import support class FakeJitCell(object): @@ -67,9 +70,16 @@ cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()]) cw.debug = True testself.cw = cw + if supports_floats and not cpu.supports_floats: + py.test.skip("this test requires supports_floats=True") + if supports_longlong and not cpu.supports_longlong: + py.test.skip("this test requires supports_longlong=True") + if supports_singlefloats and not cpu.supports_singlefloats: + py.test.skip("this test requires supports_singlefloats=True") policy = JitPolicy() - policy.set_supports_floats(True) + policy.set_supports_floats(supports_floats) policy.set_supports_longlong(supports_longlong) + policy.set_supports_singlefloats(supports_singlefloats) graphs = cw.find_all_graphs(policy) if kwds.get("backendopt"): backend_optimizations(rtyper.annotator.translator, graphs=graphs) diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -5,13 +5,13 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.annlowlevel import llhelper from rpython.jit.metainterp.test.support import LLJitMixin -from rpython.jit.codewriter.longlong import is_longlong +from rpython.jit.codewriter.longlong import is_longlong, is_64_bit from rpython.rlib import jit from rpython.rlib import jit_libffi from rpython.rlib.jit_libffi import (types, CIF_DESCRIPTION, FFI_TYPE_PP, jit_ffi_call, jit_ffi_save_result) from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.rarithmetic import intmask, r_longlong +from rpython.rlib.rarithmetic import intmask, r_longlong, r_singlefloat from rpython.rlib.longlong2float import float2longlong def get_description(atypes, rtype): @@ -45,7 +45,12 @@ class FfiCallTests(object): - def _run(self, atypes, rtype, avalues, rvalue, expected_call_release_gil=1): + def _run(self, atypes, rtype, avalues, rvalue, + expected_call_release_gil=1, + supports_floats=True, + supports_longlong=True, + supports_singlefloats=True): + cif_description = get_description(atypes, rtype) def verify(*args): @@ -67,7 +72,11 @@ for avalue in unroll_avalues: TYPE = rffi.CArray(lltype.typeOf(avalue)) data = rffi.ptradd(exchange_buffer, ofs) - assert rffi.cast(lltype.Ptr(TYPE), data)[0] == avalue + got = rffi.cast(lltype.Ptr(TYPE), data)[0] + if lltype.typeOf(avalue) is lltype.SingleFloat: + got = float(got) + avalue = float(avalue) + assert got == avalue ofs += 16 if rvalue is not None: write_rvalue = rvalue @@ -96,17 +105,30 @@ data = rffi.ptradd(exbuf, ofs) res = rffi.cast(lltype.Ptr(TYPE), data)[0] lltype.free(exbuf, flavor='raw') + if lltype.typeOf(res) is lltype.SingleFloat: + res = float(res) return res + def matching_result(res, rvalue): + if rvalue is None: + return res == 654321 + if isinstance(rvalue, r_singlefloat): + rvalue = float(rvalue) + return res == rvalue + with FakeFFI(fake_call_impl_any): res = f() - assert res == rvalue or (res, rvalue) == (654321, None) - res = self.interp_operations(f, []) + assert matching_result(res, rvalue) + res = self.interp_operations(f, [], + supports_floats = supports_floats, + supports_longlong = supports_longlong, + supports_singlefloats = supports_singlefloats) if is_longlong(FUNC.RESULT): - # longlongs are passed around as floats inside the JIT, we - # need to convert it back before checking the value + # longlongs are returned as floats, but that's just + # an inconvenience of interp_operations(). Normally both + # longlong and floats are passed around as longlongs. res = float2longlong(res) - assert res == rvalue or (res, rvalue) == (654321, None) + assert matching_result(res, rvalue) self.check_operations_history(call_may_force=0, call_release_gil=expected_call_release_gil) @@ -119,14 +141,24 @@ [-123456*j for j in range(i)], -42434445) - def test_simple_call_float(self): - self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2) + def test_simple_call_float(self, **kwds): + self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2, **kwds) - def test_simple_call_longlong(self): + def test_simple_call_longlong(self, **kwds): maxint32 = 2147483647 a = r_longlong(maxint32) + 1 b = r_longlong(maxint32) + 2 - self._run([types.slonglong] * 2, types.slonglong, [a, b], a) + self._run([types.slonglong] * 2, types.slonglong, [a, b], a, **kwds) + + def test_simple_call_singlefloat_args(self): + self._run([types.float] * 2, types.double, + [r_singlefloat(10.5), r_singlefloat(31.5)], + -4.5) + + def test_simple_call_singlefloat(self, **kwds): + self._run([types.float] * 2, types.float, + [r_singlefloat(10.5), r_singlefloat(31.5)], + r_singlefloat(-4.5), **kwds) def test_simple_call_longdouble(self): # longdouble is not supported, so we expect NOT to generate a call_release_gil @@ -266,3 +298,20 @@ assert res == math.sin(1.23) lltype.free(atypes, flavor='raw') + + def test_simple_call_float_unsupported(self): + self.test_simple_call_float(supports_floats=False, + expected_call_release_gil=0) + + def test_simple_call_longlong_unsupported(self): + self.test_simple_call_longlong(supports_longlong=False, + expected_call_release_gil=is_64_bit) + + def test_simple_call_singlefloat_unsupported(self): + self.test_simple_call_singlefloat(supports_singlefloats=False, + expected_call_release_gil=0) + + def test_simple_call_float_even_if_other_unsupported(self): + self.test_simple_call_float(supports_longlong=False, + supports_singlefloats=False) + # this is the default: expected_call_release_gil=1 diff --git a/rpython/rlib/jit_libffi.py b/rpython/rlib/jit_libffi.py --- a/rpython/rlib/jit_libffi.py +++ b/rpython/rlib/jit_libffi.py @@ -2,6 +2,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.rlib import clibffi, jit +from rpython.rlib.rarithmetic import r_longlong, r_singlefloat from rpython.rlib.nonconst import NonConstant @@ -107,12 +108,14 @@ reskind = types.getkind(cif_description.rtype) if reskind == 'v': jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer) - elif reskind == 'f' or reskind == 'L': # L is for longlongs, on 32bit - result = jit_ffi_call_impl_float(cif_description, func_addr, exchange_buffer) - jit_ffi_save_result('float', cif_description, exchange_buffer, result) elif reskind == 'i' or reskind == 'u': - result = jit_ffi_call_impl_int(cif_description, func_addr, exchange_buffer) - jit_ffi_save_result('int', cif_description, exchange_buffer, result) + _do_ffi_call_int(cif_description, func_addr, exchange_buffer) + elif reskind == 'f': + _do_ffi_call_float(cif_description, func_addr, exchange_buffer) + elif reskind == 'L': # L is for longlongs, on 32bit + _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer) + elif reskind == 'S': # SingleFloat + _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer) else: # the result kind is not supported: we disable the jit_ffi_call # optimization by calling directly jit_ffi_call_impl_any, so the JIT @@ -123,6 +126,30 @@ jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) +def _do_ffi_call_int(cif_description, func_addr, exchange_buffer): + result = jit_ffi_call_impl_int(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('int', cif_description, exchange_buffer, result) + +def _do_ffi_call_float(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support floats + result = jit_ffi_call_impl_float(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('float', cif_description, exchange_buffer, result) + +def _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support longlongs + result = jit_ffi_call_impl_longlong(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('longlong', cif_description, exchange_buffer, result) + +def _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support singlefloats + result = jit_ffi_call_impl_singlefloat(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('singlefloat', cif_description, exchange_buffer,result) + + # we must return a NonConstant else we get the constant -1 as the result of # the flowgraph, and the codewriter does not produce a box for the # result. Note that when not-jitted, the result is unused, but when jitted the @@ -139,6 +166,16 @@ return NonConstant(-1.0) @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") +def jit_ffi_call_impl_longlong(cif_description, func_addr, exchange_buffer): + jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) + return r_longlong(-1) + + at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") +def jit_ffi_call_impl_singlefloat(cif_description, func_addr, exchange_buffer): + jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) + return r_singlefloat(-1.0) + + at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") def jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer): jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) return None @@ -175,7 +212,7 @@ def compute_result_annotation(self, kind_s, *args_s): from rpython.annotator import model as annmodel assert isinstance(kind_s, annmodel.SomeString) - assert kind_s.const in ('int', 'float') + assert kind_s.const in ('int', 'float', 'longlong', 'singlefloat') def specialize_call(self, hop): hop.exception_cannot_occur() From noreply at buildbot.pypy.org Fri May 3 08:08:13 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 3 May 2013 08:08:13 +0200 (CEST) Subject: [pypy-commit] pypy default: iport test_fficall for arm Message-ID: <20130503060813.E58951C0328@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63814:3f193dc2e188 Date: 2013-05-03 08:07 +0200 http://bitbucket.org/pypy/pypy/changeset/3f193dc2e188/ Log: iport test_fficall for arm diff --git a/rpython/jit/backend/arm/test/test_fficall.py b/rpython/jit/backend/arm/test/test_fficall.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/test/test_fficall.py @@ -0,0 +1,23 @@ +import py +from rpython.jit.metainterp.test import test_fficall +from rpython.jit.backend.arm.test.support import JitARMMixin + +class TestFfiCall(JitARMMixin, test_fficall.FfiCallTests): + # for the individual tests see + # ====> ../../../metainterp/test/test_fficall.py + + def _add_libffi_types_to_ll2types_maybe(self): + # this is needed by test_guard_not_forced_fails, because it produces a + # loop which reads the value of types.* in a variable, then a guard + # fail and we switch to blackhole: the problem is that at this point + # the blackhole interp has a real integer, but it needs to convert it + # back to a lltype pointer (which is handled by ll2ctypes, deeply in + # the logic). The workaround is to teach ll2ctypes in advance which + # are the addresses of the various types.* structures. + # Try to comment this code out and run the test to see how it fails :) + from rpython.rtyper.lltypesystem import rffi, lltype, ll2ctypes + from rpython.rlib.jit_libffi import types + for key, value in types.__dict__.iteritems(): + if isinstance(value, lltype._ptr): + addr = rffi.cast(lltype.Signed, value) + ll2ctypes._int2obj[addr] = value From noreply at buildbot.pypy.org Fri May 3 11:24:20 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 3 May 2013 11:24:20 +0200 (CEST) Subject: [pypy-commit] pypy default: Release announcement Message-ID: <20130503092420.5E3CE1C0328@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63815:73c218764043 Date: 2013-05-03 11:23 +0200 http://bitbucket.org/pypy/pypy/changeset/73c218764043/ Log: Release announcement diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.0.rst @@ -0,0 +1,56 @@ +============================ +PyPy 2.0 - Einstein Sandwich +============================ + +We're pleased to announce PyPy 2.0. This is a stable release that brings +swath of bugfixes, small performance improvements and compatibility fixes. + +You can download the PyPy 2.0 release here: + + http://pypy.org/download.html + +Two biggest changes since PyPy 1.9 are: + +* stackless is now supported including greenlets, which means eventlet + and gevent should work (but read below about gevent) + +* PyPy now contains a release 0.6 of `cffi`_ as a builtin module, which + is preferred way of calling C from Python that works well on PyPy + +.. _`cffi`: http://cffi.readthedocs.org + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Windows 64 work is still stalling, we would welcome a volunteer +to handle that. ARM support is on the way and we're expecting to release +an alpha ARM version shortly. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +* Stackless including greenlets should work. For gevent, you need to check + out `pypycore`_ and use `pypy-hacks`_ branch of gevent. + +* cffi is not a module included with PyPy. It's a preferred way of calling + C from Python that works on PyPy. + +* Callbacks from C are now JITted, which means XML parsing is much faster + +* A lot of speed improvements in various language corners, most of them small, + but speeding up a particular corner a lot + +* A lot of stability issues fixed + +.. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ +.. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks + +Cheers, +fijal, arigo and the PyPy team 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 @@ -5,4 +5,3 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 - From noreply at buildbot.pypy.org Fri May 3 11:29:52 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 3 May 2013 11:29:52 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Release announcement Message-ID: <20130503092952.C7C321C13BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: release-2.0.x Changeset: r63816:8c3f07eb25d0 Date: 2013-05-03 11:23 +0200 http://bitbucket.org/pypy/pypy/changeset/8c3f07eb25d0/ Log: Release announcement diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.0.rst @@ -0,0 +1,56 @@ +============================ +PyPy 2.0 - Einstein Sandwich +============================ + +We're pleased to announce PyPy 2.0. This is a stable release that brings +swath of bugfixes, small performance improvements and compatibility fixes. + +You can download the PyPy 2.0 release here: + + http://pypy.org/download.html + +Two biggest changes since PyPy 1.9 are: + +* stackless is now supported including greenlets, which means eventlet + and gevent should work (but read below about gevent) + +* PyPy now contains a release 0.6 of `cffi`_ as a builtin module, which + is preferred way of calling C from Python that works well on PyPy + +.. _`cffi`: http://cffi.readthedocs.org + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Windows 64 work is still stalling, we would welcome a volunteer +to handle that. ARM support is on the way and we're expecting to release +an alpha ARM version shortly. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +* Stackless including greenlets should work. For gevent, you need to check + out `pypycore`_ and use `pypy-hacks`_ branch of gevent. + +* cffi is not a module included with PyPy. It's a preferred way of calling + C from Python that works on PyPy. + +* Callbacks from C are now JITted, which means XML parsing is much faster + +* A lot of speed improvements in various language corners, most of them small, + but speeding up a particular corner a lot + +* A lot of stability issues fixed + +.. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ +.. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks + +Cheers, +fijal, arigo and the PyPy team 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 @@ -5,4 +5,3 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 - From noreply at buildbot.pypy.org Fri May 3 11:44:20 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 3 May 2013 11:44:20 +0200 (CEST) Subject: [pypy-commit] pypy default: Small additions and typos. Message-ID: <20130503094420.178B81C13E5@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63817:d1d797def730 Date: 2013-05-03 11:43 +0200 http://bitbucket.org/pypy/pypy/changeset/d1d797def730/ Log: Small additions and typos. diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -3,18 +3,18 @@ ============================ We're pleased to announce PyPy 2.0. This is a stable release that brings -swath of bugfixes, small performance improvements and compatibility fixes. +a swath of bugfixes, small performance improvements and compatibility fixes. You can download the PyPy 2.0 release here: http://pypy.org/download.html -Two biggest changes since PyPy 1.9 are: +The two biggest changes since PyPy 1.9 are: * stackless is now supported including greenlets, which means eventlet and gevent should work (but read below about gevent) -* PyPy now contains a release 0.6 of `cffi`_ as a builtin module, which +* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which is preferred way of calling C from Python that works well on PyPy .. _`cffi`: http://cffi.readthedocs.org @@ -37,17 +37,22 @@ ========== * Stackless including greenlets should work. For gevent, you need to check - out `pypycore`_ and use `pypy-hacks`_ branch of gevent. + out `pypycore`_ and use the `pypy-hacks`_ branch of gevent. -* cffi is not a module included with PyPy. It's a preferred way of calling - C from Python that works on PyPy. +* cffi is now a module included with PyPy. (`cffi`_ also exists for + CPython; the two versions should be fully compatible.) It is the + preferred way of calling C from Python that works on PyPy. -* Callbacks from C are now JITted, which means XML parsing is much faster +* Callbacks from C are now JITted, which means XML parsing is much faster. * A lot of speed improvements in various language corners, most of them small, - but speeding up a particular corner a lot + but speeding up some particular corners a lot. -* A lot of stability issues fixed +* The JIT was refactored to emit machine code which manipulates a "frame" + that lives on the heap rather than on the stack. This is what makes + Stackless work, and it could bring another future speed-up (not done yet). + +* A lot of stability issues fixed. .. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ .. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks From noreply at buildbot.pypy.org Fri May 3 13:38:18 2013 From: noreply at buildbot.pypy.org (timfel) Date: Fri, 3 May 2013 13:38:18 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fix benchmark script for stackvm Message-ID: <20130503113818.AD3871C0135@cobra.cs.uni-duesseldorf.de> Author: Tim Felgentreff Branch: Changeset: r364:8d2fabd0a163 Date: 2013-05-03 13:25 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/8d2fabd0a163/ Log: fix benchmark script for stackvm diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -202,7 +202,7 @@ callback=(lambda x: subprocess.Popen(["mv", "Squeak-4.10.2.2614-linux_i386", "stackvm"]).wait()) ) ], - arguments=['-vm-display-X11', '-headless', "images/%s.image" % SqueakImage, '../benchmarks.st'], + arguments=['-vm-display-null', "images/%s.image" % SqueakImage, '../benchmarks.st'], commitid=cogid ) RSqueakVM = Project( From noreply at buildbot.pypy.org Fri May 3 13:38:19 2013 From: noreply at buildbot.pypy.org (timfel) Date: Fri, 3 May 2013 13:38:19 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: add nojit vm, rename targetimageloadingsmalltalk(-nojit)-c to rsqueakvm(-nojit) Message-ID: <20130503113819.C28741C0135@cobra.cs.uni-duesseldorf.de> Author: Tim Felgentreff Branch: Changeset: r365:31e9905ba200 Date: 2013-05-03 13:34 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/31e9905ba200/ Log: add nojit vm, rename targetimageloadingsmalltalk(-nojit)-c to rsqueakvm(-nojit) diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -208,7 +208,8 @@ RSqueakVM = Project( "lang-smalltalk", executables=[ - Executable("targetimageloadingsmalltalk-c", "./targetimageloadingsmalltalk-c") + Executable("rsqueakvm", "./targetimageloadingsmalltalk-c"), + Executable("rsqueakvm-nojit", "./targetimageloadingsmalltalk-nojit-c") ], arguments=["images/%s.image" % SqueakImage, '-m', 'runSPyBenchmarks'] ) From noreply at buildbot.pypy.org Fri May 3 13:38:21 2013 From: noreply at buildbot.pypy.org (timfel) Date: Fri, 3 May 2013 13:38:21 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: merge default Message-ID: <20130503113821.0C1041C0135@cobra.cs.uni-duesseldorf.de> Author: Tim Felgentreff Branch: Changeset: r366:daca802d08e8 Date: 2013-05-03 13:36 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/daca802d08e8/ Log: merge default diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -30,13 +30,19 @@ benchmarks = output.split('\n') for s in benchmarks: if ';' in s: - name, time = s.split(';') - self.add(executable, name, time) + results = s.split(';') + if len(results) == 2: + self.add(executable, *results) + elif len(results) == 4: + self.add(executble, *results) - def add(self, executable, benchmark, result): + def add(self, executable, benchmark, result, min=None, max=None): print "Saving result %s for executable %s, benchmark %s" % ( result, executable, benchmark) - data = self.build_data(executable, benchmark, result) + if min is max is None: + data = self.build_data(executable, benchmark, result) + else: + data = self.build_extended_data(executable, benchmark, result, min, max) params = urllib.urlencode(data) response = "None" print "Saving result for executable %s, revision %s, benchmark %s" % ( @@ -89,7 +95,13 @@ # 'max': 4001.6, # Optional. Default is blank # 'min': 3995.1, # Optional. Default is blank # } - + def build_data_extended(self, executable, benchmark, result, min, max): + return dict(self.build_data(executable, benchmark, result), + **{ + 'min': str(min), + 'max': str(max) + } + ) class Archive(object): def __init__(self, filename, target, func): From noreply at buildbot.pypy.org Fri May 3 14:08:23 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 3 May 2013 14:08:23 +0200 (CEST) Subject: [pypy-commit] pypy default: shuffle self.finished_helpers - finalizers can be still discovered during Message-ID: <20130503120823.02F491C1401@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63818:61f249b5cc08 Date: 2013-05-03 14:07 +0200 http://bitbucket.org/pypy/pypy/changeset/61f249b5cc08/ Log: shuffle self.finished_helpers - finalizers can be still discovered during finish_rtype diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py --- a/rpython/memory/gctransform/transform.py +++ b/rpython/memory/gctransform/transform.py @@ -281,11 +281,11 @@ def finish_helpers(self, backendopt=True): if self.translator is not None: self.mixlevelannotator.finish_annotate() - self.finished_helpers = True if self.translator is not None: self.mixlevelannotator.finish_rtype() if backendopt: self.mixlevelannotator.backend_optimize() + self.finished_helpers = True # Make sure that the database also sees all finalizers now. # It is likely that the finalizers need special support there newgcdependencies = self.ll_finalizers_ptrs From noreply at buildbot.pypy.org Fri May 3 14:08:24 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 3 May 2013 14:08:24 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130503120824.3F54D1C1401@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63819:c16cd00e82ef Date: 2013-05-03 14:07 +0200 http://bitbucket.org/pypy/pypy/changeset/c16cd00e82ef/ Log: merge diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -3,18 +3,18 @@ ============================ We're pleased to announce PyPy 2.0. This is a stable release that brings -swath of bugfixes, small performance improvements and compatibility fixes. +a swath of bugfixes, small performance improvements and compatibility fixes. You can download the PyPy 2.0 release here: http://pypy.org/download.html -Two biggest changes since PyPy 1.9 are: +The two biggest changes since PyPy 1.9 are: * stackless is now supported including greenlets, which means eventlet and gevent should work (but read below about gevent) -* PyPy now contains a release 0.6 of `cffi`_ as a builtin module, which +* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which is preferred way of calling C from Python that works well on PyPy .. _`cffi`: http://cffi.readthedocs.org @@ -37,17 +37,22 @@ ========== * Stackless including greenlets should work. For gevent, you need to check - out `pypycore`_ and use `pypy-hacks`_ branch of gevent. + out `pypycore`_ and use the `pypy-hacks`_ branch of gevent. -* cffi is not a module included with PyPy. It's a preferred way of calling - C from Python that works on PyPy. +* cffi is now a module included with PyPy. (`cffi`_ also exists for + CPython; the two versions should be fully compatible.) It is the + preferred way of calling C from Python that works on PyPy. -* Callbacks from C are now JITted, which means XML parsing is much faster +* Callbacks from C are now JITted, which means XML parsing is much faster. * A lot of speed improvements in various language corners, most of them small, - but speeding up a particular corner a lot + but speeding up some particular corners a lot. -* A lot of stability issues fixed +* The JIT was refactored to emit machine code which manipulates a "frame" + that lives on the heap rather than on the stack. This is what makes + Stackless work, and it could bring another future speed-up (not done yet). + +* A lot of stability issues fixed. .. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ .. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks From noreply at buildbot.pypy.org Fri May 3 14:53:25 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 3 May 2013 14:53:25 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: factored out padding from the different tracing code points Message-ID: <20130503125325.3A5131C02DA@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r367:dd37b2932749 Date: 2013-05-03 09:18 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/dd37b2932749/ Log: factored out padding from the different tracing code points diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -184,7 +184,8 @@ # We do not support external semaphores. # In cog, the method to add such a semaphore is only called in GC. - + def padding(self, symbol=' '): + return symbol * (self.max_stack_depth - self.remaining_stack_depth) class ReturnFromTopLevel(Exception): def __init__(self, object): @@ -373,8 +374,7 @@ # ###################################################################### if interp.trace: - padding = ' ' * (interp.max_stack_depth - interp.remaining_stack_depth) - print padding + s_frame.short_str(argcount) + print interp.padding() + s_frame.short_str(argcount) return interp.stack_frame(s_frame) @@ -397,8 +397,7 @@ # ###################################################################### if interp.trace: - padding = '#' * (interp.max_stack_depth - interp.remaining_stack_depth) - print '%s%s missing: #%s' % (padding, s_frame.short_str(0), w_selector.as_string()) + print '%s%s missing: #%s' % (interp.padding('#'), s_frame.short_str(0), w_selector.as_string()) if not objectmodel.we_are_translated(): import pdb; pdb.set_trace() @@ -411,6 +410,8 @@ # unfortunately, the assert below is not true for some tests # assert self._stack_ptr == self.tempsize() + if interp.trace: + print '%sreturning %s' % (interp.padding(), return_value.as_repr_string()) raise Return(return_value, s_return_to) def returnReceiver(self, interp, current_bytecode): From noreply at buildbot.pypy.org Fri May 3 14:53:26 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 3 May 2013 14:53:26 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: ensuring that our artificial benchmark-process is valid in newer Squeak versions Message-ID: <20130503125326.57D8E1C02DA@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r368:d058cc407ad5 Date: 2013-05-03 14:32 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/d058cc407ad5/ Log: ensuring that our artificial benchmark-process is valid in newer Squeak versions diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -33,6 +33,8 @@ # third variable is priority priority = space.unwrap_int(w_hpp.fetch(space, 2)) / 2 + 1 + # Priorities below 10 are not allowed in newer versions of Squeak. + priority = max(10, priority) w_benchmark_proc.store(space, 2, space.wrap_int(priority)) # make process eligible for scheduling From noreply at buildbot.pypy.org Fri May 3 14:53:37 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 3 May 2013 14:53:37 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added vm-debugging squeak package to filetree Message-ID: <20130503125337.26FCC1C02DA@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r369:bb5e33b5350a Date: 2013-05-03 14:47 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/bb5e33b5350a/ Log: added vm-debugging squeak package to filetree added another of the shootout-tests to the test-suite updated the image accordingly diff too long, truncating to 2000 out of 79913 lines diff --git a/SPy-Benchmarks.package/SPyRunner.class/class/runShootout.st b/SPy-Benchmarks.package/SPyRunner.class/class/runShootout.st --- a/SPy-Benchmarks.package/SPyRunner.class/class/runShootout.st +++ b/SPy-Benchmarks.package/SPyRunner.class/class/runShootout.st @@ -6,8 +6,8 @@ times := Dictionary new. { [ShootoutTests nbody: 200000 "20000000" to: stream]. [ShootoutTests binarytrees: 17 to: stream]. - "[ShootoutTests chameneosredux: 2600000 to: stream]. - [ShootoutTests threadring: 100000000 to: stream]" } do: + "[ShootoutTests chameneosredux: 2600000 to: stream]." + [ShootoutTests threadring: 100000000 to: stream] } do: [:block | | benchmark t | benchmark := (ShootoutTests selectorForSimpleBlock: block) copyUpTo: $:. "Smalltalk garbageCollect." diff --git a/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json b/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json --- a/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json +++ b/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json @@ -2,7 +2,7 @@ "class" : { "format:" : "lw 4/29/2013 17:13", "run" : "lw 4/29/2013 17:51", - "runShootout" : "lw 4/29/2013 18:05", + "runShootout" : "lw 5/3/2013 14:43", "runTinyBenchmarks" : "lw 4/29/2013 17:39" }, "instance" : { } } diff --git a/SPy-Benchmarks.package/monticello.meta/version b/SPy-Benchmarks.package/monticello.meta/version --- a/SPy-Benchmarks.package/monticello.meta/version +++ b/SPy-Benchmarks.package/monticello.meta/version @@ -1,1 +1,1 @@ -(name 'SPy-Benchmarks-lw.4' message 'changed the test running and collecting to work with the current spy vm removed two of the shootout tests due to failure on spy' id '9d1c1e0a-0209-45d3-8e0a-220919ab5701' date '29 April 2013' time '6:07:26.686 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.3' message 'added tiny benchmarks' id 'c8214449-4009-4a64-8284-3c58395fe2bc' date '29 April 2013' time '2:15:43.242 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.2' message 'second try for an initial commit with shootout tests' id 'e538d5dc-ff13-4753-a166-bb95af0c7e0b' date '29 April 2013' time '1:41:50.098 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.1' message 'initial commit with existing Shootout tests' id '67ba6a6a-5476-4dc0-892f-de76933491e8' date '29 April 2013' time '1:40:20.34 pm' author 'lw' ancestors () stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ()) \ No newline at end of file +(name 'SPy-Benchmarks-lw.5' message 'added another benchmark' id 'cfe2797f-9dd9-4073-aa6e-86cda0ba3dbf' date '3 May 2013' time '2:43:39.36 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.4' message 'changed the test running and collecting to work with the current spy vm removed two of the shootout tests due to failure on spy' id '9d1c1e0a-0209-45d3-8e0a-220919ab5701' date '29 April 2013' time '6:07:26.686 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.3' message 'added tiny benchmarks' id 'c8214449-4009-4a64-8284-3c58395fe2bc' date '29 April 2013' time '2:15:43.242 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.2' message 'second try for an initial commit with shootout tests' id 'e538d5dc-ff13-4753-a166-bb95af0c7e0b' date '29 April 2013' time '1:41:50.098 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.1' message 'initial commit with existing Shootout tests' id '67ba6a6a-5476-4dc0-892f-de76933491e8' date '29 April 2013' time '1:40:20.34 pm' author 'lw' ancestors () stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ()) \ No newline at end of file diff --git a/SPy-Debugging.package/.filetree b/SPy-Debugging.package/.filetree new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/.filetree @@ -0,0 +1,4 @@ +{ + "noMethodMetaData" : true, + "separateMethodMetaAndSource" : false, + "useCypressPropertiesFile" : true } diff --git a/SPy-Debugging.package/SPyVM.class/README.md b/SPy-Debugging.package/SPyVM.class/README.md new file mode 100644 diff --git a/SPy-Debugging.package/SPyVM.class/class/halt.st b/SPy-Debugging.package/SPyVM.class/class/halt.st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/class/halt.st @@ -0,0 +1,3 @@ +as yet unclassified +halt + \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/class/trace.st b/SPy-Debugging.package/SPyVM.class/class/trace.st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/class/trace.st @@ -0,0 +1,3 @@ +as yet unclassified +trace + \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/class/untrace.st b/SPy-Debugging.package/SPyVM.class/class/untrace.st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/class/untrace.st @@ -0,0 +1,3 @@ +as yet unclassified +untrace + \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/methodProperties.json b/SPy-Debugging.package/SPyVM.class/methodProperties.json new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/methodProperties.json @@ -0,0 +1,7 @@ +{ + "class" : { + "halt" : "lw 4/30/2013 12:44", + "trace" : "lw 4/30/2013 12:44", + "untrace" : "lw 4/30/2013 12:44" }, + "instance" : { + } } diff --git a/SPy-Debugging.package/SPyVM.class/properties.json b/SPy-Debugging.package/SPyVM.class/properties.json new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/properties.json @@ -0,0 +1,14 @@ +{ + "category" : "SPy-Debugging", + "classinstvars" : [ + ], + "classvars" : [ + ], + "commentStamp" : "", + "instvars" : [ + ], + "name" : "SPyVM", + "pools" : [ + ], + "super" : "Object", + "type" : "normal" } diff --git a/SPy-Debugging.package/monticello.meta/categories.st b/SPy-Debugging.package/monticello.meta/categories.st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/monticello.meta/categories.st @@ -0,0 +1,1 @@ +SystemOrganization addCategory: #'SPy-Debugging'! diff --git a/SPy-Debugging.package/monticello.meta/initializers.st b/SPy-Debugging.package/monticello.meta/initializers.st new file mode 100644 diff --git a/SPy-Debugging.package/monticello.meta/package b/SPy-Debugging.package/monticello.meta/package new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/monticello.meta/package @@ -0,0 +1,1 @@ +(name 'SPy-Debugging') \ No newline at end of file diff --git a/SPy-Debugging.package/monticello.meta/version b/SPy-Debugging.package/monticello.meta/version new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/monticello.meta/version @@ -0,0 +1,1 @@ +(name 'SPy-Debugging-lw.1' message 'added class for starting vm-tracing, etc.' id 'e6eeab78-6e5c-43bf-9dbc-dfdad29756bd' date '30 April 2013' time '3:54:48.262 pm' author 'lw' ancestors () stepChildren ()) \ No newline at end of file diff --git a/SPy-Debugging.package/properties.json b/SPy-Debugging.package/properties.json new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/properties.json @@ -0,0 +1,2 @@ +{ + } diff --git a/images/Squeak4.5-12568.changes b/images/Squeak4.5-12568.changes --- a/images/Squeak4.5-12568.changes +++ b/images/Squeak4.5-12568.changes @@ -36,4 +36,4 @@ Workspace allInstances do: [:w | w topView delete]. ReleaseBuilderFor4dot4 prepareNewBuild. Smalltalk snapshot: true andQuit: true. -! ----End fileIn of a stream----! ----SNAPSHOT----{31 March 2013 . 3:27:34 pm} Squeak4.5-12327.image priorSource: 7430688! !Installer methodsFor: 'squeakmap' stamp: 'fbs 1/28/2013 19:25' prior: 57597950! packageAndVersionFrom: pkg | p | p := ReadStream on: pkg . ^{(p upTo: $(). p upTo: $)} collect: [:s | s withBlanksTrimmed].! ! "Installer-Core"! !Categorizer methodsFor: 'fileIn/Out' stamp: 'cwp 6/20/2012 16:58'! scanFrom: aStream environment: anEnvironment ^ self scanFrom: aStream! ! !ClassCategoryReader methodsFor: 'fileIn/Out' stamp: 'cwp 6/20/2012 17:21'! scanFrom: aStream environment: anEnvironment "File in methods from the stream, aStream." | methodText | [methodText := aStream nextChunkText. methodText size > 0] whileTrue: [class compile: methodText environment: anEnvironment classified: category withStamp: changeStamp notifying: nil]! ! !ClassCommentReader methodsFor: 'as yet unclassified' stamp: 'cwp 6/20/2012 17:22'! scanFrom: aStream environment: anEnvironment ^ self scanFrom: aStream! ! !Metaclass methodsFor: 'compiling' stamp: 'cwp 6/20/2012 17:29'! bindingOf: varName environment: anEnvironment ^ thisClass classBindingOf: varName environment: anEnvironment! ! !LargePositiveInteger methodsFor: 'arithmetic' stamp: 'nice 12/30/2012 20:03' prior: 22505876! \\ aNumber "Primitive. Take the receiver modulo the argument. The result is the remainder rounded towards negative infinity, of the receiver divided by the argument. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." aNumber isInteger ifTrue: [| neg qr q r | neg := self negative == aNumber negative == false. qr := (self digitDiv: (aNumber class == SmallInteger ifTrue: [aNumber abs] ifFalse: [aNumber]) neg: neg). q := qr first normalize. r := qr last normalize. ^(q negative ifTrue: [r isZero not] ifFalse: [q isZero and: [neg]]) ifTrue: [r + aNumber] ifFalse: [r]]. ^super \\ aNumber ! ! !LargePositiveInteger methodsFor: 'converting' stamp: 'nice 1/27/2012 22:41' prior: 37616324! asFloat "Answer a Float that best approximates the value of the receiver. This algorithm is optimized to process only the significant digits of a LargeInteger. And it does honour IEEE 754 round to nearest even mode in case of excess precision (see details below)." "How numbers are rounded in IEEE 754 default rounding mode: A shift is applied so that the highest 53 bits are placed before the floating point to form a mantissa. The trailing bits form the fraction part placed after the floating point. This fractional number must be rounded to the nearest integer. If fraction part is 2r0.1, exactly between two consecutive integers, there is a tie. The nearest even integer is chosen in this case. Examples (First 52bits of mantissa are omitted for brevity): 2r0.00001 is rounded downward to 2r0 2r1.00001 is rounded downward to 2r1 2r0.1 is a tie and rounded to 2r0 (nearest even) 2r1.1 is a tie and rounded to 2r10 (nearest even) 2r0.10001 is rounded upward to 2r1 2r1.10001 is rounded upward to 2r10 Thus, if the next bit after floating point is 0, the mantissa is left unchanged. If next bit after floating point is 1, an odd mantissa is always rounded upper. An even mantissa is rounded upper only if the fraction part is not a tie." "Algorihm details: The floating point hardware can perform the rounding correctly with several excess bits as long as there is a single inexact operation. This can be obtained by splitting the mantissa plus excess bits in two part with less bits than Float precision. Note 1: the inexact flag in floating point hardware must not be trusted because in some cases the operations would be exact but would not take into account some bits that were truncated before the Floating point operations. Note 2: the floating point hardware is presumed configured in default rounding mode." | mantissa shift excess result n | "Check how many bits excess the maximum precision of a Float mantissa." excess := self highBitOfMagnitude - Float precision. excess > 7 ifTrue: ["Remove the excess bits but seven." mantissa := self bitShiftMagnitude: 7 - excess. shift := excess - 7. "An even mantissa with a single excess bit immediately following would be truncated. But this would not be correct if above shift has truncated some extra bits. Check this case, and round excess bits upper manually." ((mantissa digitAt: 1) = 2r01000000 and: [self anyBitOfMagnitudeFrom: 1 to: shift]) ifTrue: [mantissa := mantissa + 1]] ifFalse: [mantissa := self. shift := 0]. "There will be a single inexact round off at last iteration" result := (mantissa digitAt: (n := mantissa digitLength)) asFloat. [(n := n - 1) > 0] whileTrue: [ result := 256.0 * result + (mantissa digitAt: n) asFloat]. ^result timesTwoPower: shift.! ! !LargePositiveInteger methodsFor: 'private' stamp: 'nice 12/30/2012 14:25'! primitiveQuo: anInteger "Primitive. Divide the receiver by the argument and return the result. Round the result down towards zero to make it a whole integer. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." ^nil! ! !LargePositiveInteger methodsFor: 'arithmetic' stamp: 'nice 12/30/2012 14:34'! rem: aNumber "Remainder defined in terms of quo:. See super rem:. This is defined only to speed up case of very large integers." (self primitiveQuo: aNumber) ifNotNil: [:quo | ^self - (quo * aNumber)]. aNumber isInteger ifTrue: [| ng rem | ng := self negative == aNumber negative == false. rem := (self digitDiv: (aNumber class == SmallInteger ifTrue: [aNumber abs] ifFalse: [aNumber]) neg: ng) at: 2. ^ rem normalize]. ^super rem: aNumber! ! !LargeNegativeInteger methodsFor: 'converting' stamp: 'nice 1/1/2013 15:42' prior: 37616204! asFloat ^super asFloat negated! ! !UndefinedObject methodsFor: 'class hierarchy' stamp: 'cwp 6/22/2012 15:39'! literalScannedAs: scannedLiteral environment: anEnvironment notifying: requestor ^ scannedLiteral! ! !Behavior methodsFor: 'testing method dictionary' stamp: 'cwp 6/20/2012 17:32'! bindingOf: varName environment: anEnvironment ^superclass bindingOf: varName environment: anEnvironment! ! !Behavior methodsFor: 'testing method dictionary' stamp: 'cwp 6/20/2012 17:30'! classBindingOf: varName environment: anEnvironment ^self bindingOf: varName environment: anEnvironment! ! !Behavior methodsFor: 'printing' stamp: 'cwp 6/22/2012 15:37'! literalScannedAs: scannedLiteral environment: anEnvironment notifying: requestor "Postprocesses a literal scanned by Scanner scanToken (esp. xLitQuote). If scannedLiteral is not an association, answer it. Else, if it is of the form: nil->#NameOfMetaclass answer nil->theMetaclass, if any has that name, else report an error. Else, if it is of the form: #NameOfGlobalVariable->anythiEng answer the global, class, or pool association with that nameE, if any, else add it to Undeclared a answer the new Association." | key value | (scannedLiteral isVariableBinding) ifFalse: [^ scannedLiteral]. key := scannedLiteral key. value := scannedLiteral value. key ifNil: "###" [(self bindingOf: value environment: anEnvironment) ifNotNil: [:assoc| (assoc value isKindOf: Behavior) ifTrue: [^ nil->assoc value class]]. requestor notify: 'No such metaclass'. ^false]. (key isSymbol) ifTrue: "##" [(self bindingOf: key environment: anEnvironment) ifNotNil: [:assoc | ^assoc]. ^ anEnvironment undeclared: key]. requestor notify: '## must be followed by a non-local variable name'. ^false " Form literalScannedAs: 14 notifying: nil 14 Form literalScannedAs: #OneBitForm notiEfying: nil OneBitForm Form literalScannedAs: ##OneBitForm notifying: nil OneBitForm->a Form Form literalScannedAs: ##Form notifying: nil Form->Form Form literalScannedAs: ###Form notifying: nil nilE->Form class "! ! !Fraction methodsFor: 'converting' stamp: 'nice 11/21/2011 22:34' prior: 37619655! asFloat "Answer a Float that closely approximates the value of the receiver. This implementation will answer the closest floating point number to the receiver. In case of a tie, it will use the IEEE 754 round to nearest even mode. In case of overflow, it will answer +/- Float infinity." | a b mantissa exponent hasTruncatedBits lostBit n ha hb hm | a := numerator abs. b := denominator. "denominator is always positive" ha := a highBitOfMagnitude. hb := b highBitOfMagnitude. "Number of bits to keep in mantissa plus one to handle rounding." n := 1 + Float precision. "If both numerator and denominator are represented exactly in floating point number, then fastest thing to do is to use hardwired float division." (ha < n and: [hb < n]) ifTrue: [^numerator asFloat / denominator asFloat]. "Shift the fraction by a power of two exponent so as to obtain a mantissa with n bits. First guess is rough, the mantissa might have n+1 bits." exponent := ha - hb - n. exponent >= 0 ifTrue: [b := b bitShift: exponent] ifFalse: [a := a bitShift: exponent negated]. mantissa := a quo: b. hasTruncatedBits := a > (mantissa * b). hm := mantissa highBit. "Check for gradual underflow, in which case the mantissa will loose bits. Keep at least one bit to let underflow preserve the sign of zero." lostBit := Float emin - (exponent + hm - 1). lostBit > 0 ifTrue: [n := n - lostBit max: 1]. "Remove excess bits in the mantissa." hm > n ifTrue: [exponent := exponent + hm - n. hasTruncatedBits := hasTruncatedBits or: [mantissa anyBitOfMagnitudeFrom: 1 to: hm - n]. mantissa := mantissa bitShift: n - hm]. "Check if mantissa must be rounded upward. The case of tie (mantissa odd & hasTruncatedBits not) will be handled by Integer>>asFloat." (hasTruncatedBits and: [mantissa odd]) ifTrue: [mantissa := mantissa + 1]. ^ (self positive ifTrue: [mantissa asFloat] ifFalse: [mantissa asFloat negated]) timesTwoPower: exponent! ! !Float methodsFor: 'arithmetic' stamp: 'nice 12/20/2012 23:16' prior: 20878776! negated "Answer a Number that is the negation of the receiver. Implementation note: this version cares of negativeZero." ^-1.0 * self! ! !ClassDescription methodsFor: 'compiling' stamp: 'cwp 6/20/2012 17:21'! compile: text environment: anEnvironment classified: category withStamp: changeStamp notifying: requestor ^ self compile: text environment: anEnvironment classified: category withStamp: changeStamp notifying: requestor logSource: self acceptsLoggingOfCompilation! ! !ClassDescription methodsFor: 'compiling' stamp: 'cwp 12/27/2012 13:17'! compile: text environment: anEnvironment classified: category withStamp: changeStamp notifying: requestor logSource: logSource | methodAndNode context methodNode | context := CompilationCue source: text class: self environment: anEnvironment category: category requestor: requestor. methodNode := self newCompiler compile: context ifFail: [^ nil]. methodAndNode := CompiledMethodWithNode generateMethodFromNode: methodNode trailer: self defaultMethodTrailer. logSource ifTrue: [ self logMethodSource: text forMethodWithNode: methodAndNode inCategory: category withStamp: changeStamp notifying: requestor. ]. self addAndClassifySelector: methodAndNode selector withMethod: methodAndNode method inProtocol: category notifying: requestor. self instanceSide noteCompilationOf: methodAndNode selector meta: self isClassSide. ^ methodAndNode selector! ! !Class methodsFor: 'compiling' stamp: 'cwp 6/20/2012 09:47'! bindingOf: varName environment: anEnvironment "Answer the binding of some variable resolved in the scope of the receiver" | aSymbol binding | aSymbol := varName asSymbol. "First look in classVar dictionary." binding := self classPool bindingOf: aSymbol. binding ifNotNil:[^binding]. "Next look in shared pools." self sharedPools do:[:pool | binding := pool bindingOf: aSymbol. binding ifNotNil:[^binding]. ]. "Next look in declared environment." binding := anEnvironment bindingOf: aSymbol. binding ifNotNil:[^binding]. "Finally look higher up the superclass chain and fail at the end." superclass == nil ifTrue: [^ nil] ifFalse: [^ superclass bindingOf: aSymbol]. ! ! "Kernel"! ParseNode subclass: #Encoder instanceVariableNames: 'scopeTable nTemps supered requestor class selector literalStream selectorSet litIndSet litSet sourceRanges globalSourceRanges addedSelectorAndMethodClassLiterals optimizedSelectors cue' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! !Encoder commentStamp: 'cwp 12/26/2012 23:29' prior: 36323851! I encode names and literals into tree nodes with byte codes for the compiler. Byte codes for literals are not assigned until the tree-sizing pass of the compiler, because only then is it known which literals are actually needed. I also keep track of sourceCode ranges during parsing and code generation so I can provide an inverse map for the debugger.! Scanner subclass: #Parser instanceVariableNames: 'here hereType hereMark hereEnd prevMark prevEnd encoder requestor parseNode failBlock requestorOffset tempsMark doitFlag properties category queriedUnusedTemporaries cue' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! !Parser commentStamp: 'cwp 12/26/2012 23:34' prior: 38557958! I parse Smalltalk syntax and create a MethodNode that is the root of the parse tree. I look one token ahead.! Object subclass: #CompilationCue instanceVariableNames: 'source context receiver class environment category requestor' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! Object subclass: #Compiler instanceVariableNames: 'sourceStream requestor class category context parser cue' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! !Compiler commentStamp: 'cwp 12/26/2012 23:17' prior: 59257505! The compiler accepts Smalltalk source code and compiles it with respect to a given class. The user of the compiler supplies a context so that temporary variables are accessible during compilation. If there is an error, a requestor (usually a kind of StringHolderController) is sent the message notify:at:in: so that the error message can be displayed. If there is no error, then the result of compilation is a MethodNode, which is the root of a parse tree whose nodes are kinds of ParseNodes. The parse tree can be sent messages to (1) generate code for a CompiledMethod (this is done for compiling methods or evaluating expressions); (2) pretty-print the code (for formatting); or (3) produce a map from object code back to source code (used by debugger program-counter selection). See also Parser, Encoder, ParseNode.! !Encoder methodsFor: 'initialize-release' stamp: 'cwp 12/26/2012 23:34'! init: aCue notifying: anObject "The use of the variable requestor is a bit confusing here. This is *not* the original requestor, which is available through the cue. It's the Parser instance that is using the encoder." self setCue: aCue. requestor := anObject. nTemps := 0. supered := false. self initScopeAndLiteralTables. cue getClass variablesAndOffsetsDo: [:variable "" :offset "" | offset isNil ifTrue: [scopeTable at: variable name put: (FieldNode new fieldDefinition: variable)] ifFalse: [scopeTable at: variable put: (offset >= 0 ifTrue: [InstanceVariableNode new name: variable index: offset] ifFalse: [MaybeContextInstanceVariableNode new name: variable index: offset negated])]]. cue context ~~ nil ifTrue: [| homeNode | homeNode := self bindTemp: self doItInContextName. "0th temp = aContext passed as arg" cue context tempNames withIndexDo: [:variable :index| scopeTable at: variable put: (MessageAsTempNode new receiver: homeNode selector: #namedTempAt: arguments: (Array with: (self encodeLiteral: index)) precedence: 3 from: self)]]. sourceRanges := Dictionary new: 32. globalSourceRanges := OrderedCollection new: 32 ! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/26/2012 23:30'! setCue: aCue cue := aCue. "Also set legacy instance variables for methods that don't use cue yet" class := cue getClass.! ! !Dictionary methodsFor: '*Compiler' stamp: 'cwp 6/22/2012 09:17'! bindingOf: varName ifAbsent: aBlock ^self associationAt: varName ifAbsent: aBlock! ! !Parser methodsFor: 'private' stamp: 'cwp 12/26/2012 23:37'! init: sourceStream cue: aCue failBlock: aBlock self setCue: aCue. failBlock := aBlock. requestorOffset := 0. super scan: sourceStream. prevMark := hereMark := mark. self advance ! ! !Parser methodsFor: 'public access' stamp: 'cwp 12/26/2012 23:41'! parse: sourceStream cue: aCue noPattern: noPattern ifFail: aBlock "Answer a MethodNode for the argument, sourceStream, that is the root of a parse tree. Parsing is done with respect to the CompilationCue to resolve variables. Errors in parsing are reported to the cue's requestor; otherwise aBlock is evaluated. The argument noPattern is a Boolean that is true if the the sourceStream does not contain a method header (i.e., for DoIts)." | methNode repeatNeeded myStream s p subSelection | myStream := sourceStream. [repeatNeeded := false. p := myStream position. s := myStream upToEnd. myStream position: p. subSelection := aCue requestor notNil and: [aCue requestor selectionInterval = (p + 1 to: p + s size)]. self encoder init: aCue notifying: self. self init: myStream cue: aCue failBlock: [^ aBlock value]. doitFlag := noPattern. failBlock:= aBlock. [methNode := self method: noPattern context: cue context] on: ReparseAfterSourceEditing do: [ :ex | repeatNeeded := true. myStream := subSelection ifTrue: [ReadStream on: cue requestor text string from: cue requestor selectionInterval first to: cue requestor selectionInterval last] ifFalse: [ReadStream on: cue requestor text string]]. repeatNeeded] whileTrue: [encoder := self encoder class new]. methNode sourceText: s. ^methNode ! ! !Parser methodsFor: 'private' stamp: 'cwp 12/26/2012 23:35'! setCue: aCue cue := aCue. "Also set legacy variables for methods that don't use cue yet." requestor := cue requestor. category := cue category.! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:53'! class: aClass ^ self context: nil class: aClass requestor: nil! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:53'! context: aContext class: aClass requestor: anObject ^ self source: nil context: aContext receiver: nil class: aClass environment: (aClass ifNotNil: [aClass environment]) category: nil requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:16'! source: aTextOrStream class: aClass environment: anEnvironment category: aString requestor: anObject ^ self source: aTextOrStream context: nil receiver: nil class: aClass environment: anEnvironment category: aString requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:53'! source: aTextOrStream context: aContext class: aClass category: aString requestor: anObject ^ self source: aTextOrStream context: aContext receiver: (aContext ifNotNil: [aContext receiver]) class: aClass environment: (aClass ifNotNil: [aClass environment]) category: aString requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:54'! source: aTextOrStream context: aContext class: aClass requestor: anObject ^ self source: aTextOrStream context: aContext class: aClass category: nil requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:55'! source: aTextOrStream context: aContext receiver: recObject class: aClass environment: anEnvironment category: aString requestor: reqObject ^ self basicNew initializeWithSource: aTextOrStream context: aContext receiver: recObject class: aClass environment: anEnvironment category: aString requestor: reqObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:16'! source: aString environment: anEnvironment ^ self source: aString context: nil receiver: nil class: UndefinedObject environment: anEnvironment category: nil requestor: nil! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:54'! source: aTextOrStream requestor: anObject ^ self source: aTextOrStream context: nil class: nil requestor: anObject! ! !CompilationCue methodsFor: 'binding' stamp: 'cwp 6/20/2012 09:39'! bindingOf: aSymbol ^ class bindingOf: aSymbol environment: environment! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! category ^ category! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 12/26/2012 23:19'! context ^ context! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! environment ^ environment! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:16'! getClass ^ class! ! !CompilationCue methodsFor: 'initialization' stamp: 'cwp 12/26/2012 23:16'! initializeWithSource: aTextOrString context: aContext receiver: recObject class: aClass environment: anEnvironment category: aString requestor: reqObject self initialize. source := aTextOrString isStream ifTrue: [aTextOrString contents] ifFalse: [aTextOrString]. context := aContext. receiver := recObject. class := aClass. environment := anEnvironment. category := aString. requestor := reqObject! ! !CompilationCue methodsFor: 'binding' stamp: 'cwp 6/22/2012 15:39'! literalScannedAs: anObject notifying: anEncoder ^ class literalScannedAs: anObject environment: environment notifying: anEncoder! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! receiver ^ receiver! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:16'! requestor ^ requestor! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! source ^ source! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:44'! sourceStream ^ source readStream! ! !Compiler class methodsFor: 'evaluating' stamp: 'cwp 6/20/2012 17:25'! evaluate: aString environment: anEnvironment ^ self evaluate: aString environment: anEnvironment logged: false! ! !Compiler class methodsFor: 'evaluating' stamp: 'cwp 12/27/2012 12:36'! evaluate: aString environment: anEnvironment logged: aBoolean | cue | cue := CompilationCue source: aString environment: anEnvironment. ^ self new evaluate: aString cue: cue ifFail: [^ nil] logged: aBoolean! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 13:18'! compile: aCue ifFail: failBlock "Answer a MethodNode. If the MethodNode can not be created, notify the requestor in the contxt. If the requestor is nil, evaluate failBlock instead. The MethodNode is the root of a parse tree. It can be told to generate a CompiledMethod to be installed in the method dictionary of the class specified by the context." self setCue: aCue. self source: cue source. ^self translate: sourceStream noPattern: false ifFail: failBlock! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 00:06'! evaluate: textOrStream cue: aCue ifFail: failBlock logged: logFlag "Compiles the sourceStream into a parse tree, then generates code into a method. Finally, the compiled method is invoked from here via withArgs:executeMethod:, hence the system no longer creates Doit method litter on errors." | methodNode method value toLog itsSelection itsSelectionString | self setCue: aCue. self source: textOrStream. methodNode := self translate: sourceStream noPattern: true ifFail: [^failBlock value]. method := self interactive ifTrue: [methodNode generateWithTempNames] ifFalse: [methodNode generate]. value := cue receiver withArgs: (cue context ifNil: [#()] ifNotNil: [{cue context}]) executeMethod: method. logFlag ifTrue: [toLog := ((cue requestor respondsTo: #selection) and:[(itsSelection := cue requestor selection) notNil and:[(itsSelectionString := itsSelection asString) isEmptyOrNil not]]) ifTrue:[itsSelectionString] ifFalse:[sourceStream contents]. SystemChangeNotifier uniqueInstance evaluated: toLog context: cue context]. ^ value ! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/26/2012 23:20'! setCue: aCue cue := aCue. "Set legacy instance variables for methods that don't use cue yet." requestor := cue requestor. class := cue getClass. category := cue category. context := cue context.! ! !Compiler methodsFor: 'private' stamp: 'cwp 6/19/2012 21:58'! source: textOrStream sourceStream := (textOrStream isKindOf: PositionableStream) ifTrue: [ textOrStream ] ifFalse: [ ReadStream on: textOrStream asString ]! ! "Compiler"! !SmartRefStream class methodsFor: 'i/o' stamp: 'cwp 6/20/2012 17:42'! scanFrom: aByteStream environment: anEnvironment ^ self scanFrom: aByteStream! ! !SmartRefStream methodsFor: 'read write' stamp: 'cwp 6/20/2012 17:41'! scanFrom: aByteStream environment: anEnvironment ^ self scanFrom: aByteStream! ! !ImageSegment methodsFor: 'fileIn/Out' stamp: 'cwp 6/20/2012 17:23'! scanFrom: aStream environment: anEnvironment ^ self scanFrom: aStream! ! !PseudoClass methodsFor: 'printing' stamp: 'cwp 6/22/2012 15:39'! literalScannedAs: scannedLiteral environment: anEnvironment notifying: requestor ^ scannedLiteral! ! !InternalTranslator methodsFor: 'fileIn/fileOut' stamp: 'cwp 6/20/2012 17:34'! scanFrom: aStream environment: anEnvironment "Read a definition of dictionary. Make sure current locale corresponds my locale id" | aString newTranslations assoc currentPlatform | newTranslations := Dictionary new. currentPlatform := Locale currentPlatform. [Locale currentPlatform: (Locale localeID: id). [aString := aStream nextChunk withSqueakLineEndings. aString size > 0] whileTrue: [assoc := Compiler evaluate: aString environment: anEnvironment. assoc value = '' ifTrue: [self class registerPhrase: assoc key] ifFalse: [newTranslations add: assoc]]] ensure: [Locale currentPlatform: currentPlatform]. self mergeTranslations: newTranslations! ! !NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'cwp 6/20/2012 17:26'! scanFrom: aStream environment: anEnvironment "Read a definition of dictionary. Make sure current locale corresponds my locale id" | newTranslations currentPlatform | newTranslations := Dictionary new. currentPlatform := Locale currentPlatform. [| aString assoc | Locale currentPlatform: (Locale localeID: id). [aString := aStream nextChunk withSqueakLineEndings. aString size > 0] whileTrue: [assoc := Compiler evaluate: aString environment: anEnvironment. assoc value = '' ifTrue: [self class registerPhrase: assoc key] ifFalse: [newTranslations add: assoc]]] ensure: [Locale currentPlatform: currentPlatform]. self mergeTranslations: newTranslations! ! !ObjectScanner methodsFor: 'scanning' stamp: 'cwp 6/20/2012 17:39'! scanFrom: aByteStream environment: anEnvironment "This should probably be reimplemented using an environment for compilation. For now, don't change anything" ^ self scanFrom: aByteStream! ! !SystemDictionary methodsFor: 'accessing' stamp: 'cwp 6/22/2012 09:16'! bindingOf: varName ifAbsent: aBlock "SystemDictionary includes Symbols only" ^super bindingOf: varName asSymbol ifAbsent: aBlock! ! !SystemDictionary methodsFor: 'accessing' stamp: 'cwp 6/22/2012 15:48'! undeclared ^ self at: #Undeclared! ! "System"! !ExceptionTests methodsFor: 'testing-outer' stamp: 'fbs 1/1/2013 22:14' prior: 40840955! expectedFailures ^ #().! ! "Tests"! ReleaseBuilder subclass: #ReleaseBuilderFor4dot5 instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'ReleaseBuilder'! !ReleaseBuilderFor4dot5 commentStamp: 'fbs 1/1/2013 20:25' prior: 0! The release builder for Squeak 4.5! !ReleaseBuilder class methodsFor: 'scripts' stamp: 'fbs 12/31/2012 20:43'! transferCurrentPackagesAsUser: username password: password "Copy the packages currently loaded in the image from the trunk repository to my releaseRepository." | trunkRep releaseRep | trunkRep := self trunkRepository. releaseRep := self releaseRepository user: username; password: password; yourself. MCWorkingCopy allManagers do: [ : eachWorkingCopy | eachWorkingCopy ancestors do: [ : eachVersionInfo | (releaseRep includesVersionNamed: eachVersionInfo versionName) ifFalse: [ (trunkRep versionWithInfo: eachVersionInfo) ifNil: [ Warning signal: eachVersionInfo name , ' not found in ', trunkRep ] ifNotNilDo: [ : ver | releaseRep storeVersion: ver ] ] ] ]! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! openWelcomeWorkspaces TheWorldMainDockingBar instance showWelcomeText: #squeakUserInterface label: 'Squeak User Interface' in: (40 @ 40 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #workingWithSqueak label: 'Working With Squeak' in: (80 @ 80 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #licenseInformation label: 'License Information' in: (120 @ 120 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #welcomeFutureDirections label: 'Future Directions' in: (160 @ 160 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #welcomeToSqueak label: 'Welcome to Squeak 4.5' in: (200 @ 200 extent: 500 @ 300)! ! !ReleaseBuilderFor4dot5 class methodsFor: 'scripts' stamp: 'fbs 1/1/2013 20:22'! prepareNewBuild super prepareNewBuild. MCMockPackageInfo initialize.! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:24'! releaseRepository "At release time, change 'trunk' to 'squeak45'." ^ MCHttpRepository location: 'http://source.squeak.org/trunk' user: 'squeak' password: 'squeak'! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:22'! setDisplayExtent: extent "Uncomment next line when the primitives become available in the Squeak VM." " DisplayScreen hostWindowSize: extent." Display extent = extent ifFalse: [ Warning signal: 'Display extent not set to ', extent ]! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! setPreferences Preferences installBrightWindowColors ; setPreference: #scrollBarsWithoutMenuButton toValue: true ; setPreference: #swapMouseButtons toValue: true ; setPreference: #annotationPanes toValue: true ; setPreference: #showSplitterHandles toValue: false ; setPreference: #showBoundsInHalo toValue: true ; setPreference: #alternateHandlesLook toValue: false ; setPreference: #roundedMenuCorners toValue: false ; setPreference: #roundedWindowCorners toValue: false. PluggableButtonMorph roundedButtonCorners: false. FillInTheBlankMorph roundedDialogCorners: false. Workspace shouldStyle: false. NetNameResolver enableIPv6: true.! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! switchToNewRepository | old44Repository | MCMcmUpdater defaultUpdateURL: self releaseRepository description. old44Repository := MCRepositoryGroup default repositories detect: [:each | each description includesSubString: 'squeak44'] ifNone: [nil]. old44Repository ifNotNil: [MCRepositoryGroup default removeRepository: old44Repository]. MCRepositoryGroup default addRepository: self releaseRepository! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! versionString ^ 'Squeak4.5'.! ! ReleaseBuilder class removeSelector: #transferCurrentPackages! "ReleaseBuilder"! !Environment class methodsFor: 'as yet unclassified' stamp: 'cwp 1/1/2013 18:52' prior: 40834114! initialize self install! ! "Environments"! !Parser methodsFor: 'private' stamp: 'cwp 12/26/2012 23:59' prior: 52081878! initPattern: aString notifying: req return: aBlock | result | self init: (ReadStream on: aString asString) cue: (CompilationCue source: aString requestor: req) failBlock: [^nil]. encoder := self. result := aBlock value: (self pattern: false inContext: nil). encoder := failBlock := nil. "break cycles" ^result! ! !Parser methodsFor: 'public access' stamp: 'cwp 12/27/2012 00:01' prior: 34175471! parse: sourceStream class: class category: aCategory noPattern: noPattern context: aContext notifying: req ifFail: aBlock | c | c := CompilationCue source: sourceStream context: aContext class: class category: aCategory requestor: req. ^ self parse: sourceStream cue: c noPattern: noPattern ifFail: aBlock! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 09:11' prior: 34183963! evaluate: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: logFlag "Compiles the sourceStream into a parse tree, then generates code into a method. If aContext is not nil, the text can refer to temporaries in that context (the Debugger uses this). If aRequestor is not nil, then it will receive a notify:at: message before the attempt to evaluate is aborted. Finally, the compiled method is invoked from here via withArgs:executeMethod:, hence the system no longer creates Doit method litter on errors." | theClass | theClass := ((aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class). self setCue: (CompilationCue source: textOrStream context: aContext receiver: receiver class: theClass environment: theClass environment category: nil requestor: aRequestor). ^ self evaluate: textOrStream cue: cue ifFail: failBlock logged: logFlag! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 09:17' prior: 34185488! from: textOrStream class: aClass classified: aCategory context: aContext notifying: req self source: textOrStream. self setCue: (CompilationCue source: textOrStream context: aContext class: aClass category: aCategory requestor: req)! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/26/2012 23:55' prior: 50781309! from: textOrStream class: aClass context: aContext notifying: req self source: textOrStream. self setCue: (CompilationCue source: textOrStream context: aContext class: aClass requestor: req) ! ! !Encoder methodsFor: 'initialize-release' stamp: 'cwp 12/27/2012 09:41' prior: 50996506! init: aClass context: aContext notifying: anObject | c | c := CompilationCue context: aContext class: aClass requestor: nil. self init: c notifying: anObject! ! !Encoder methodsFor: 'initialize-release' stamp: 'cwp 12/26/2012 23:58' prior: 39061698! temps: tempVars literals: lits class: cl "Initialize this encoder for decompilation." self setCue: (CompilationCue class: cl). supered := false. nTemps := tempVars size. tempVars do: [:node | scopeTable at: node name put: node]. literalStream := WriteStream on: (Array new: lits size). literalStream nextPutAll: lits. sourceRanges := Dictionary new: 32. globalSourceRanges := OrderedCollection new: 32.! ! "Compiler"! !Class methodsFor: 'class variables' stamp: 'cwp 6/22/2012 15:48' prior: 36026010! addClassVarName: aString "Add the argument, aString, as a class variable of the receiver. Signal an error if the first character of aString is not capitalized, or if it is already a variable named in the class." | symbol oldState | oldState := self copy. aString first canBeGlobalVarInitial ifFalse: [^self error: aString, ' class variable name should be capitalized; proceed to include anyway.']. symbol := aString asSymbol. self withAllSubclasses do: [:subclass | (self canFindWithoutEnvironment: symbol) ifTrue: [ (DuplicateVariableError new) superclass: superclass; "fake!!!!!!" variable: aString; signal: aString, ' is already defined']]. classPool == nil ifTrue: [classPool := Dictionary new]. (classPool includesKey: symbol) ifFalse: ["Pick up any refs in Undeclared" classPool declare: symbol from: environment undeclared. SystemChangeNotifier uniqueInstance classDefinitionChangedFrom: oldState to: self]! ! !Class methodsFor: 'compiling' stamp: 'cwp 6/20/2012 09:48' prior: 54782024! bindingOf: varName ^ self bindingOf: varName environment: self environment! ! !Class methodsFor: 'organization' stamp: 'cwp 6/25/2012 18:25' prior: 54785804! category "Answer the system organization category for the receiver. First check whether the category name stored in the ivar is still correct and only if this fails look it up (latter is much more expensive)" category ifNotNil: [ :symbol | ((self environment organization listAtCategoryNamed: symbol) includes: self name) ifTrue: [ ^symbol ] ]. category := self environment organization categoryOfElement: self name. ^category! ! !Class methodsFor: 'initialize-release' stamp: 'cwp 6/22/2012 15:49' prior: 36027730! declare: varString "Declare class variables common to all instances. Answer whether recompilation is advisable." | newVars conflicts | newVars := (Scanner new scanFieldNames: varString) collect: [:x | x asSymbol]. newVars do: [:var | var first canBeGlobalVarInitial ifFalse: [self error: var, ' class variable name should be capitalized; proceed to include anyway.']]. conflicts := false. classPool == nil ifFalse: [(classPool keys reject: [:x | newVars includes: x]) do: [:var | self removeClassVarName: var]]. (newVars reject: [:var | self classPool includesKey: var]) do: [:var | "adding" "check if new vars defined elsewhere" (self canFindWithoutEnvironment: var) ifTrue: [ (DuplicateVariableError new) superclass: superclass; "fake!!!!!!" variable: var; signal: var, ' is already defined'. conflicts := true]]. newVars size > 0 ifTrue: [classPool := self classPool. "in case it was nil" newVars do: [:var | classPool declare: var from: environment undeclared]]. ^conflicts! ! !Class methodsFor: 'class variables' stamp: 'cwp 6/22/2012 15:49' prior: 54802475! removeClassVarName: aString "Remove the class variable whose name is the argument, aString, from the names defined in the receiver, a class. Create an error notification if aString is not a class variable or if it is still being used in the code of the class." | aSymbol | aSymbol := aString asSymbol. (classPool includesKey: aSymbol) ifFalse: [^self error: aString, ' is not a class variable']. self withAllSubclasses do:[:subclass | (Array with: subclass with: subclass class) do:[:classOrMeta | (classOrMeta whichSelectorsReferTo: (classPool associationAt: aSymbol)) isEmpty ifFalse: [ InMidstOfFileinNotification signal ifTrue: [ Transcript cr; show: self name, ' (' , aString , ' is Undeclared) '. ^ environment undeclared declare: aSymbol from: classPool]. (self confirm: (aString,' is still used in code of class ', classOrMeta name, '.\Is it okay to move it to Undeclared?') withCRs) ifTrue:[^Undeclared declare: aSymbol from: classPool] ifFalse:[^self]]]]. classPool removeKey: aSymbol. classPool isEmpty ifTrue: [classPool := nil]. ! ! !Class methodsFor: 'class name' stamp: 'cwp 6/22/2012 15:49' prior: 54796206! rename: aString "The new name of the receiver is the argument, aString." | oldName newName | (newName := aString asSymbol) = (oldName := self name) ifTrue: [^ self]. (self environment includesKey: newName) ifTrue: [^ self error: newName , ' already exists']. (environment undeclared includesKey: newName) ifTrue: [self inform: 'There are references to, ' , aString printString , ' from Undeclared. Check them after this change.']. name := newName. self environment renameClass: self from: oldName! ! !ClassBuilder methodsFor: 'class definition' stamp: 'cwp 6/22/2012 01:05' prior: 39054430! name: className inEnvironment: env subclassOf: newSuper type: type instanceVariableNames: instVarString classVariableNames: classVarString poolDictionaries: poolString category: category unsafe: unsafe "Define a new class in the given environment. If unsafe is true do not run any validation checks. This facility is provided to implement important system changes." | oldClass instVars classVars copyOfOldClass newClass | environ := env. instVars := Scanner new scanFieldNames: instVarString. classVars := (Scanner new scanFieldNames: classVarString) collect: [:x | x asSymbol]. "Validate the proposed name" unsafe ifFalse:[(self validateClassName: className) ifFalse:[^nil]]. oldClass := env at: className ifAbsent:[nil]. oldClass isBehavior ifFalse: [oldClass := nil] "Already checked in #validateClassName:" ifTrue: [ copyOfOldClass := oldClass copy. copyOfOldClass superclass addSubclass: copyOfOldClass]. [ | newCategory needNew force organization oldCategory | unsafe ifFalse:[ "Run validation checks so we know that we have a good chance for recompilation" (self validateSuperclass: newSuper forSubclass: oldClass) ifFalse:[^nil]. (self validateInstvars: instVars from: oldClass forSuper: newSuper) ifFalse:[^nil]. (self validateClassvars: classVars from: oldClass forSuper: newSuper) ifFalse:[^nil]. (self validateSubclassFormat: type from: oldClass forSuper: newSuper extra: instVars size) ifFalse:[^nil]]. "See if we need a new subclass" needNew := self needsSubclassOf: newSuper type: type instanceVariables: instVars from: oldClass. needNew == nil ifTrue:[^nil]. "some error" (needNew and:[unsafe not]) ifTrue:[ "Make sure we don't redefine any dangerous classes" (self tooDangerousClasses includes: oldClass name) ifTrue:[ self error: oldClass name, ' cannot be changed'. ]. "Check if the receiver should not be redefined" (oldClass ~~ nil and:[oldClass shouldNotBeRedefined]) ifTrue:[ self notify: oldClass name asText allBold, ' should not be redefined. \Proceed to store over it.' withCRs]]. needNew ifTrue:[ "Create the new class" newClass := self newSubclassOf: newSuper type: type instanceVariables: instVars from: oldClass. newClass == nil ifTrue:[^nil]. "Some error" newClass setName: className. newClass environment: environ. ] ifFalse:[ "Reuse the old class" newClass := oldClass. ]. "Install the class variables and pool dictionaries... " force := (newClass declare: classVarString) | (newClass sharing: poolString). "... classify ..." newCategory := category asSymbol. organization := environ ifNotNil:[environ organization]. oldClass isNil ifFalse: [oldCategory := (organization categoryOfElement: oldClass name) asSymbol]. organization classify: newClass name under: newCategory suppressIfDefault: true. "... recompile ..." newClass := self recompile: force from: oldClass to: newClass mutate: false. "... export if not yet done ..." (environ at: newClass name ifAbsent:[nil]) == newClass ifFalse:[ [environ at: newClass name put: newClass] on: AttemptToWriteReadOnlyGlobal do:[:ex| ex resume: true]. environ flushClassNameCache. ]. newClass doneCompiling. "... notify interested clients ..." oldClass isNil ifTrue: [ SystemChangeNotifier uniqueInstance classAdded: newClass inCategory: newCategory. ^ newClass]. newCategory ~= oldCategory ifTrue: [SystemChangeNotifier uniqueInstance class: newClass recategorizedFrom: oldCategory to: category] ifFalse: [SystemChangeNotifier uniqueInstance classDefinitionChangedFrom: copyOfOldClass to: newClass.]. ] ensure: [copyOfOldClass ifNotNil: [copyOfOldClass superclass removeSubclass: copyOfOldClass]. Behavior flushObsoleteSubclasses. ]. ^newClass! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 22:57' prior: 18572019! superclass: newSuper subclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class." | env | env := EnvironmentRequest signal ifNil: [newSuper environment]. ^self name: t inEnvironment: env subclassOf: newSuper type: newSuper typeOfClass instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:01' prior: 50629912! superclass: aClass variableByteSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class in which the subclass is to have indexable byte-sized nonpointer variables." | oldClassOrNil actualType env | (aClass instSize > 0) ifTrue: [^self error: 'cannot make a byte subclass of a class with named fields']. (aClass isVariable and: [aClass isWords]) ifTrue: [^self error: 'cannot make a byte subclass of a class with word fields']. (aClass isVariable and: [aClass isPointers]) ifTrue: [^self error: 'cannot make a byte subclass of a class with pointer fields']. oldClassOrNil := aClass environment at: t ifAbsent:[nil]. actualType := (oldClassOrNil notNil and: [oldClassOrNil typeOfClass == #compiledMethod]) ifTrue: [#compiledMethod] ifFalse: [#bytes]. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: actualType instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:03' prior: 18573442! superclass: aClass variableSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class in which the subclass is to have indexable pointer variables." | env | aClass isBits ifTrue: [^self error: 'cannot make a pointer subclass of a class with non-pointer fields']. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: #variable instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:04' prior: 18574098! superclass: aClass variableWordSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class in which the subclass is to have indexable word-sized nonpointer variables." | env | (aClass instSize > 0) ifTrue: [^self error: 'cannot make a word subclass of a class with named fields']. (aClass isVariable and: [aClass isBytes]) ifTrue: [^self error: 'cannot make a word subclass of a class with byte fields']. (aClass isVariable and: [aClass isPointers]) ifTrue: [^self error: 'cannot make a word subclass of a class with pointer fields']. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: #words instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:04' prior: 18575028! superclass: aClass weakSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class (the receiver) in which the subclass is to have weak indexable pointer variables." | env | aClass isBits ifTrue: [^self error: 'cannot make a pointer subclass of a class with non-pointer fields']. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: #weak instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! "Kernel"! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:21' prior: 59135029! ambiguousSelector: aString inRange: anInterval | correctedSelector userSelection offset intervalWithOffset | self interactive ifFalse: [ "In non interactive mode, compile with backward comapatibility: $- is part of literal argument" Transcript cr; store: encoder classEncoding; nextPutAll:#'>>';store: encoder selector; show: ' would send ' , token , '-'. ^super ambiguousSelector: aString inRange: anInterval]. "handle the text selection" userSelection := cue requestor selectionInterval. intervalWithOffset := anInterval first + requestorOffset to: anInterval last + requestorOffset. cue requestor selectFrom: intervalWithOffset first to: intervalWithOffset last. cue requestor select. "Build the menu with alternatives" correctedSelector := AmbiguousSelector signalName: aString inRange: intervalWithOffset. correctedSelector ifNil: [^self fail]. "Execute the selected action" offset := self substituteWord: correctedSelector wordInterval: intervalWithOffset offset: 0. cue requestor deselect. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last + offset. token := (correctedSelector readStream upTo: Character space) asSymbol! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:21' prior: 38558136! collectTemporaryDeclarationsFrom: methodNode | tempsMarks str | tempsMarks := OrderedCollection new. str := cue requestor text asString. methodNode accept: (ParseNodeEnumerator ofBlock: [ :aNode | | mark | (aNode class canUnderstand: #tempsMark) ifTrue: [mark := aNode tempsMark. (mark notNil and: [ mark between: 1 and: str size ] and: [ (str at: mark) = $| ]) ifTrue: [ tempsMarks addLast: aNode ]]]). (tempsMark notNil and: [ tempsMark between: 1 and: str size ] and: [ (str at: tempsMark) = $| ]) ifTrue: [ tempsMarks addLast: self ]. ^ tempsMarks sorted: [ :a :b | a tempsMark > b tempsMark ]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:20' prior: 52096606! correctSelector: proposedKeyword wordIntervals: spots exprInterval: expInt ifAbort: abortAction "Correct the proposedKeyword to some selector symbol, correcting the original text if such action is indicated. abortAction is invoked if the proposedKeyword couldn't be converted into a valid selector. Spots is an ordered collection of intervals within the test stream of the for each of the keyword parts." | correctSelector userSelection | "If we can't ask the user, assume that the keyword will be defined later" self interactive ifFalse: [^proposedKeyword asSymbol]. userSelection := cue requestor selectionInterval. cue requestor selectFrom: spots first first to: spots last last. cue requestor select. correctSelector := UnknownSelector name: proposedKeyword. correctSelector ifNil: [^abortAction value]. cue requestor deselect. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last. self substituteSelector: correctSelector keywords wordIntervals: spots. ^(proposedKeyword last ~~ $: and: [correctSelector last == $:]) ifTrue: [abortAction value] ifFalse: [correctSelector]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:20' prior: 33907242! correctVariable: proposedVariable interval: spot "Correct the proposedVariable to a known variable, or declare it as a new variable if such action is requested. We support declaring lowercase variables as temps or inst-vars, and uppercase variables as Globals or ClassVars, depending on whether the context is nil (class=UndefinedObject). Spot is the interval within the test stream of the variable. rr 3/4/2004 10:26 : adds the option to define a new class. " "Check if this is an i-var, that has been corrected already (ugly)" "Display the pop-up menu" | binding userSelection action | (encoder classEncoding instVarNames includes: proposedVariable) ifTrue: [^InstanceVariableNode new name: proposedVariable index: (encoder classEncoding allInstVarNames indexOf: proposedVariable)]. "If we can't ask the user for correction, make it undeclared" self interactive ifFalse: [^encoder undeclared: proposedVariable]. "First check to see if the requestor knows anything about the variable" (binding := cue requestor bindingOf: proposedVariable) ifNotNil: [^encoder global: binding name: proposedVariable]. userSelection := cue requestor selectionInterval. cue requestor selectFrom: spot first to: spot last. cue requestor select. "Build the menu with alternatives" action := UndeclaredVariable signalFor: self name: proposedVariable inRange: spot. action ifNil: [^self fail]. "Execute the selected action" cue requestor deselect. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last. ^action value! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:19' prior: 34172921! declareUndeclaredTemps: methodNode "Declare any undeclared temps, declaring them at the smallest enclosing scope." | undeclared userSelection blocksToVars | (undeclared := encoder undeclaredTemps) isEmpty ifTrue: [^self]. userSelection := cue requestor selectionInterval. blocksToVars := IdentityDictionary new. undeclared do: [:var| (blocksToVars at: (var tag == #method ifTrue: [methodNode block] ifFalse: [methodNode accept: (VariableScopeFinder new ofVariable: var)]) ifAbsentPut: [SortedCollection new]) add: var name]. (blocksToVars removeKey: methodNode block ifAbsent: []) ifNotNil: [:rootVars| rootVars do: [:varName| self pasteTempAtMethodLevel: varName]]. (blocksToVars keys sorted: [:a :b| a tempsMark < b tempsMark]) do: [:block| | decl | decl := (blocksToVars at: block) reduce: [:a :b| a, ' ', b]. block temporaries isEmpty ifTrue: [self substituteWord: ' | ', decl, ' |' wordInterval: (block tempsMark + 1 to: block tempsMark) offset: requestorOffset] ifFalse: [self substituteWord: decl, ' ' wordInterval: (block tempsMark to: block tempsMark - 1) offset: requestorOffset]]. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last + requestorOffset. ReparseAfterSourceEditing signal! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 11:45' prior: 37183770! defineClass: className "prompts the user to define a new class, asks for it's category, and lets the users edit further the definition" | sym cat def d2 | sym := className asSymbol. cat := UIManager default request: 'Enter class category : ' initialAnswer: self encoder classEncoding theNonMetaClass category. cat ifEmpty: [cat := 'Unknown']. def := 'Object subclass: #' , sym , ' instanceVariableNames: '''' classVariableNames: '''' poolDictionaries: '''' category: ''' , cat , ''''. d2 := UIManager default request: 'Edit class definition : ' initialAnswer: def. d2 ifEmpty: [d2 := def]. Compiler evaluate: d2. ^ encoder global: (cue environment bindingOf: sym) name: sym! ! !Parser methodsFor: 'primitives' stamp: 'cwp 12/27/2012 11:46' prior: 37184567! externalFunctionDeclaration "Parse the function declaration for a call to an external library." | descriptorClass callType modifier retType externalName args argType module fn | descriptorClass := cue environment valueOf: #ExternalFunction ifAbsent: [^ false]. callType := descriptorClass callingConventionFor: here. callType == nil ifTrue:[^false]. [modifier := descriptorClass callingConventionModifierFor: token. modifier notNil] whileTrue: [self advance. callType := callType bitOr: modifier]. "Parse return type" self advance. retType := self externalType: descriptorClass. retType == nil ifTrue:[^self expected:'return type']. "Parse function name or index" externalName := here. (self match: #string) ifTrue:[externalName := externalName asSymbol] ifFalse:[(self match:#number) ifFalse:[^self expected:'function name or index']]. (self matchToken: #'(') ifFalse:[^self expected:'argument list']. args := WriteStream on: Array new. [here == #')'] whileFalse:[ argType := self externalType: descriptorClass. argType == nil ifTrue:[^self expected:'argument']. argType isVoid & argType isPointerType not ifFalse:[args nextPut: argType]. ]. (self matchToken: #')') ifFalse:[^self expected:')']. (self matchToken: 'module:') ifTrue:[ module := here. (self match: #string) ifFalse:[^self expected: 'String']. module := module asSymbol]. Smalltalk at: #ExternalLibraryFunction ifPresent:[:xfn| fn := xfn name: externalName module: module callType: callType returnType: retType argumentTypes: args contents. self allocateLiteral: fn. ]. (self matchToken: 'error:') ifTrue: [| errorCodeVariable | errorCodeVariable := here. (hereType == #string or: [hereType == #word]) ifFalse:[^self expected: 'error code (a variable or string)']. self advance. self addPragma: (Pragma keyword: #primitive:error: arguments: (Array with: 120 with: errorCodeVariable)). fn ifNotNil: [fn setErrorCodeName: errorCodeVariable]] ifFalse: [self addPragma: (Pragma keyword: #primitive: arguments: #(120))]. ^true ! ! !Parser methodsFor: 'error handling' stamp: 'cwp 12/27/2012 10:19' prior: 58306169! interactive "Answer true if compilation is interactive" ^ cue requestor notNil! ! !Parser methodsFor: 'error handling' stamp: 'cwp 12/27/2012 10:22' prior: 58137223! notify: string at: location cue requestor isNil ifTrue: [(encoder == self or: [encoder isNil]) ifTrue: [^ self fail "failure setting up syntax error"]. SyntaxErrorNotification inClass: encoder classEncoding category: cue category withCode: (source contents asText copyReplaceFrom: location to: location - 1 with: ((string , ' ->') asText allBold addAttribute: TextColor red; yourself)) doitFlag: doitFlag errorMessage: string location: location] ifFalse: [cue requestor notify: string , ' ->' at: location in: source]. ^self fail! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:17' prior: 34177108! pasteTempAtMethodLevel: name | insertion delta theTextString characterBeforeMark | theTextString := cue requestor text string. characterBeforeMark := theTextString at: tempsMark-1 ifAbsent: [$ ]. (theTextString at: tempsMark) = $| ifTrue: [ "Paste it before the second vertical bar" insertion := name, ' '. characterBeforeMark isSeparator ifFalse: [ insertion := ' ', insertion]. delta := 0. ] ifFalse: [ "No bars - insert some with CR, tab" insertion := '| ' , name , ' |',String cr. delta := 2. "the bar and CR" characterBeforeMark = Character tab ifTrue: [ insertion := insertion , String tab. delta := delta + 1. "the tab" ]. ]. tempsMark := tempsMark + (self substituteWord: insertion wordInterval: (tempsMark to: tempsMark-1) offset: 0) - delta! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:16' prior: 52095305! queryUndefined | varStart varName | varName := parseNode key. varStart := self endOfLastToken + requestorOffset - varName size + 1. cue requestor selectFrom: varStart to: varStart + varName size - 1; select. (UndefinedVariable name: varName) ifFalse: [^ self fail]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:15' prior: 38599341! removeEmptyTempDeclarationsFrom: methodNode | sourceCode madeChanges tempsMarkHolder | sourceCode := cue requestor text asString. tempsMarkHolder := self collectTemporaryDeclarationsFrom: methodNode. madeChanges := false. tempsMarkHolder do: [ :currentBlock | | tempsMarkChar0 tempsMarkChar1 tempsMarkChar2 end start | tempsMarkChar0 := (sourceCode at: currentBlock tempsMark). tempsMarkChar1 := (sourceCode at: currentBlock tempsMark - 1). tempsMarkChar2 := (sourceCode at: currentBlock tempsMark - 2). tempsMarkChar0 = $| & tempsMarkChar1 = $| ifTrue: [ end := currentBlock tempsMark. start := end - 1]. tempsMarkChar0 = $| & tempsMarkChar1 = $ & tempsMarkChar2 = $| ifTrue: [ end := currentBlock tempsMark. start := end - 2]. start notNil & end notNil ifTrue: [ | lineStart lineEnd | lineStart := 1 + (sourceCode lastIndexOf: Character cr startingAt: start - 1 ifAbsent: [ 0 ]). lineEnd := sourceCode indexOf: Character cr startingAt: end + 1 ifAbsent: [ sourceCode size ]. ((sourceCode indexOfAnyOf: CharacterSet nonSeparators startingAt: lineStart) >= start and: [ (sourceCode indexOfAnyOf: CharacterSet nonSeparators startingAt: end + 1) > lineEnd ]) ifTrue: [ start := lineStart. end := lineEnd ]. cue requestor correctFrom: start to: end with: ''. madeChanges := true. currentBlock tempsMark: nil ] ]. madeChanges ifTrue: [ReparseAfterSourceEditing signal]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:15' prior: 38561281! removeUnusedTemporaryNamed: temp from: str lookingAt: currentBlock movingTempMarksOf: someBlocks | start end | end := currentBlock tempsMark - 1. ["Beginning at right temp marker..." start := end - temp size + 1. end < temp size or: [ (str at: start) = $| ] or: [ temp = (str copyFrom: start to: end) and: [ ((str at: start - 1) = $| | (str at: start - 1) isSeparator) & ((str at: end + 1) = $| | (str at: end + 1) isSeparator) ] ]] whileFalse: [ "Search left for the unused temp" end := cue requestor nextTokenFrom: end direction: -1 ]. (end < temp size or: [ (str at: start) = $| ]) ifFalse: [(str at: start - 1) = $ ifTrue: [ start := start - 1 ]. cue requestor correctFrom: start to: end with: ''. someBlocks do: [ :aBlock | aBlock tempsMark: aBlock tempsMark - (end - start + 1)]. ^true ]. ^false! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:14' prior: 38562194! removeUnusedTemps: methodNode "Scan for unused temp names, and prompt the user about the prospect of removing each one found" | madeChanges tempsMarkHolder unusedTempNames tempMarkHoldersToChange | madeChanges := false. tempMarkHoldersToChange := OrderedCollection new. tempsMarkHolder := self collectTemporaryDeclarationsFrom: methodNode. unusedTempNames := encoder unusedTempNames select: [ :temp | (encoder lookupVariable: temp ifAbsent: [ ]) isUndefTemp and: [ self queriedUnusedTemporaries at: temp ifAbsentPut: [UnusedVariable name: temp] ]]. tempsMarkHolder do: [ :currentBlock | tempMarkHoldersToChange add: currentBlock. unusedTempNames do: [ :temp | (self removeUnusedTemporaryNamed: temp from: cue requestor text asString lookingAt: currentBlock movingTempMarksOf: tempMarkHoldersToChange) ifTrue: [ madeChanges := true ]]]. madeChanges ifTrue: [ self removeEmptyTempDeclarationsFrom: methodNode. ReparseAfterSourceEditing signal ]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:14' prior: 34179326! substituteWord: correctWord wordInterval: spot offset: o "Substitute the correctSelector into the (presumed interactive) receiver. Update requestorOffset based on the delta size and answer the updated offset." cue requestor correctFrom: spot first + o to: spot last + o with: correctWord. requestorOffset := requestorOffset + correctWord size - spot size. ^o + correctWord size - spot size! ! !Parser methodsFor: 'expression types' stamp: 'cwp 12/27/2012 10:14' prior: 34179807! temporaries " [ '|' (variable)* '|' ]" | vars theActualText | (self match: #verticalBar) ifFalse: ["no temps" doitFlag ifTrue: [tempsMark := self interactive ifTrue: [cue requestor selectionInterval first] ifFalse: [1]. ^ #()]. tempsMark := hereMark "formerly --> prevMark + prevToken". tempsMark > 0 ifTrue: [theActualText := source contents. [tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]] whileTrue: [tempsMark := tempsMark + 1]]. ^ #()]. vars := OrderedCollection new. [hereType == #word] whileTrue: [vars addLast: (encoder bindTemp: self advance)]. (self match: #verticalBar) ifTrue: [tempsMark := prevMark. ^ vars]. ^ self expected: 'Vertical bar' ! ! !Parser methodsFor: 'expression types' stamp: 'cwp 12/27/2012 10:14' prior: 34180638! temporariesIn: methodSelector " [ '|' (variable)* '|' ]" | vars theActualText | (self match: #verticalBar) ifFalse: ["no temps" doitFlag ifTrue: [tempsMark := self interactive ifTrue: [cue requestor selectionInterval first] ifFalse: [1]. ^ #()]. tempsMark := hereMark "formerly --> prevMark + prevToken". tempsMark > 0 ifTrue: [theActualText := source contents. [tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]] whileTrue: [tempsMark := tempsMark + 1]]. ^ #()]. vars := OrderedCollection new. [hereType == #word] whileTrue: [vars addLast: (encoder bindTemp: self advance in: methodSelector)]. (self match: #verticalBar) ifTrue: [tempsMark := prevMark. ^ vars]. ^ self expected: 'Vertical bar'! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 10:11' prior: 53971863! compiledMethodFor: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: logFlag "Compiles the sourceStream into a parse tree, then generates code into a method, and answers it. If receiver is not nil, then the text can refer to instance variables of that receiver (the Inspector uses this). If aContext is not nil, the text can refer to temporaries in that context (the Debugger uses this). If aRequestor is not nil, then it will receive a notify:at: message before the attempt to evaluate is aborted." | methodNode method theClass | theClass := (aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class. self from: textOrStream class: theClass context: aContext notifying: aRequestor. methodNode := self translate: sourceStream noPattern: true ifFail: [^failBlock value]. method := self interactive ifTrue: [ methodNode generateWithTempNames ] ifFalse: [methodNode generate]. logFlag ifTrue: [SystemChangeNotifier uniqueInstance evaluated: sourceStream contents context: aContext]. ^method! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/27/2012 11:33' prior: 34363593! format: aStream noPattern: noPattern ifFail: failBlock ^(self parser parse: aStream cue: cue noPattern: noPattern ifFail: [^failBlock value]) preen! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/27/2012 10:08' prior: 58306325! interactive "Answer true if compilation is interactive" ^ cue requestor notNil! ! !Compiler methodsFor: 'error handling' stamp: 'cwp 12/27/2012 10:10' prior: 50779387! notify: aString at: location "Refer to the comment in Object|notify:." ^ cue requestor == nil ifTrue: [SyntaxErrorNotification inClass: cue getClass category: cue category withCode: (sourceStream contents copyReplaceFrom: location to: location - 1 with: aString) doitFlag: false errorMessage: aString location: location] ifFalse: [cue requestor notify: aString at: location in: sourceStream]! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 11:34' prior: 50777201! parse: textOrStream in: aClass notifying: req "Compile the argument, textOrStream, with respect to the class, aClass, and answer the MethodNode that is the root of the resulting parse tree. Notify the argument, req, if an error occurs. The failBlock is defaulted to an empty block." self from: textOrStream class: aClass context: nil notifying: req. ^self parser parse: sourceStream cue: cue noPattern: false ifFail: []! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 10:09' prior: 36332471! parser parser ifNil: [parser := (cue getClass ifNil: [self class]) newParser]. ^parser! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/27/2012 11:37' prior: 50780779! translate: aStream noPattern: noPattern ifFail: failBlock ^self parser parse: aStream cue: cue noPattern: noPattern ifFail: [^failBlock value]! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 11:37' prior: 19124095! translate: aStream noPattern: noPattern ifFail: failBlock parser: parser | tree | tree := parser parse: aStream cue: cue noPattern: noPattern ifFail: [^ failBlock value]. ^ tree! ! !Encoder methodsFor: 'results' stamp: 'cwp 12/27/2012 10:26' prior: 50999892! associationForClass | assoc | assoc := self environment associationAt: cue getClass name ifAbsent: [nil]. ^assoc value == cue getClass ifTrue: [assoc] ifFalse: [Association new value: cue getClass]! ! !Encoder methodsFor: 'temps' stamp: 'cwp 12/27/2012 10:25' prior: 20148386! bindTemp: name in: methodSelector "Declare a temporary; error not if a field or class variable." scopeTable at: name ifPresent:[:node| "When non-interactive raise the error only if its a duplicate" (node isTemp or:[requestor interactive]) ifTrue:[^self notify:'Name is already defined'] ifFalse:[Transcript show: '(', name, ' is shadowed in "' , cue getClass printString , '>>' , methodSelector printString , '")']]. ^self reallyBind: name! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:25' prior: 20149084! classEncoding "This is a hack so that the parser may findout what class it was parsing for when it wants to create a syntax error view." ^ cue getClass! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:39' prior: 20138819! encodeLiteral: object ^self name: object key: (cue literalScannedAs: object notifying: self) class: LiteralNode type: LdLitType set: litSet! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:40' prior: 20139010! encodeSelector: aSelector ^self name: aSelector key: aSelector class: SelectorNode type: SendType set: selectorSet! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:40' prior: 58545123! environment "Answer the environment of the current compilation context, be it in a class or global (e.g. a workspace)" ^cue environment! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 11:41' prior: 50994497! lookupInPools: varName ifFound: assocBlock ^Symbol hasInterned: varName ifTrue: [:sym| (cue bindingOf: sym) ifNil: [^false] ifNotNil: [:assoc| assocBlock value: assoc]]! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:24' prior: 51004306! possibleNamesFor: proposedName | results | results := cue getClass possibleVariablesFor: proposedName continuedFrom: nil. ^ proposedName correctAgainst: nil continuedFrom: results. ! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:24' prior: 50995012! possibleVariablesFor: proposedVariable | results | results := proposedVariable correctAgainstDictionary: scopeTable continuedFrom: nil. proposedVariable first canBeGlobalVarInitial ifTrue: [ results := cue getClass possibleVariablesFor: proposedVariable continuedFrom: results ]. ^ proposedVariable correctAgainst: nil continuedFrom: results. ! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:42' prior: 51002830! undeclared: name | sym | requestor interactive ifTrue: [requestor requestor == #error: ifTrue: [requestor error: 'Undeclared']. ^self notify: 'Undeclared']. "Allow knowlegeable clients to squash the undeclared warning if they want (e.g. Diffing pretty printers that are simply formatting text). As this breaks compilation it should only be used by clients that want to discard the result of the compilation. To squash the warning use e.g. [Compiler format: code in: class notifying: nil decorated: false] on: UndeclaredVariableWarning do: [:ex| ex resume: false]" sym := name asSymbol. ^(UndeclaredVariableWarning new name: name selector: selector class: cue getClass) signal ifTrue: [| undeclared | undeclared := cue environment undeclared. undeclared at: sym put: nil. self global: (undeclared associationAt: sym) name: sym] ifFalse: [self global: (Association key: sym) name: sym]! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:23' prior: 51006007! warnAboutShadowed: name requestor addWarning: name,' is shadowed'. selector ifNotNil: [Transcript cr; show: cue getClass name,'>>', selector, '(', name,' is shadowed)']! ! "Compiler"! !SmalltalkImage methodsFor: 'housekeeping' stamp: 'cwp 6/22/2012 15:56' prior: 58497062! cleanOutUndeclared globals undeclared removeUnreferencedKeys! ! !SmalltalkImage methodsFor: 'special objects' stamp: 'cwp 6/22/2012 09:01' prior: 40515090! recreateSpecialObjectsArray "Smalltalk recreateSpecialObjectsArray" "To external package developers: **** DO NOT OVERRIDE THIS METHOD. ***** If you are writing a plugin and need additional special object(s) for your own use, use addGCRoot() function and use own, separate special objects registry " "The Special Objects Array is an array of objects used by the Squeak virtual machine. Its contents are critical and accesses to it by the VM are unchecked, so don't even think of playing here unless you know what you are doing." | newArray | newArray := Array new: 56. "Nil false and true get used throughout the interpreter" newArray at: 1 put: nil. newArray at: 2 put: false. newArray at: 3 put: true. "This association holds the active process (a ProcessScheduler)" newArray at: 4 put: (self bindingOf: #Processor). "Numerous classes below used for type checking and instantiation" newArray at: 5 put: Bitmap. newArray at: 6 put: SmallInteger. newArray at: 7 put: ByteString. newArray at: 8 put: Array. newArray at: 9 put: Smalltalk. newArray at: 10 put: Float. newArray at: 11 put: MethodContext. newArray at: 12 put: BlockContext. newArray at: 13 put: Point. newArray at: 14 put: LargePositiveInteger. newArray at: 15 put: Display. newArray at: 16 put: Message. newArray at: 17 put: CompiledMethod. newArray at: 18 put: (self specialObjectsArray at: 18). "(low space Semaphore)" newArray at: 19 put: Semaphore. newArray at: 20 put: Character. newArray at: 21 put: #doesNotUnderstand:. newArray at: 22 put: #cannotReturn:. newArray at: 23 put: nil. "This is the process signalling low space." "An array of the 32 selectors that are compiled as special bytecodes, paired alternately with the number of arguments each takes." newArray at: 24 put: #( #+ 1 #- 1 #< 1 #> 1 #<= 1 #>= 1 #= 1 #~= 1 #* 1 #/ 1 #\\ 1 #@ 1 #bitShift: 1 #// 1 #bitAnd: 1 #bitOr: 1 #at: 1 #at:put: 2 #size 0 #next 0 #nextPut: 1 #atEnd 0 #== 1 #class 0 #blockCopy: 1 #value 0 #value: 1 #do: 1 #new 0 #new: 1 #x 0 #y 0 ). "An array of the 255 Characters in ascii order. Cog inlines table into machine code at: prim so do not regenerate it." newArray at: 25 put: (self specialObjectsArray at: 25). newArray at: 26 put: #mustBeBoolean. newArray at: 27 put: ByteArray. newArray at: 28 put: Process. "An array of up to 31 classes whose instances will have compact headers" newArray at: 29 put: self compactClassesArray. newArray at: 30 put: (self specialObjectsArray at: 30). "(delay Semaphore)" newArray at: 31 put: (self specialObjectsArray at: 31). "(user interrupt Semaphore)" "Entries 32 - 34 unreferenced. Previously these contained prototype instances to be copied for fast initialization" newArray at: 32 put: nil. "was (Float new: 2)" newArray at: 33 put: nil. "was (LargePositiveInteger new: 4)" newArray at: 34 put: nil. "was Point new" newArray at: 35 put: #cannotInterpret:. "Note: This must be fixed once we start using context prototypes (yeah, right)" "(MethodContext new: CompiledMethod fullFrameSize)." newArray at: 36 put: (self specialObjectsArray at: 36). "Is the prototype MethodContext (unused by the VM)" newArray at: 37 put: BlockClosure. "(BlockContext new: CompiledMethod fullFrameSize)." newArray at: 38 put: (self specialObjectsArray at: 38). "Is the prototype BlockContext (unused by the VM)" From noreply at buildbot.pypy.org Fri May 3 14:53:38 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 3 May 2013 14:53:38 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changed tracing prefixes from words to symbols to alleviate reading Message-ID: <20130503125338.589FB1C13BD@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r370:b080c3949fe4 Date: 2013-05-03 14:48 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/b080c3949fe4/ Log: changed tracing prefixes from words to symbols to alleviate reading diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -347,7 +347,7 @@ func = primitives.prim_holder.prim_table[code] # ################################################################## if interp.trace: - print "%s calling primitive %d \t(in #%s, named #%s)" % ( + print "%s-> primitive %d \t(in #%s, named #%s)" % ( ' ' * (interp.max_stack_depth - interp.remaining_stack_depth), code, self.w_method()._likely_methodname, w_selector.as_string()) try: @@ -411,7 +411,7 @@ # assert self._stack_ptr == self.tempsize() if interp.trace: - print '%sreturning %s' % (interp.padding(), return_value.as_repr_string()) + print '%s<- %s' % (interp.padding(), return_value.as_repr_string()) raise Return(return_value, s_return_to) def returnReceiver(self, interp, current_bytecode): From noreply at buildbot.pypy.org Fri May 3 14:53:40 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 3 May 2013 14:53:40 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: merge ci-fix Message-ID: <20130503125340.22E3D1C02DA@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r371:66a8f9a4cd9e Date: 2013-05-03 14:49 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/66a8f9a4cd9e/ Log: merge ci-fix diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -214,13 +214,14 @@ callback=(lambda x: subprocess.Popen(["mv", "Squeak-4.10.2.2614-linux_i386", "stackvm"]).wait()) ) ], - arguments=['-vm-display-X11', '-headless', "images/%s.image" % SqueakImage, '../benchmarks.st'], + arguments=['-vm-display-null', "images/%s.image" % SqueakImage, '../benchmarks.st'], commitid=cogid ) RSqueakVM = Project( "lang-smalltalk", executables=[ - Executable("targetimageloadingsmalltalk-c", "./targetimageloadingsmalltalk-c") + Executable("rsqueakvm", "./targetimageloadingsmalltalk-c"), + Executable("rsqueakvm-nojit", "./targetimageloadingsmalltalk-nojit-c") ], arguments=["images/%s.image" % SqueakImage, '-m', 'runSPyBenchmarks'] ) From noreply at buildbot.pypy.org Fri May 3 21:59:02 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 3 May 2013 21:59:02 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed one of the problems with the last of the four shootout tests used by eliot: renamed highest_priority_process to pop_highest_priority_process to indicate the resulting state changes Message-ID: <20130503195902.8D4C61C1439@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r373:5dddfd278ce6 Date: 2013-05-03 20:11 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/5dddfd278ce6/ Log: fixed one of the problems with the last of the four shootout tests used by eliot: renamed highest_priority_process to pop_highest_priority_process to indicate the resulting state changes diff --git a/spyvm/test/test_wrapper.py b/spyvm/test/test_wrapper.py --- a/spyvm/test/test_wrapper.py +++ b/spyvm/test/test_wrapper.py @@ -216,15 +216,15 @@ assert semaphore.excess_signals() == 1 def test_highest_priority(self): - py.test.raises(FatalError, wrapper.scheduler(space).highest_priority_process) + py.test.raises(FatalError, wrapper.scheduler(space).pop_highest_priority_process) process, old_process = self.make_processes(4, 2, space.w_false) process.put_to_sleep() old_process.put_to_sleep() - highest = wrapper.scheduler(space).highest_priority_process() + highest = wrapper.scheduler(space).pop_highest_priority_process() assert highest is process._w_self - highest = wrapper.scheduler(space).highest_priority_process() + highest = wrapper.scheduler(space).pop_highest_priority_process() assert highest is old_process._w_self - py.test.raises(FatalError, wrapper.scheduler(space).highest_priority_process) + py.test.raises(FatalError, wrapper.scheduler(space).pop_highest_priority_process) def test_semaphore_wait(self): semaphore = new_semaphore() diff --git a/spyvm/wrapper.py b/spyvm/wrapper.py --- a/spyvm/wrapper.py +++ b/spyvm/wrapper.py @@ -104,7 +104,7 @@ def suspend(self, w_current_frame): if self.is_active_process(): assert self.my_list().is_same_object(self.space.w_nil) - w_process = scheduler(self.space).highest_priority_process() + w_process = scheduler(self.space).pop_highest_priority_process() self.store_suspended_context(w_current_frame) return ProcessWrapper(self.space, w_process).activate() else: @@ -176,6 +176,18 @@ return ProcessListWrapper(self.space, lists.read(priority)) + def pop_highest_priority_process(self): + w_lists = self.priority_list() + # Asserts as W_PointersObjectonion in the varnish. + lists = Wrapper(self.space, w_lists) + + for i in range(w_lists.size() - 1, -1, -1): + process_list = ProcessListWrapper(self.space, lists.read(i)) + if not process_list.is_empty_list(): + return process_list.remove_first_link_of_list() + + raise FatalError("Scheduler could not find a runnable process") + def highest_priority_process(self): w_lists = self.priority_list() # Asserts as W_PointersObjectonion in the varnish. @@ -184,7 +196,7 @@ for i in range(w_lists.size() - 1, -1, -1): process_list = ProcessListWrapper(self.space, lists.read(i)) if not process_list.is_empty_list(): - return process_list.remove_first_link_of_list() + return process_list.first_link() raise FatalError("Scheduler could not find a runnable process") diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -12,6 +12,8 @@ def _run_benchmark(interp, number, benchmark): scheduler = wrapper.scheduler(interp.space) w_hpp = scheduler.highest_priority_process() + if space.unwrap_int(scheduler.active_process().fetch(space, 2)) > space.unwrap_int(w_hpp.fetch(space, 2)): + w_hpp = scheduler.active_process() assert isinstance(w_hpp, model.W_PointersObject) w_benchmark_proc = model.W_PointersObject( interp.space, @@ -34,7 +36,7 @@ # third variable is priority priority = space.unwrap_int(w_hpp.fetch(space, 2)) / 2 + 1 # Priorities below 10 are not allowed in newer versions of Squeak. - priority = max(10, priority) + priority = max(11, priority) w_benchmark_proc.store(space, 2, space.wrap_int(priority)) # make process eligible for scheduling From noreply at buildbot.pypy.org Fri May 3 21:59:01 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 3 May 2013 21:59:01 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added may_context_switch to stack frame to enable primitives 221, 222: valueNoContextSwitch(:) Message-ID: <20130503195901.6AC5F1C13E5@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r372:854e627f1b25 Date: 2013-05-03 20:09 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/854e627f1b25/ Log: added may_context_switch to stack frame to enable primitives 221, 222: valueNoContextSwitch(:) diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -83,9 +83,9 @@ print "====== Switch from: %s to: %s ======" % (s_new_context.short_str(0), p.s_new_context.short_str(0)) s_new_context = p.s_new_context - def c_loop(self, s_context): + def c_loop(self, s_context, may_context_switch=True): old_pc = 0 - if not jit.we_are_jitted(): + if not jit.we_are_jitted() and may_context_switch: self.quick_check_for_interrupt(s_context) while True: pc = s_context.pc() @@ -118,7 +118,7 @@ decr_by = int(trace_length // 100) return max(decr_by, 1) - def stack_frame(self, s_new_frame): + def stack_frame(self, s_new_frame, may_context_switch=True): if not self._loop: return s_new_frame # this test is done to not loop in test, # but rather step just once where wanted @@ -127,7 +127,7 @@ self.remaining_stack_depth -= 1 try: - retval = self.c_loop(s_new_frame) + retval = self.c_loop(s_new_frame, may_context_switch) finally: self.remaining_stack_depth += 1 return retval diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -51,7 +51,8 @@ pos_32bit_int = object() def expose_primitive(code, unwrap_spec=None, no_result=False, - result_is_new_frame=False, clean_stack=True, compiled_method=False): + result_is_new_frame=False, may_context_switch=True, + clean_stack=True, compiled_method=False): # heuristics to give it a nice name name = None for key, value in globals().iteritems(): @@ -68,7 +69,7 @@ wrapped = wrap_primitive( unwrap_spec=unwrap_spec, no_result=no_result, - result_is_new_frame=result_is_new_frame, + result_is_new_frame=result_is_new_frame, may_context_switch=may_context_switch, clean_stack=clean_stack, compiled_method=compiled_method )(func) wrapped.func_name = "wrap_prim_" + name @@ -79,12 +80,14 @@ def wrap_primitive(unwrap_spec=None, no_result=False, - result_is_new_frame=False, clean_stack=True, - compiled_method=False): + result_is_new_frame=False, may_context_switch=True, + clean_stack=True, compiled_method=False): # some serious magic, don't look from rpython.rlib.unroll import unrolling_iterable assert not (no_result and result_is_new_frame) + assert may_context_switch or result_is_new_frame + # Because methods always have a receiver, an unwrap_spec of [] is a bug assert unwrap_spec is None or unwrap_spec @@ -96,7 +99,7 @@ else: w_result = func(interp, s_frame, argument_count_m1) if result_is_new_frame: - return interp.stack_frame(w_result) + return interp.stack_frame(w_result, may_context_switch) if not no_result: assert w_result is not None s_frame.push(w_result) @@ -144,7 +147,7 @@ if clean_stack: # happens only if no exception occurs! s_frame.pop_n(len_unwrap_spec) - return interp.stack_frame(s_new_frame) + return interp.stack_frame(s_new_frame, may_context_switch) else: w_result = func(interp, s_frame, *args) # After calling primitive, reload context-shadow in case it @@ -1278,8 +1281,7 @@ return w_context -def activateClosure(interp, s_frame, w_block, args_w, mayContextSwitch=True): - # XXX mayContextSwitch is ignored +def activateClosure(interp, s_frame, w_block, args_w): space = interp.space if not w_block.getclass(space).is_same_object( space.w_BlockClosure): @@ -1327,13 +1329,13 @@ def func(interp, s_frame, w_block_closure, args_w): return activateClosure(interp, s_frame, w_block_closure, args_w) - at expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH, unwrap_spec=[object], result_is_new_frame=True) + at expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH, unwrap_spec=[object], result_is_new_frame=True, may_context_switch=False) def func(interp, s_frame, w_block_closure): - return activateClosure(interp, s_frame, w_block_closure, [], mayContextSwitch=False) + return activateClosure(interp, s_frame, w_block_closure, []) - at expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH_, unwrap_spec=[object, object], result_is_new_frame=True) + at expose_primitive(CLOSURE_VALUE_NO_CONTEXT_SWITCH_, unwrap_spec=[object, object], result_is_new_frame=True, may_context_switch=False) def func(interp, s_frame, w_block_closure, w_a0): - return activateClosure(interp, s_frame, w_block_closure, [w_a0], mayContextSwitch=False) + return activateClosure(interp, s_frame, w_block_closure, [w_a0]) # ___________________________________________________________________________ # Override the default primitive to give latitude to the VM in context management. diff --git a/spyvm/test/test_interpreter.py b/spyvm/test/test_interpreter.py --- a/spyvm/test/test_interpreter.py +++ b/spyvm/test/test_interpreter.py @@ -1003,7 +1003,7 @@ assert False class StackTestInterpreter(interpreter.Interpreter): - def stack_frame(self, w_frame): + def stack_frame(self, w_frame, may_interrupt=True): import sys stack_depth = self.max_stack_depth - self.remaining_stack_depth for i in range(stack_depth + 1): diff --git a/spyvm/test/test_wrapper.py b/spyvm/test/test_wrapper.py --- a/spyvm/test/test_wrapper.py +++ b/spyvm/test/test_wrapper.py @@ -261,7 +261,7 @@ with py.test.raises(interpreter.ProcessSwitch): semaphore.wait(currentcontext) - + assert wrapper.scheduler(space).active_process() is process._w_self semaphore.signal(currentcontext) assert wrapper.scheduler(space).active_process() is process._w_self From noreply at buildbot.pypy.org Fri May 3 23:53:02 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 3 May 2013 23:53:02 +0200 (CEST) Subject: [pypy-commit] pypy py3k: PyBytes_FromStringAndSize(NULL, n) was returning a Unicode string! Message-ID: <20130503215302.DA2771C13E5@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: py3k Changeset: r63821:e59ac0bca759 Date: 2013-05-03 23:46 +0200 http://bitbucket.org/pypy/pypy/changeset/e59ac0bca759/ Log: PyBytes_FromStringAndSize(NULL, n) was returning a Unicode string! Test and fix. diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py --- a/pypy/module/cpyext/bytesobject.py +++ b/pypy/module/cpyext/bytesobject.py @@ -100,7 +100,7 @@ """ py_str = rffi.cast(PyBytesObject, py_obj) s = rffi.charpsize2str(py_str.c_buffer, py_str.c_size) - w_obj = space.wrap(s) + w_obj = space.wrapbytes(s) track_reference(space, py_obj, w_obj) return w_obj diff --git a/pypy/module/cpyext/test/test_bytesobject.py b/pypy/module/cpyext/test/test_bytesobject.py --- a/pypy/module/cpyext/test/test_bytesobject.py +++ b/pypy/module/cpyext/test/test_bytesobject.py @@ -77,7 +77,7 @@ ]) s = module.getbytes() assert len(s) == 4 - assert s == 'ab\x00c' + assert s == b'ab\x00c' From noreply at buildbot.pypy.org Fri May 3 23:53:01 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 3 May 2013 23:53:01 +0200 (CEST) Subject: [pypy-commit] pypy py3k: Fix test_compiler: pypy optimizes the code like CPython 3.3, Message-ID: <20130503215301.477851C13BD@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: py3k Changeset: r63820:c277866e4943 Date: 2013-05-03 22:21 +0200 http://bitbucket.org/pypy/pypy/changeset/c277866e4943/ Log: Fix test_compiler: pypy optimizes the code like CPython 3.3, and stores -0.0 in co_const. diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -717,6 +717,9 @@ class AppTestCompiler: + def setup_class(cls): + cls.w_runappdirect = cls.space.wrap(cls.runappdirect) + def test_bom_with_future(self): s = b'\xef\xbb\xbffrom __future__ import division\nx = 1/2' ns = {} @@ -738,12 +741,15 @@ assert type(ns['d'][0][0]) is complex def test_zeros_not_mixed(self): - import math + import math, sys code = compile("x = -0.0; y = 0.0", "", "exec") consts = code.co_consts - x, y = consts - assert isinstance(x, float) - assert math.copysign(1, x) == 1 + if not self.runappdirect or sys.version_info[:2] != (3, 2): + # Only CPython 3.2 does not store -0.0. + # PyPy implements 3.3 here. + x, y, z = consts + assert isinstance(x, float) and isinstance(y, float) + assert math.copysign(1, x) != math.copysign(1, y) ns = {} exec("z1, z2 = 0j, -0j", ns) assert math.atan2(ns["z1"].imag, -1.) == math.atan2(0., -1.) From noreply at buildbot.pypy.org Fri May 3 23:53:04 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 3 May 2013 23:53:04 +0200 (CEST) Subject: [pypy-commit] pypy py3k: My comments about py3k failing tests Message-ID: <20130503215304.4D74C1C13BD@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: py3k Changeset: r63822:634e55c1f144 Date: 2013-05-03 23:49 +0200 http://bitbucket.org/pypy/pypy/changeset/634e55c1f144/ Log: My comments about py3k failing tests diff --git a/pypy/TODO b/pypy/TODO --- a/pypy/TODO +++ b/pypy/TODO @@ -1,2 +1,41 @@ +TODO for the python3 test suite: -* ARM +* test_decimal: + In py3k, hash(-1) is now -2 (probably as an optimisation, because + PyObject_Hash() return -1 on exception). + It's important to be compatible, since other classes like Decimal + and Fractions have to return the same hashes for equivalent values. + IOW: int.__hash__ is part of the Python language specification. + +* test_fractions +* test_numeric_tower + float.__hash__ has changed as well. + +* test_float + nan = float('nan'); assert nan in [nan] + This has always been true in CPython, it is now guaranteed that the + containers use the "is" operator as an optimization. + Difficult in pypy because optimized containers are arrays of + unwrapped doubles. A possible solution is to special-case nan in + FloatListStrategy.unwrap(). + +* test_memoryview + Needs bytes/str changes. Probably easy. + +* test_peepholer + 'a in [1,2,3]' is rewritten as 'a in (1, 2, 3)' + and the tuple is a prebuilt constant. + Likewise, a set becomes a frozenset. + +* test_pep263 + Tracebacks should be able to print unicode source code. + +* test_sqlite + (Probably easy) Ports of CPython changeset fc6f90545cb4 and PyPy + 48d194e3ac07. + +* test_sys +* test_threading: + Missing sys.getswitchinterval(). + We would be interesting to implement the new thread switching + logic, it's a lot of work though. From noreply at buildbot.pypy.org Sat May 4 02:05:29 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:29 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: This branch introduces an Opcode class to deal with decoding bytecode Message-ID: <20130504000529.718B31C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63823:483f596960d2 Date: 2013-05-04 00:48 +0100 http://bitbucket.org/pypy/pypy/changeset/483f596960d2/ Log: This branch introduces an Opcode class to deal with decoding bytecode in rpython.flowspace in a more object-oriented way. From noreply at buildbot.pypy.org Sat May 4 02:05:30 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:30 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Simplify flowspace op creation Message-ID: <20130504000530.B542D1C1401@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63824:cd71cce3a8c8 Date: 2013-04-28 13:37 +0100 http://bitbucket.org/pypy/pypy/changeset/cd71cce3a8c8/ Log: Simplify flowspace op creation diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py --- a/rpython/flowspace/objspace.py +++ b/rpython/flowspace/objspace.py @@ -462,11 +462,15 @@ raise FlowingError(self.frame, self.wrap(message)) return self.wrap(value) +def make_impure_op(name, arity): + def generic_operator(self, *args_w): + assert len(args_w) == arity, name + " got the wrong number of arguments" + w_result = self.frame.do_operation_with_implicit_exceptions(name, *args_w) + return w_result + return generic_operator + def make_op(name, arity): """Add function operation to the flow space.""" - if getattr(FlowObjSpace, name, None) is not None: - return - op = None skip = False arithmetic = False @@ -474,11 +478,9 @@ if (name.startswith('del') or name.startswith('set') or name.startswith('inplace_')): - # skip potential mutators - skip = True + return make_impure_op(name, arity) elif name in ('id', 'hash', 'iter', 'userdel'): - # skip potential runtime context dependecies - skip = True + return make_impure_op(name, arity) elif name in ('repr', 'str'): rep = getattr(__builtin__, name) def op(obj): @@ -490,54 +492,50 @@ op = operation.FunctionByName[name] arithmetic = (name + '_ovf') in operation.FunctionByName - if not op and not skip: - raise ValueError("XXX missing operator: %s" % (name,)) - def generic_operator(self, *args_w): assert len(args_w) == arity, name + " got the wrong number of arguments" - if op: - args = [] - for w_arg in args_w: - try: - arg = self.unwrap_for_computation(w_arg) - except UnwrapException: - break + args = [] + for w_arg in args_w: + try: + arg = self.unwrap_for_computation(w_arg) + except UnwrapException: + break + else: + args.append(arg) + else: + # All arguments are constants: call the operator now + try: + result = op(*args) + except Exception, e: + etype = e.__class__ + msg = "%s%r always raises %s: %s" % ( + name, tuple(args), etype, e) + raise FlowingError(self.frame, msg) + else: + # don't try to constant-fold operations giving a 'long' + # result. The result is probably meant to be sent to + # an intmask(), but the 'long' constant confuses the + # annotator a lot. + if arithmetic and type(result) is long: + pass + # don't constant-fold getslice on lists, either + elif name == 'getslice' and type(result) is list: + pass + # otherwise, fine else: - args.append(arg) - else: - # All arguments are constants: call the operator now - try: - result = op(*args) - except Exception, e: - etype = e.__class__ - msg = "%s%r always raises %s: %s" % ( - name, tuple(args), etype, e) - raise FlowingError(self.frame, msg) - else: - # don't try to constant-fold operations giving a 'long' - # result. The result is probably meant to be sent to - # an intmask(), but the 'long' constant confuses the - # annotator a lot. - if arithmetic and type(result) is long: + try: + return self.wrap(result) + except WrapException: + # type cannot sanely appear in flow graph, + # store operation with variable result instead pass - # don't constant-fold getslice on lists, either - elif name == 'getslice' and type(result) is list: - pass - # otherwise, fine - else: - try: - return self.wrap(result) - except WrapException: - # type cannot sanely appear in flow graph, - # store operation with variable result instead - pass w_result = self.frame.do_operation_with_implicit_exceptions(name, *args_w) return w_result - - setattr(FlowObjSpace, name, generic_operator) + return generic_operator for (name, symbol, arity, specialnames) in operation.MethodTable: - make_op(name, arity) + if getattr(FlowObjSpace, name, None) is None: + setattr(FlowObjSpace, name, make_op(name, arity)) def build_flow(func, space=FlowObjSpace()): From noreply at buildbot.pypy.org Sat May 4 02:05:31 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:31 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Replace unwrap_for_computation() with Constant.foldable() Message-ID: <20130504000531.F27DA1C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63825:75c10594741f Date: 2013-05-01 16:49 +0100 http://bitbucket.org/pypy/pypy/changeset/75c10594741f/ Log: Replace unwrap_for_computation() with Constant.foldable() diff --git a/rpython/flowspace/model.py b/rpython/flowspace/model.py --- a/rpython/flowspace/model.py +++ b/rpython/flowspace/model.py @@ -3,6 +3,7 @@ # # the below object/attribute model evolved from # a discussion in Berlin, 4th of october 2003 +import types import py from rpython.tool.uid import uid, Hashable @@ -261,6 +262,7 @@ dummyname = 'v' namesdict = {dummyname : (dummyname, 0)} + @property def name(self): _name = self._name _nr = self._nr @@ -270,11 +272,10 @@ _nr = self._nr = nd[_name][1] nd[_name] = (_name, _nr + 1) return "%s%d" % (_name, _nr) - name = property(name) + @property def renamed(self): return self._name is not self.dummyname - renamed = property(renamed) def __init__(self, name=None): self._name = self.dummyname @@ -314,6 +315,9 @@ self._name = intern(name) self._nr = nr + def foldable(self): + return False + class Constant(Hashable): __slots__ = ["concretetype"] @@ -323,6 +327,25 @@ if concretetype is not None: self.concretetype = concretetype + def foldable(self): + to_check = self.value + if hasattr(to_check, 'im_self'): + to_check = to_check.im_self + if isinstance(to_check, (type, types.ClassType, types.ModuleType)): + # classes/types/modules are assumed immutable + return True + if (hasattr(to_check, '__class__') and + to_check.__class__.__module__ == '__builtin__'): + # builtin object + return True + # User-created instance + if hasattr(to_check, '_freeze_'): + assert to_check._freeze_() is True + return True + else: + # cannot count on it not mutating at runtime! + return False + class UnwrapException(Exception): """Attempted to unwrap a Variable.""" diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py --- a/rpython/flowspace/objspace.py +++ b/rpython/flowspace/objspace.py @@ -176,22 +176,6 @@ else: raise TypeError("not wrapped: " + repr(w_obj)) - def unwrap_for_computation(self, w_obj): - obj = self.unwrap(w_obj) - to_check = obj - if hasattr(to_check, 'im_self'): - to_check = to_check.im_self - if (not isinstance(to_check, (type, types.ClassType, types.ModuleType)) and - # classes/types/modules are assumed immutable - hasattr(to_check, '__class__') and to_check.__class__.__module__ != '__builtin__'): - frozen = hasattr(to_check, '_freeze_') - if frozen: - assert to_check._freeze_() is True - else: - # cannot count on it not mutating at runtime! - raise UnwrapException - return obj - def exception_issubclass_w(self, w_cls1, w_cls2): return self.is_true(self.issubtype(w_cls1, w_cls2)) @@ -291,12 +275,8 @@ return self.wrap(not self.is_true(w_obj)) def is_true(self, w_obj): - try: - obj = self.unwrap_for_computation(w_obj) - except UnwrapException: - pass - else: - return bool(obj) + if w_obj.foldable(): + return bool(w_obj.value) w_truthvalue = self.frame.do_operation('is_true', w_obj) return self.frame.guessbool(w_truthvalue) @@ -343,12 +323,8 @@ if w_name not in const_w: return self.frame.do_operation_with_implicit_exceptions('getattr', w_obj, w_name) - try: - obj = self.unwrap_for_computation(w_obj) - name = self.unwrap_for_computation(w_name) - except UnwrapException: - pass - else: + if w_obj.foldable() and w_name.foldable(): + obj, name = w_obj.value, w_name.value try: result = getattr(obj, name) except Exception, e: @@ -495,14 +471,8 @@ def generic_operator(self, *args_w): assert len(args_w) == arity, name + " got the wrong number of arguments" args = [] - for w_arg in args_w: - try: - arg = self.unwrap_for_computation(w_arg) - except UnwrapException: - break - else: - args.append(arg) - else: + if all(w_arg.foldable() for w_arg in args_w): + args = [w_arg.value for w_arg in args_w] # All arguments are constants: call the operator now try: result = op(*args) From noreply at buildbot.pypy.org Sat May 4 02:05:33 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:33 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Extract record_block() from FSFrame.build_flow() Message-ID: <20130504000533.45CDA1C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63826:84404950a8bf Date: 2013-04-28 16:02 +0100 http://bitbucket.org/pypy/pypy/changeset/84404950a8bf/ Log: Extract record_block() from FSFrame.build_flow() diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -488,39 +488,42 @@ self.pendingblocks = collections.deque([graph.startblock]) while self.pendingblocks: block = self.pendingblocks.popleft() - try: - self.recorder = self.recording(block) - while True: - self.last_instr = self.handle_bytecode(self.last_instr) - self.recorder.final_state = self.getstate() + self.record_block(block) - except ImplicitOperationError, e: - if isinstance(e.w_type, Constant): - exc_cls = e.w_type.value - else: - exc_cls = Exception - msg = "implicit %s shouldn't occur" % exc_cls.__name__ - w_type = Constant(AssertionError) - w_value = Constant(AssertionError(msg)) - link = Link([w_type, w_value], graph.exceptblock) - self.recorder.crnt_block.closeblock(link) + def record_block(self, block): + try: + self.recorder = self.recording(block) + while True: + self.last_instr = self.handle_bytecode(self.last_instr) + self.recorder.final_state = self.getstate() - except FSException, e: - if e.w_type is self.space.w_ImportError: - msg = 'import statement always raises %s' % e - raise ImportError(msg) - link = Link([e.w_type, e.w_value], graph.exceptblock) - self.recorder.crnt_block.closeblock(link) + except ImplicitOperationError, e: + if isinstance(e.w_type, Constant): + exc_cls = e.w_type.value + else: + exc_cls = Exception + msg = "implicit %s shouldn't occur" % exc_cls.__name__ + w_type = Constant(AssertionError) + w_value = Constant(AssertionError(msg)) + link = Link([w_type, w_value], self.graph.exceptblock) + self.recorder.crnt_block.closeblock(link) - except StopFlowing: - pass + except FSException, e: + if e.w_type is self.space.w_ImportError: + msg = 'import statement always raises %s' % e + raise ImportError(msg) + link = Link([e.w_type, e.w_value], self.graph.exceptblock) + self.recorder.crnt_block.closeblock(link) - except Return as exc: - w_result = exc.value - link = Link([w_result], graph.returnblock) - self.recorder.crnt_block.closeblock(link) + except StopFlowing: + pass - del self.recorder + except Return as exc: + w_result = exc.value + link = Link([w_result], self.graph.returnblock) + self.recorder.crnt_block.closeblock(link) + + self.recorder = None def mergeblock(self, currentblock, currentstate): next_instr = currentstate.next_instr From noreply at buildbot.pypy.org Sat May 4 02:05:34 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:34 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Simplify record_block() setup. Message-ID: <20130504000534.93BFA1C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63827:34743f1d56d2 Date: 2013-05-02 04:12 +0100 http://bitbucket.org/pypy/pypy/changeset/34743f1d56d2/ Log: Simplify record_block() setup. Kill FSFrame.recording() and dispatch its logic to Block methods. diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -55,25 +55,44 @@ pass class SpamBlock(Block): - # make slots optional, for debugging - if hasattr(Block, '__slots__'): - __slots__ = "dead framestate".split() - def __init__(self, framestate): Block.__init__(self, framestate.getvariables()) self.framestate = framestate self.dead = False + def make_recorder(self): + return BlockRecorder(self) + class EggBlock(Block): - # make slots optional, for debugging - if hasattr(Block, '__slots__'): - __slots__ = "prevblock booloutcome last_exception".split() - def __init__(self, inputargs, prevblock, booloutcome): Block.__init__(self, inputargs) self.prevblock = prevblock self.booloutcome = booloutcome + @property + def ancestor(self): + parent = self.prevblock + while isinstance(parent, EggBlock): + parent = parent.prevblock + return parent + + @property + def dead(self): + return self.ancestor.dead + + @property + def framestate(self): + return self.ancestor.framestate + + def make_recorder(self): + recorder = BlockRecorder(self) + curr = self + while isinstance(curr, EggBlock): + prev = curr.prevblock + recorder = Replayer(prev, curr.booloutcome, recorder) + curr = prev + return recorder + def extravars(self, last_exception=None, last_exc_value=None): self.last_exception = last_exception @@ -430,24 +449,6 @@ self.last_instr = state.next_instr self.blockstack = state.blocklist[:] - def recording(self, block): - """ Setup recording of the block and return the recorder. """ - parentblocks = [] - parent = block - while isinstance(parent, EggBlock): - parent = parent.prevblock - parentblocks.append(parent) - # parentblocks = [Egg, Egg, ..., Egg, Spam] not including block - if parent.dead: - raise StopFlowing - self.setstate(parent.framestate) - recorder = BlockRecorder(block) - prevblock = block - for parent in parentblocks: - recorder = Replayer(parent, prevblock.booloutcome, recorder) - prevblock = parent - return recorder - def record(self, spaceop): """Record an operation into the active block""" recorder = self.recorder @@ -488,11 +489,13 @@ self.pendingblocks = collections.deque([graph.startblock]) while self.pendingblocks: block = self.pendingblocks.popleft() - self.record_block(block) + if not block.dead: + self.record_block(block) def record_block(self, block): + self.setstate(block.framestate) + self.recorder = block.make_recorder() try: - self.recorder = self.recording(block) while True: self.last_instr = self.handle_bytecode(self.last_instr) self.recorder.final_state = self.getstate() From noreply at buildbot.pypy.org Sat May 4 02:05:35 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:35 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Merge FSFrame.record() into .do_operation() Message-ID: <20130504000535.C20981C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63828:fcd38d092db1 Date: 2013-05-02 04:14 +0100 http://bitbucket.org/pypy/pypy/changeset/fcd38d092db1/ Log: Merge FSFrame.record() into .do_operation() diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -449,21 +449,17 @@ self.last_instr = state.next_instr self.blockstack = state.blocklist[:] - def record(self, spaceop): - """Record an operation into the active block""" + def guessbool(self, w_condition, **kwds): + return self.recorder.guessbool(self, w_condition, **kwds) + + def do_operation(self, name, *args_w): recorder = self.recorder if getattr(recorder, 'final_state', None) is not None: self.mergeblock(recorder.crnt_block, recorder.final_state) raise StopFlowing - recorder.append(spaceop) - - def guessbool(self, w_condition, **kwds): - return self.recorder.guessbool(self, w_condition, **kwds) - - def do_operation(self, name, *args_w): spaceop = SpaceOperation(name, args_w, Variable()) spaceop.offset = self.last_instr - self.record(spaceop) + recorder.append(spaceop) return spaceop.result def do_operation_with_implicit_exceptions(self, name, *args_w): From noreply at buildbot.pypy.org Sat May 4 02:05:37 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:37 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Clean up exc_from_raise() Message-ID: <20130504000537.38AD51C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63829:33acc1d192dc Date: 2013-05-02 17:32 +0100 http://bitbucket.org/pypy/pypy/changeset/33acc1d192dc/ Log: Clean up exc_from_raise() diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py --- a/rpython/flowspace/objspace.py +++ b/rpython/flowspace/objspace.py @@ -216,36 +216,32 @@ return True return False - def exc_from_raise(self, w_type, w_value): + def exc_from_raise(self, w_arg1, w_arg2): """ Create a wrapped exception from the arguments of a raise statement. Returns an FSException object whose w_value is an instance of w_type. """ - if self.isinstance_w(w_type, self.w_type): + if self.isinstance_w(w_arg1, self.w_type): # this is for all cases of the form (Class, something) - if self.is_w(w_value, self.w_None): + if self.is_w(w_arg2, self.w_None): # raise Type: we assume we have to instantiate Type - w_value = self.call_function(w_type) - w_type = self.type(w_value) + w_value = self.call_function(w_arg1) else: - w_valuetype = self.type(w_value) - if self.exception_issubclass_w(w_valuetype, w_type): + w_valuetype = self.type(w_arg2) + if self.exception_issubclass_w(w_valuetype, w_arg1): # raise Type, Instance: let etype be the exact type of value - w_type = w_valuetype + w_value = w_arg2 else: # raise Type, X: assume X is the constructor argument - w_value = self.call_function(w_type, w_value) - w_type = self.type(w_value) + w_value = self.call_function(w_arg1, w_arg2) else: # the only case left here is (inst, None), from a 'raise inst'. - w_inst = w_type - w_instclass = self.type(w_inst) - if not self.is_w(w_value, self.w_None): + if not self.is_w(w_arg2, self.w_None): raise FSException(self.w_TypeError, self.wrap( "instance exception may not have a separate value")) - w_value = w_inst - w_type = w_instclass + w_value = w_arg1 + w_type = self.type(w_value) return FSException(w_type, w_value) def unpackiterable(self, w_iterable): From noreply at buildbot.pypy.org Sat May 4 02:05:38 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:38 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Create exc_wrap() Message-ID: <20130504000538.6C7801C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63830:9a3915380afb Date: 2013-05-02 18:08 +0100 http://bitbucket.org/pypy/pypy/changeset/9a3915380afb/ Log: Create exc_wrap() diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -507,11 +507,11 @@ link = Link([w_type, w_value], self.graph.exceptblock) self.recorder.crnt_block.closeblock(link) - except FSException, e: - if e.w_type is self.space.w_ImportError: - msg = 'import statement always raises %s' % e - raise ImportError(msg) - link = Link([e.w_type, e.w_value], self.graph.exceptblock) + except FSException as exc: + if exc.w_type == self.space.w_ImportError: + msg = 'import statement always raises %s' % exc + raise exc.w_value.value + link = Link([exc.w_type, exc.w_value], self.graph.exceptblock) self.recorder.crnt_block.closeblock(link) except StopFlowing: @@ -663,8 +663,8 @@ self.last_exception = operr raise operr else: - raise FSException(space.w_TypeError, - space.wrap("raise: no active exception to re-raise")) + raise space.exc_wrap(TypeError( + "raise: no active exception to re-raise")) w_value = space.w_None if nbargs >= 3: diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py --- a/rpython/flowspace/objspace.py +++ b/rpython/flowspace/objspace.py @@ -135,6 +135,11 @@ raise WrapException return Constant(obj) + def exc_wrap(self, exc): + w_value = self.wrap(exc) + w_type = self.wrap(type(exc)) + return FSException(w_type, w_value) + def int_w(self, w_obj): if isinstance(w_obj, Constant): val = w_obj.value @@ -238,7 +243,7 @@ else: # the only case left here is (inst, None), from a 'raise inst'. if not self.is_w(w_arg2, self.w_None): - raise FSException(self.w_TypeError, self.wrap( + raise self.exc_wrap(TypeError( "instance exception may not have a separate value")) w_value = w_arg1 w_type = self.type(w_value) @@ -292,7 +297,7 @@ try: v, next_unroller = it.step() except IndexError: - raise FSException(self.w_StopIteration, self.w_None) + raise self.exc_wrap(StopIteration()) else: frame.replace_in_stack(it, next_unroller) return self.wrap(v) @@ -341,8 +346,8 @@ def import_name(self, name, glob=None, loc=None, frm=None, level=-1): try: mod = __import__(name, glob, loc, frm, level) - except ImportError, e: - raise FSException(self.w_ImportError, self.wrap(str(e))) + except ImportError as e: + raise self.exc_wrap(e) return self.wrap(mod) def import_from(self, w_module, w_name): @@ -357,8 +362,8 @@ try: return self.wrap(getattr(w_module.value, w_name.value)) except AttributeError: - raise FSException(self.w_ImportError, - self.wrap("cannot import name '%s'" % w_name.value)) + raise self.exc_wrap(ImportError( + "cannot import name '%s'" % w_name.value)) def call_method(self, w_obj, methname, *arg_w): w_meth = self.getattr(w_obj, self.wrap(methname)) From noreply at buildbot.pypy.org Sat May 4 02:05:39 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:39 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Create Opcode class Message-ID: <20130504000539.AA67E1C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63831:3a1519f5a455 Date: 2013-05-02 06:11 +0100 http://bitbucket.org/pypy/pypy/changeset/3a1519f5a455/ Log: Create Opcode class diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -103,9 +103,19 @@ next_instr += 3 oparg = (oparg * 65536) | (hi * 256) | lo - opname = self.opnames[opcode] - return next_instr, opname, oparg + return next_instr, Opcode(opcode, oparg, pos) @property def is_generator(self): return bool(self.co_flags & CO_GENERATOR) + +OPNAMES = host_bytecode_spec.method_names + +class Opcode(object): + def __init__(self, opcode, arg, offset=-1): + self.name = OPNAMES[opcode] + self.arg = arg + self.offset = offset + + def eval(self, frame, next_instr): + return getattr(frame, self.name)(self.arg, next_instr) diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -575,9 +575,9 @@ break def handle_bytecode(self, next_instr): - next_instr, methodname, oparg = self.pycode.read(next_instr) + next_instr, opcode = self.pycode.read(next_instr) try: - res = getattr(self, methodname)(oparg, next_instr) + res = opcode.eval(self, next_instr) return res if res is not None else next_instr except FSException, operr: return self.handle_operation_error(operr) From noreply at buildbot.pypy.org Sat May 4 02:05:41 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:41 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Kill next_instr argument in FSFrame.OPCODE methods Message-ID: <20130504000541.238381C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63832:d27c6cf80457 Date: 2013-04-29 03:03 +0100 http://bitbucket.org/pypy/pypy/changeset/d27c6cf80457/ Log: Kill next_instr argument in FSFrame.OPCODE methods diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -3,6 +3,7 @@ """ from rpython.tool.stdlib_opcode import host_bytecode_spec from opcode import EXTENDED_ARG, HAVE_ARGUMENT +import opcode from rpython.flowspace.argument import Signature from rpython.flowspace.flowcontext import BytecodeCorruption @@ -83,10 +84,10 @@ Returns (next_instr, opname, oparg). """ co_code = self.co_code - opcode = ord(co_code[pos]) + opnum = ord(co_code[pos]) next_instr = pos + 1 - if opcode >= HAVE_ARGUMENT: + if opnum >= HAVE_ARGUMENT: lo = ord(co_code[next_instr]) hi = ord(co_code[next_instr+1]) next_instr += 2 @@ -94,16 +95,18 @@ else: oparg = 0 - while opcode == EXTENDED_ARG: - opcode = ord(co_code[next_instr]) - if opcode < HAVE_ARGUMENT: + while opnum == EXTENDED_ARG: + opnum = ord(co_code[next_instr]) + if opnum < HAVE_ARGUMENT: raise BytecodeCorruption lo = ord(co_code[next_instr+1]) hi = ord(co_code[next_instr+2]) next_instr += 3 oparg = (oparg * 65536) | (hi * 256) | lo - return next_instr, Opcode(opcode, oparg, pos) + if opnum in opcode.hasjrel: + oparg += next_instr + return next_instr, Opcode(opnum, oparg, pos) @property def is_generator(self): @@ -117,5 +120,5 @@ self.arg = arg self.offset = offset - def eval(self, frame, next_instr): - return getattr(frame, self.name)(self.arg, next_instr) + def eval(self, frame): + return getattr(frame, self.name)(self.arg) diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -577,7 +577,7 @@ def handle_bytecode(self, next_instr): next_instr, opcode = self.pycode.read(next_instr) try: - res = opcode.eval(self, next_instr) + res = opcode.eval(self) return res if res is not None else next_instr except FSException, operr: return self.handle_operation_error(operr) @@ -603,13 +603,13 @@ def getname_w(self, index): return Constant(self.pycode.names[index]) - def BAD_OPCODE(self, _, next_instr): + def BAD_OPCODE(self, _): raise FlowingError(self, "This operation is not RPython") - def BREAK_LOOP(self, oparg, next_instr): + def BREAK_LOOP(self, oparg): return self.unrollstack_and_jump(SBreakLoop.singleton) - def CONTINUE_LOOP(self, startofloop, next_instr): + def CONTINUE_LOOP(self, startofloop): unroller = SContinueLoop(startofloop) return self.unrollstack_and_jump(unroller) @@ -646,13 +646,13 @@ def cmp_exc_match(self, w_1, w_2): return self.space.newbool(self.space.exception_match(w_1, w_2)) - def COMPARE_OP(self, testnum, next_instr): + def COMPARE_OP(self, testnum): w_2 = self.popvalue() w_1 = self.popvalue() w_result = getattr(self, compare_method[testnum])(w_1, w_2) self.pushvalue(w_result) - def RAISE_VARARGS(self, nbargs, next_instr): + def RAISE_VARARGS(self, nbargs): space = self.space if nbargs == 0: if self.last_exception is not None: @@ -676,7 +676,7 @@ operror = space.exc_from_raise(w_type, w_value) raise operror - def IMPORT_NAME(self, nameindex, next_instr): + def IMPORT_NAME(self, nameindex): space = self.space modulename = self.getname_u(nameindex) glob = space.unwrap(self.w_globals) @@ -685,12 +685,12 @@ w_obj = space.import_name(modulename, glob, None, fromlist, level) self.pushvalue(w_obj) - def IMPORT_FROM(self, nameindex, next_instr): + def IMPORT_FROM(self, nameindex): w_name = self.getname_w(nameindex) w_module = self.peekvalue() self.pushvalue(self.space.import_from(w_module, w_name)) - def RETURN_VALUE(self, oparg, next_instr): + def RETURN_VALUE(self, oparg): w_returnvalue = self.popvalue() block = self.unrollstack(SReturnValue.kind) if block is None: @@ -700,7 +700,7 @@ next_instr = block.handle(self, unroller) return next_instr # now inside a 'finally' block - def END_FINALLY(self, oparg, next_instr): + def END_FINALLY(self, oparg): # unlike CPython, there are two statically distinct cases: the # END_FINALLY might be closing an 'except' block or a 'finally' # block. In the first case, the stack contains three items: @@ -731,14 +731,14 @@ else: return block.handle(self, unroller) - def POP_BLOCK(self, oparg, next_instr): + def POP_BLOCK(self, oparg): block = self.blockstack.pop() block.cleanupstack(self) # the block knows how to clean up the value stack - def JUMP_ABSOLUTE(self, jumpto, next_instr): + def JUMP_ABSOLUTE(self, jumpto): return jumpto - def YIELD_VALUE(self, _, next_instr): + def YIELD_VALUE(self, _): assert self.pycode.is_generator w_result = self.popvalue() self.do_operation('yield', w_result) @@ -750,64 +750,57 @@ PRINT_ITEM_TO = BAD_OPCODE PRINT_NEWLINE_TO = BAD_OPCODE - def PRINT_ITEM(self, oparg, next_instr): + def PRINT_ITEM(self, oparg): w_item = self.popvalue() w_s = self.do_operation('str', w_item) self.space.appcall(rpython_print_item, w_s) - def PRINT_NEWLINE(self, oparg, next_instr): + def PRINT_NEWLINE(self, oparg): self.space.appcall(rpython_print_newline) - def JUMP_FORWARD(self, jumpby, next_instr): - next_instr += jumpby - return next_instr + def JUMP_FORWARD(self, target): + return target - def JUMP_IF_FALSE(self, stepby, next_instr): + def JUMP_IF_FALSE(self, target): # Python <= 2.6 only w_cond = self.peekvalue() if not self.space.is_true(w_cond): - next_instr += stepby - return next_instr + return target - def JUMP_IF_TRUE(self, stepby, next_instr): + def JUMP_IF_TRUE(self, target): # Python <= 2.6 only w_cond = self.peekvalue() if self.space.is_true(w_cond): - next_instr += stepby - return next_instr + return target - def POP_JUMP_IF_FALSE(self, target, next_instr): + def POP_JUMP_IF_FALSE(self, target): w_value = self.popvalue() if not self.space.is_true(w_value): return target - return next_instr - def POP_JUMP_IF_TRUE(self, target, next_instr): + def POP_JUMP_IF_TRUE(self, target): w_value = self.popvalue() if self.space.is_true(w_value): return target - return next_instr - def JUMP_IF_FALSE_OR_POP(self, target, next_instr): + def JUMP_IF_FALSE_OR_POP(self, target): w_value = self.peekvalue() if not self.space.is_true(w_value): return target self.popvalue() - return next_instr - def JUMP_IF_TRUE_OR_POP(self, target, next_instr): + def JUMP_IF_TRUE_OR_POP(self, target): w_value = self.peekvalue() if self.space.is_true(w_value): return target self.popvalue() - return next_instr - def GET_ITER(self, oparg, next_instr): + def GET_ITER(self, oparg): w_iterable = self.popvalue() w_iterator = self.space.iter(w_iterable) self.pushvalue(w_iterator) - def FOR_ITER(self, jumpby, next_instr): + def FOR_ITER(self, target): w_iterator = self.peekvalue() try: w_nextitem = self.space.next(w_iterator) @@ -816,24 +809,23 @@ raise # iterator exhausted self.popvalue() - next_instr += jumpby + return target else: self.pushvalue(w_nextitem) - return next_instr - def SETUP_LOOP(self, offsettoend, next_instr): - block = LoopBlock(self, next_instr + offsettoend) + def SETUP_LOOP(self, target): + block = LoopBlock(self, target) self.blockstack.append(block) - def SETUP_EXCEPT(self, offsettoend, next_instr): - block = ExceptBlock(self, next_instr + offsettoend) + def SETUP_EXCEPT(self, target): + block = ExceptBlock(self, target) self.blockstack.append(block) - def SETUP_FINALLY(self, offsettoend, next_instr): - block = FinallyBlock(self, next_instr + offsettoend) + def SETUP_FINALLY(self, target): + block = FinallyBlock(self, target) self.blockstack.append(block) - def SETUP_WITH(self, offsettoend, next_instr): + def SETUP_WITH(self, target): # A simpler version than the 'real' 2.7 one: # directly call manager.__enter__(), don't use special lookup functions # which don't make sense on the RPython type system. @@ -841,11 +833,11 @@ w_exit = self.space.getattr(w_manager, self.space.wrap("__exit__")) self.settopvalue(w_exit) w_result = self.space.call_method(w_manager, "__enter__") - block = WithBlock(self, next_instr + offsettoend) + block = WithBlock(self, target) self.blockstack.append(block) self.pushvalue(w_result) - def WITH_CLEANUP(self, oparg, next_instr): + def WITH_CLEANUP(self, oparg): # Note: RPython context managers receive None in lieu of tracebacks # and cannot suppress the exception. # This opcode changed a lot between CPython versions @@ -867,22 +859,22 @@ else: self.space.call_function(w_exitfunc, w_None, w_None, w_None) - def LOAD_FAST(self, varindex, next_instr): + def LOAD_FAST(self, varindex): w_value = self.locals_stack_w[varindex] if w_value is None: raise FlowingError(self, "Local variable referenced before assignment") self.pushvalue(w_value) - def LOAD_CONST(self, constindex, next_instr): + def LOAD_CONST(self, constindex): w_const = self.getconstant_w(constindex) self.pushvalue(w_const) - def LOAD_GLOBAL(self, nameindex, next_instr): + def LOAD_GLOBAL(self, nameindex): w_result = self.space.find_global(self.w_globals, self.getname_u(nameindex)) self.pushvalue(w_result) LOAD_NAME = LOAD_GLOBAL - def LOAD_ATTR(self, nameindex, next_instr): + def LOAD_ATTR(self, nameindex): "obj.attributename" w_obj = self.popvalue() w_attributename = self.getname_w(nameindex) @@ -890,29 +882,29 @@ self.pushvalue(w_value) LOOKUP_METHOD = LOAD_ATTR - def LOAD_DEREF(self, varindex, next_instr): + def LOAD_DEREF(self, varindex): self.pushvalue(self.closure[varindex]) - def STORE_FAST(self, varindex, next_instr): + def STORE_FAST(self, varindex): w_newvalue = self.popvalue() assert w_newvalue is not None self.locals_stack_w[varindex] = w_newvalue - def STORE_GLOBAL(self, nameindex, next_instr): + def STORE_GLOBAL(self, nameindex): varname = self.getname_u(nameindex) raise FlowingError(self, "Attempting to modify global variable %r." % (varname)) - def POP_TOP(self, oparg, next_instr): + def POP_TOP(self, oparg): self.popvalue() - def ROT_TWO(self, oparg, next_instr): + def ROT_TWO(self, oparg): w_1 = self.popvalue() w_2 = self.popvalue() self.pushvalue(w_1) self.pushvalue(w_2) - def ROT_THREE(self, oparg, next_instr): + def ROT_THREE(self, oparg): w_1 = self.popvalue() w_2 = self.popvalue() w_3 = self.popvalue() @@ -920,7 +912,7 @@ self.pushvalue(w_3) self.pushvalue(w_2) - def ROT_FOUR(self, oparg, next_instr): + def ROT_FOUR(self, oparg): w_1 = self.popvalue() w_2 = self.popvalue() w_3 = self.popvalue() @@ -930,11 +922,11 @@ self.pushvalue(w_3) self.pushvalue(w_2) - def DUP_TOP(self, oparg, next_instr): + def DUP_TOP(self, oparg): w_1 = self.peekvalue() self.pushvalue(w_1) - def DUP_TOPX(self, itemcount, next_instr): + def DUP_TOPX(self, itemcount): delta = itemcount - 1 while True: itemcount -= 1 @@ -952,7 +944,7 @@ for OPCODE, op in _unsupported_ops: locals()[OPCODE] = unsupportedoperation(OPCODE, op) - def BUILD_LIST_FROM_ARG(self, _, next_instr): + def BUILD_LIST_FROM_ARG(self, _): # This opcode was added with pypy-1.8. Here is a simpler # version, enough for annotation. last_val = self.popvalue() @@ -976,37 +968,37 @@ w_result = self.space.call_args(w_function, args) self.pushvalue(w_result) - def CALL_FUNCTION(self, oparg, next_instr): + def CALL_FUNCTION(self, oparg): self.call_function(oparg) CALL_METHOD = CALL_FUNCTION - def CALL_FUNCTION_VAR(self, oparg, next_instr): + def CALL_FUNCTION_VAR(self, oparg): w_varargs = self.popvalue() self.call_function(oparg, w_varargs) - def CALL_FUNCTION_KW(self, oparg, next_instr): + def CALL_FUNCTION_KW(self, oparg): w_varkw = self.popvalue() self.call_function(oparg, None, w_varkw) - def CALL_FUNCTION_VAR_KW(self, oparg, next_instr): + def CALL_FUNCTION_VAR_KW(self, oparg): w_varkw = self.popvalue() w_varargs = self.popvalue() self.call_function(oparg, w_varargs, w_varkw) - def MAKE_FUNCTION(self, numdefaults, next_instr): + def MAKE_FUNCTION(self, numdefaults): w_codeobj = self.popvalue() defaults = self.popvalues(numdefaults) fn = self.space.newfunction(w_codeobj, self.w_globals, defaults) self.pushvalue(fn) - def STORE_ATTR(self, nameindex, next_instr): + def STORE_ATTR(self, nameindex): "obj.attributename = newvalue" w_attributename = self.getname_w(nameindex) w_obj = self.popvalue() w_newvalue = self.popvalue() self.space.setattr(w_obj, w_attributename, w_newvalue) - def UNPACK_SEQUENCE(self, itemcount, next_instr): + def UNPACK_SEQUENCE(self, itemcount): w_iterable = self.popvalue() items = self.space.unpack_sequence(w_iterable, itemcount) for w_item in reversed(items): @@ -1017,18 +1009,18 @@ w_result = self.space.getslice(w_obj, w_start, w_end) self.pushvalue(w_result) - def SLICE_0(self, oparg, next_instr): + def SLICE_0(self, oparg): self.slice(self.space.w_None, self.space.w_None) - def SLICE_1(self, oparg, next_instr): + def SLICE_1(self, oparg): w_start = self.popvalue() self.slice(w_start, self.space.w_None) - def SLICE_2(self, oparg, next_instr): + def SLICE_2(self, oparg): w_end = self.popvalue() self.slice(self.space.w_None, w_end) - def SLICE_3(self, oparg, next_instr): + def SLICE_3(self, oparg): w_end = self.popvalue() w_start = self.popvalue() self.slice(w_start, w_end) @@ -1038,18 +1030,18 @@ w_newvalue = self.popvalue() self.space.setslice(w_obj, w_start, w_end, w_newvalue) - def STORE_SLICE_0(self, oparg, next_instr): + def STORE_SLICE_0(self, oparg): self.storeslice(self.space.w_None, self.space.w_None) - def STORE_SLICE_1(self, oparg, next_instr): + def STORE_SLICE_1(self, oparg): w_start = self.popvalue() self.storeslice(w_start, self.space.w_None) - def STORE_SLICE_2(self, oparg, next_instr): + def STORE_SLICE_2(self, oparg): w_end = self.popvalue() self.storeslice(self.space.w_None, w_end) - def STORE_SLICE_3(self, oparg, next_instr): + def STORE_SLICE_3(self, oparg): w_end = self.popvalue() w_start = self.popvalue() self.storeslice(w_start, w_end) @@ -1058,23 +1050,23 @@ w_obj = self.popvalue() self.space.delslice(w_obj, w_start, w_end) - def DELETE_SLICE_0(self, oparg, next_instr): + def DELETE_SLICE_0(self, oparg): self.deleteslice(self.space.w_None, self.space.w_None) - def DELETE_SLICE_1(self, oparg, next_instr): + def DELETE_SLICE_1(self, oparg): w_start = self.popvalue() self.deleteslice(w_start, self.space.w_None) - def DELETE_SLICE_2(self, oparg, next_instr): + def DELETE_SLICE_2(self, oparg): w_end = self.popvalue() self.deleteslice(self.space.w_None, w_end) - def DELETE_SLICE_3(self, oparg, next_instr): + def DELETE_SLICE_3(self, oparg): w_end = self.popvalue() w_start = self.popvalue() self.deleteslice(w_start, w_end) - def LIST_APPEND(self, oparg, next_instr): + def LIST_APPEND(self, oparg): w = self.popvalue() if sys.version_info < (2, 7): v = self.popvalue() @@ -1082,27 +1074,27 @@ v = self.peekvalue(oparg - 1) self.space.call_method(v, 'append', w) - def DELETE_FAST(self, varindex, next_instr): + def DELETE_FAST(self, varindex): if self.locals_stack_w[varindex] is None: varname = self.getlocalvarname(varindex) message = "local variable '%s' referenced before assignment" raise UnboundLocalError(message, varname) self.locals_stack_w[varindex] = None - def STORE_MAP(self, oparg, next_instr): + def STORE_MAP(self, oparg): w_key = self.popvalue() w_value = self.popvalue() w_dict = self.peekvalue() self.space.setitem(w_dict, w_key, w_value) - def STORE_SUBSCR(self, oparg, next_instr): + def STORE_SUBSCR(self, oparg): "obj[subscr] = newvalue" w_subscr = self.popvalue() w_obj = self.popvalue() w_newvalue = self.popvalue() self.space.setitem(w_obj, w_subscr, w_newvalue) - def BUILD_SLICE(self, numargs, next_instr): + def BUILD_SLICE(self, numargs): if numargs == 3: w_step = self.popvalue() elif numargs == 2: @@ -1114,23 +1106,23 @@ w_slice = self.space.newslice(w_start, w_end, w_step) self.pushvalue(w_slice) - def DELETE_SUBSCR(self, oparg, next_instr): + def DELETE_SUBSCR(self, oparg): "del obj[subscr]" w_subscr = self.popvalue() w_obj = self.popvalue() self.space.delitem(w_obj, w_subscr) - def BUILD_TUPLE(self, itemcount, next_instr): + def BUILD_TUPLE(self, itemcount): items = self.popvalues(itemcount) w_tuple = self.space.newtuple(items) self.pushvalue(w_tuple) - def BUILD_LIST(self, itemcount, next_instr): + def BUILD_LIST(self, itemcount): items = self.popvalues(itemcount) w_list = self.space.newlist(items) self.pushvalue(w_list) - def BUILD_MAP(self, itemcount, next_instr): + def BUILD_MAP(self, itemcount): w_dict = self.space.newdict() self.pushvalue(w_dict) @@ -1141,15 +1133,15 @@ # Set literals, set comprehensions - def BUILD_SET(self, oparg, next_instr): + def BUILD_SET(self, oparg): raise NotImplementedError("BUILD_SET") - def SET_ADD(self, oparg, next_instr): + def SET_ADD(self, oparg): raise NotImplementedError("SET_ADD") # Dict comprehensions - def MAP_ADD(self, oparg, next_instr): + def MAP_ADD(self, oparg): raise NotImplementedError("MAP_ADD") # Closures From noreply at buildbot.pypy.org Sat May 4 02:05:42 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:42 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Deal with FSFrame.last_instr a bit more explicitly Message-ID: <20130504000542.5A0631C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63833:8fcf71337b33 Date: 2013-04-30 15:32 +0100 http://bitbucket.org/pypy/pypy/changeset/8fcf71337b33/ Log: Deal with FSFrame.last_instr a bit more explicitly diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -424,7 +424,7 @@ raise BytecodeCorruption("misplaced bytecode - should not return") return block.handle(self, unroller) - def getstate(self): + def getstate(self, next_pos): # getfastscope() can return real None, for undefined locals data = self.save_locals_stack() if self.last_exception is None: @@ -434,7 +434,7 @@ data.append(self.last_exception.w_type) data.append(self.last_exception.w_value) recursively_flatten(self.space, data) - return FrameState(data, self.blockstack[:], self.last_instr) + return FrameState(data, self.blockstack[:], next_pos) def setstate(self, state): """ Reset the frame to the given state. """ @@ -446,7 +446,6 @@ self.last_exception = None else: self.last_exception = FSException(data[-2], data[-1]) - self.last_instr = state.next_instr self.blockstack = state.blocklist[:] def guessbool(self, w_condition, **kwds): @@ -490,11 +489,12 @@ def record_block(self, block): self.setstate(block.framestate) + next_pos = block.framestate.next_instr self.recorder = block.make_recorder() try: while True: - self.last_instr = self.handle_bytecode(self.last_instr) - self.recorder.final_state = self.getstate() + next_pos = self.handle_bytecode(next_pos) + self.recorder.final_state = self.getstate(next_pos) except ImplicitOperationError, e: if isinstance(e.w_type, Constant): @@ -577,6 +577,7 @@ def handle_bytecode(self, next_instr): next_instr, opcode = self.pycode.read(next_instr) try: + self.last_instr = opcode.offset res = opcode.eval(self) return res if res is not None else next_instr except FSException, operr: diff --git a/rpython/flowspace/test/test_framestate.py b/rpython/flowspace/test/test_framestate.py --- a/rpython/flowspace/test/test_framestate.py +++ b/rpython/flowspace/test/test_framestate.py @@ -25,55 +25,55 @@ def test_eq_framestate(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() - fs2 = frame.getstate() + fs1 = frame.getstate(0) + fs2 = frame.getstate(0) assert fs1 == fs2 def test_neq_hacked_framestate(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable() - fs2 = frame.getstate() + fs2 = frame.getstate(0) assert fs1 != fs2 def test_union_on_equal_framestates(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() - fs2 = frame.getstate() + fs1 = frame.getstate(0) + fs2 = frame.getstate(0) assert fs1.union(fs2) == fs1 def test_union_on_hacked_framestates(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable() - fs2 = frame.getstate() + fs2 = frame.getstate(0) assert fs1.union(fs2) == fs2 # fs2 is more general assert fs2.union(fs1) == fs2 # fs2 is more general def test_restore_frame(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable() frame.setstate(fs1) - assert fs1 == frame.getstate() + assert fs1 == frame.getstate(0) def test_copy(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) fs2 = fs1.copy() assert fs1 == fs2 def test_getvariables(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) vars = fs1.getvariables() assert len(vars) == 1 def test_getoutputargs(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) frame.locals_stack_w[frame.pycode.co_nlocals-1] = Variable() - fs2 = frame.getstate() + fs2 = frame.getstate(0) outputargs = fs1.getoutputargs(fs2) # 'x' -> 'x' is a Variable # locals_w[n-1] -> locals_w[n-1] is Constant(None) @@ -81,9 +81,9 @@ def test_union_different_constants(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(42) - fs2 = frame.getstate() + fs2 = frame.getstate(0) fs3 = fs1.union(fs2) frame.setstate(fs3) assert isinstance(frame.locals_stack_w[frame.pycode.co_nlocals-1], @@ -91,7 +91,7 @@ def test_union_spectag(self): frame = self.getframe(self.func_simple) - fs1 = frame.getstate() + fs1 = frame.getstate(0) frame.locals_stack_w[frame.pycode.co_nlocals-1] = Constant(SpecTag()) - fs2 = frame.getstate() + fs2 = frame.getstate(0) assert fs1.union(fs2) is None # UnionError From noreply at buildbot.pypy.org Sat May 4 02:05:43 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:43 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Implement registration of opcode classes Message-ID: <20130504000543.943341C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63834:612e87240217 Date: 2013-05-02 05:43 +0100 http://bitbucket.org/pypy/pypy/changeset/612e87240217/ Log: Implement registration of opcode classes diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -106,7 +106,11 @@ if opnum in opcode.hasjrel: oparg += next_instr - return next_instr, Opcode(opnum, oparg, pos) + try: + op = Opcode.num2op[opnum](oparg, pos) + except KeyError: + op = Opcode(opnum, oparg, pos) + return next_instr, op @property def is_generator(self): @@ -115,8 +119,10 @@ OPNAMES = host_bytecode_spec.method_names class Opcode(object): + num2op = {} def __init__(self, opcode, arg, offset=-1): self.name = OPNAMES[opcode] + self.num = opcode self.arg = arg self.offset = offset From noreply at buildbot.pypy.org Sat May 4 02:05:44 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:44 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Add hook to customize opcode decoding Message-ID: <20130504000544.DCF9E1C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63835:a436f69d22e4 Date: 2013-05-02 15:29 +0100 http://bitbucket.org/pypy/pypy/changeset/a436f69d22e4/ Log: Add hook to customize opcode decoding diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -107,7 +107,7 @@ if opnum in opcode.hasjrel: oparg += next_instr try: - op = Opcode.num2op[opnum](oparg, pos) + op = Opcode.num2op[opnum].decode(oparg, pos, self) except KeyError: op = Opcode(opnum, oparg, pos) return next_instr, op @@ -126,5 +126,9 @@ self.arg = arg self.offset = offset + @classmethod + def decode(cls, arg, offset, code): + return cls(arg, offset) + def eval(self, frame): return getattr(frame, self.name)(self.arg) From noreply at buildbot.pypy.org Sat May 4 02:05:46 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:46 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Create @register_opcode Message-ID: <20130504000546.0E3581C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63836:83dc2f3f8201 Date: 2013-05-02 19:09 +0100 http://bitbucket.org/pypy/pypy/changeset/83dc2f3f8201/ Log: Create @register_opcode diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -132,3 +132,21 @@ def eval(self, frame): return getattr(frame, self.name)(self.arg) + + @classmethod + def register_name(cls, name, op_class): + try: + num = OPNAMES.index(name) + cls.num2op[num] = op_class + return num + except ValueError: + return -1 + + def __repr__(self): + return "%s(%d)" % (self.name, self.arg) + +def register_opcode(cls): + """Class decorator: register opcode class as real Python opcode""" + name = cls.__name__ + cls.num = Opcode.register_name(name, cls) + return cls From noreply at buildbot.pypy.org Sat May 4 02:05:47 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:47 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Create HostCode.disassemble() Message-ID: <20130504000547.55A781C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63837:62e72859ced3 Date: 2013-05-02 23:24 +0100 http://bitbucket.org/pypy/pypy/changeset/62e72859ced3/ Log: Create HostCode.disassemble() diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -53,6 +53,23 @@ self.co_lnotab = lnotab self.signature = cpython_code_signature(self) + def disassemble(self): + contents = [] + offsets = [] + jumps = {} + pos = 0 + i = 0 + while pos < len(self.co_code): + offsets.append(pos) + next_pos, op = self.decode(pos) + contents.append(op) + if op.has_jump(): + jumps[pos] = op.arg + pos = next_pos + i += 1 + return contents, offsets, jumps + + @classmethod def _from_code(cls, code): """Initialize the code object from a real (CPython) one. @@ -142,6 +159,9 @@ except ValueError: return -1 + def has_jump(self): + return self.num in opcode.hasjrel or self.num in opcode.hasjabs + def __repr__(self): return "%s(%d)" % (self.name, self.arg) From noreply at buildbot.pypy.org Sat May 4 02:05:48 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:48 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Decode the bytecode up-front Message-ID: <20130504000548.ABDFA1C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63838:b0a33987a874 Date: 2013-04-28 15:02 +0100 http://bitbucket.org/pypy/pypy/changeset/b0a33987a874/ Log: Decode the bytecode up-front diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -52,6 +52,7 @@ self.co_firstlineno = firstlineno self.co_lnotab = lnotab self.signature = cpython_code_signature(self) + self.build_flow() def disassemble(self): contents = [] @@ -69,6 +70,14 @@ i += 1 return contents, offsets, jumps + def build_flow(self): + next_pos = pos = 0 + contents, offsets, jumps = self.disassemble() + self.contents = zip(offsets, contents) + self.pos_index = dict((offset, i) for i, offset in enumerate(offsets)) + # add end marker + self.contents.append((len(self.co_code), None)) + @classmethod def _from_code(cls, code): @@ -95,10 +104,17 @@ return self.signature.scope_length() def read(self, pos): + i = self.pos_index[pos] + op = self.contents[i][1] + next_pos = self.contents[i+1][0] + return next_pos, op + + + def decode(self, pos): """ Decode the instruction starting at position ``next_instr``. - Returns (next_instr, opname, oparg). + Returns (next_instr, op). """ co_code = self.co_code opnum = ord(co_code[pos]) From noreply at buildbot.pypy.org Sat May 4 02:05:49 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:49 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Resolve LOAD_CONST constants at decoding time Message-ID: <20130504000549.CB6631C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63839:64d1839ad4a4 Date: 2013-05-02 16:02 +0100 http://bitbucket.org/pypy/pypy/changeset/64d1839ad4a4/ Log: Resolve LOAD_CONST constants at decoding time diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -184,5 +184,16 @@ def register_opcode(cls): """Class decorator: register opcode class as real Python opcode""" name = cls.__name__ + cls.name = name cls.num = Opcode.register_name(name, cls) return cls + + at register_opcode +class LOAD_CONST(Opcode): + def __init__(self, arg, offset=-1): + self.arg = arg + self.offset = offset + + @staticmethod + def decode(arg, offset, code): + return LOAD_CONST(code.consts[arg], offset) diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -595,9 +595,6 @@ def getlocalvarname(self, index): return self.pycode.co_varnames[index] - def getconstant_w(self, index): - return self.space.wrap(self.pycode.consts[index]) - def getname_u(self, index): return self.pycode.names[index] @@ -866,8 +863,8 @@ raise FlowingError(self, "Local variable referenced before assignment") self.pushvalue(w_value) - def LOAD_CONST(self, constindex): - w_const = self.getconstant_w(constindex) + def LOAD_CONST(self, const): + w_const = self.space.wrap(const) self.pushvalue(w_const) def LOAD_GLOBAL(self, nameindex): From noreply at buildbot.pypy.org Sat May 4 02:05:51 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 4 May 2013 02:05:51 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Resolve names at decoding time Message-ID: <20130504000551.1BDA91C02DA@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r63840:d3207d87d828 Date: 2013-05-02 17:04 +0100 http://bitbucket.org/pypy/pypy/changeset/d3207d87d828/ Log: Resolve names at decoding time diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -139,6 +139,8 @@ if opnum in opcode.hasjrel: oparg += next_instr + elif opnum in opcode.hasname: + oparg = self.names[oparg] try: op = Opcode.num2op[opnum].decode(oparg, pos, self) except KeyError: diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -595,12 +595,6 @@ def getlocalvarname(self, index): return self.pycode.co_varnames[index] - def getname_u(self, index): - return self.pycode.names[index] - - def getname_w(self, index): - return Constant(self.pycode.names[index]) - def BAD_OPCODE(self, _): raise FlowingError(self, "This operation is not RPython") @@ -674,17 +668,16 @@ operror = space.exc_from_raise(w_type, w_value) raise operror - def IMPORT_NAME(self, nameindex): + def IMPORT_NAME(self, modulename): space = self.space - modulename = self.getname_u(nameindex) glob = space.unwrap(self.w_globals) fromlist = space.unwrap(self.popvalue()) level = self.popvalue().value w_obj = space.import_name(modulename, glob, None, fromlist, level) self.pushvalue(w_obj) - def IMPORT_FROM(self, nameindex): - w_name = self.getname_w(nameindex) + def IMPORT_FROM(self, name): + w_name = Constant(name) w_module = self.peekvalue() self.pushvalue(self.space.import_from(w_module, w_name)) @@ -867,15 +860,15 @@ w_const = self.space.wrap(const) self.pushvalue(w_const) - def LOAD_GLOBAL(self, nameindex): - w_result = self.space.find_global(self.w_globals, self.getname_u(nameindex)) + def LOAD_GLOBAL(self, name): + w_result = self.space.find_global(self.w_globals, name) self.pushvalue(w_result) LOAD_NAME = LOAD_GLOBAL - def LOAD_ATTR(self, nameindex): + def LOAD_ATTR(self, name): "obj.attributename" w_obj = self.popvalue() - w_attributename = self.getname_w(nameindex) + w_attributename = Constant(name) w_value = self.space.getattr(w_obj, w_attributename) self.pushvalue(w_value) LOOKUP_METHOD = LOAD_ATTR @@ -888,8 +881,7 @@ assert w_newvalue is not None self.locals_stack_w[varindex] = w_newvalue - def STORE_GLOBAL(self, nameindex): - varname = self.getname_u(nameindex) + def STORE_GLOBAL(self, varname): raise FlowingError(self, "Attempting to modify global variable %r." % (varname)) @@ -989,9 +981,9 @@ fn = self.space.newfunction(w_codeobj, self.w_globals, defaults) self.pushvalue(fn) - def STORE_ATTR(self, nameindex): + def STORE_ATTR(self, name): "obj.attributename = newvalue" - w_attributename = self.getname_w(nameindex) + w_attributename = Constant(name) w_obj = self.popvalue() w_newvalue = self.popvalue() self.space.setattr(w_obj, w_attributename, w_newvalue) From noreply at buildbot.pypy.org Sat May 4 03:47:00 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 4 May 2013 03:47:00 +0200 (CEST) Subject: [pypy-commit] pypy py3k: exceptions is really builtins in appdirect Message-ID: <20130504014700.5777D1C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63841:44741af7e252 Date: 2013-05-03 18:41 -0700 http://bitbucket.org/pypy/pypy/changeset/44741af7e252/ Log: exceptions is really builtins in appdirect diff --git a/pypy/tool/pytest/apptest.py b/pypy/tool/pytest/apptest.py --- a/pypy/tool/pytest/apptest.py +++ b/pypy/tool/pytest/apptest.py @@ -20,7 +20,7 @@ RENAMED_USEMODULES = dict( _winreg='winreg', - exceptions='__exceptions__', + exceptions='builtins', rctime='time', struct='_struct', thread='_thread', From noreply at buildbot.pypy.org Sat May 4 03:47:01 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 4 May 2013 03:47:01 +0200 (CEST) Subject: [pypy-commit] pypy py3k: maintain AssertionError.__doc__ Message-ID: <20130504014701.90D191C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63842:5ffc21d95e86 Date: 2013-05-03 18:41 -0700 http://bitbucket.org/pypy/pypy/changeset/5ffc21d95e86/ Log: maintain AssertionError.__doc__ diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -184,7 +184,8 @@ space.wrap('AssertionError')) w_metaclass = space.type(w_BuiltinAssertionError) w_init = space.wrap(gateway.interp2app_temp(my_init)) - w_dict = space.newdict() + w_dict = space.getattr(w_BuiltinAssertionError, space.wrap('__dict__')) + w_dict = space.call_method(w_dict, 'copy') space.setitem(w_dict, space.wrap('__init__'), w_init) return space.call_function(w_metaclass, space.wrap('AssertionError'), From noreply at buildbot.pypy.org Sat May 4 03:47:02 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 4 May 2013 03:47:02 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill BaseException's message/__getitem__ Message-ID: <20130504014702.D23C11C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63843:ac27970cee54 Date: 2013-05-03 18:46 -0700 http://bitbucket.org/pypy/pypy/changeset/ac27970cee54/ Log: kill BaseException's message/__getitem__ diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py --- a/pypy/interpreter/test/test_argument.py +++ b/pypy/interpreter/test/test_argument.py @@ -669,23 +669,23 @@ class AppTestArgument: def test_error_message(self): exc = raises(TypeError, (lambda a, b=2: 0), b=3) - assert exc.value.message == "() takes at least 1 non-keyword argument (0 given)" + assert str(exc.value) == "() takes at least 1 non-keyword argument (0 given)" exc = raises(TypeError, (lambda: 0), b=3) - assert exc.value.message == "() takes no arguments (1 given)" + assert str(exc.value) == "() takes no arguments (1 given)" exc = raises(TypeError, (lambda a, b: 0), 1, 2, 3, a=1) - assert exc.value.message == "() takes exactly 2 arguments (4 given)" + assert str(exc.value) == "() takes exactly 2 arguments (4 given)" exc = raises(TypeError, (lambda a, b=1: 0), 1, 2, 3, a=1) - assert exc.value.message == "() takes at most 2 non-keyword arguments (3 given)" + assert str(exc.value) == "() takes at most 2 non-keyword arguments (3 given)" exc = raises(TypeError, (lambda a, b=1, **kw: 0), 1, 2, 3) - assert exc.value.message == "() takes at most 2 non-keyword arguments (3 given)" + assert str(exc.value) == "() takes at most 2 non-keyword arguments (3 given)" exc = raises(TypeError, (lambda a, b, c=3, **kw: 0), 1) - assert exc.value.message == "() takes at least 2 arguments (1 given)" + assert str(exc.value) == "() takes at least 2 arguments (1 given)" exc = raises(TypeError, (lambda a, b, **kw: 0), 1) - assert exc.value.message == "() takes exactly 2 non-keyword arguments (1 given)" + assert str(exc.value) == "() takes exactly 2 non-keyword arguments (1 given)" exc = raises(TypeError, (lambda a, b, c=3, **kw: 0), a=1) - assert exc.value.message == "() takes at least 2 non-keyword arguments (0 given)" + assert str(exc.value) == "() takes at least 2 non-keyword arguments (0 given)" exc = raises(TypeError, (lambda a, b, **kw: 0), a=1) - assert exc.value.message == "() takes exactly 2 non-keyword arguments (0 given)" + assert str(exc.value) == "() takes exactly 2 non-keyword arguments (0 given)" def test_unicode_keywords(self): """ diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py --- a/pypy/interpreter/test/test_typedef.py +++ b/pypy/interpreter/test/test_typedef.py @@ -180,7 +180,7 @@ self.space.appexec([w_obj], """(obj): assert type(obj).__hash__ is None err = raises(TypeError, hash, obj) - assert err.value.message == "'some_type' objects are unhashable" + assert str(err.value) == "'some_type' objects are unhashable" """) def test_destructor(self): diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py --- a/pypy/module/_ffi/test/test_funcptr.py +++ b/pypy/module/_ffi/test/test_funcptr.py @@ -574,7 +574,7 @@ try: pow(2, 3) except ValueError as e: - assert e.message.startswith('Procedure called with') + assert str(e).startswith('Procedure called with') else: assert 0, 'test must assert, wrong calling convention' @@ -595,7 +595,7 @@ try: wrong_sleep(10) except ValueError as e: - assert e.message.startswith('Procedure called with') + assert str(e).startswith('Procedure called with') else: assert 0, 'test must assert, wrong calling convention' @@ -611,7 +611,7 @@ try: wrong_pow(2, 3) == 8 except ValueError as e: - assert e.message.startswith('Procedure called with') + assert str(e).startswith('Procedure called with') else: assert 0, 'test must assert, wrong calling convention' diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -883,7 +883,7 @@ try: f() except ValueError as e: - assert "Procedure called with not enough arguments" in e.message + assert "Procedure called with not enough arguments" in str(e) else: assert 0, "Did not raise" @@ -894,7 +894,7 @@ try: f(arg) except ValueError as e: - assert "Procedure called with too many arguments" in e.message + assert "Procedure called with too many arguments" in str(e) else: assert 0, "Did not raise" arg.free() diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py --- a/pypy/module/_socket/test/test_sock_app.py +++ b/pypy/module/_socket/test/test_sock_app.py @@ -708,4 +708,4 @@ assert isinstance(exc.value, IOError) # error is EINVAL, or WSAEINVAL on Windows assert exc.value.errno == getattr(errno, 'WSAEINVAL', errno.EINVAL) - assert isinstance(exc.value.message, str) + assert isinstance(exc.value.strerror, str) diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -610,7 +610,7 @@ if type(exc.value) is not Exception: raise exc.value - assert exc.value.message == "moo!" + assert str(exc.value) == "moo!" def test_refcount(self): import sys @@ -674,7 +674,7 @@ if type(exc.value) is not Exception: raise exc.value - assert exc.value.message == "moo!" + assert str(exc.value) == "moo!" def test_internal_exceptions(self): diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py --- a/pypy/module/exceptions/interp_exceptions.py +++ b/pypy/module/exceptions/interp_exceptions.py @@ -91,11 +91,7 @@ class W_BaseException(W_Root): - """Superclass representing the base of the exception hierarchy. - - The __getitem__ method is provided for backwards-compatibility - and will be deprecated at some point. - """ + """Superclass representing the base of the exception hierarchy.""" w_dict = None args_w = [] w_cause = None @@ -103,14 +99,10 @@ w_traceback = None def __init__(self, space): - self.w_message = space.w_None + pass def descr_init(self, space, args_w): self.args_w = args_w - if len(args_w) == 1: - self.w_message = args_w[0] - else: - self.w_message = space.wrap("") def descr_str(self, space): lgt = len(self.args_w) @@ -187,9 +179,6 @@ w_newtraceback = check_traceback(space, w_newtraceback, msg) self.w_traceback = w_newtraceback - def descr_getitem(self, space, w_index): - return space.getitem(space.newtuple(self.args_w), w_index) - def getdict(self, space): if self.w_dict is None: self.w_dict = space.newdict(instance=True) @@ -214,32 +203,6 @@ self.descr_settraceback(space, w_traceback) return space.wrap(self) - def descr_message_get(self, space): - w_dict = self.w_dict - if w_dict is not None: - w_msg = space.finditem(w_dict, space.wrap("message")) - if w_msg is not None: - return w_msg - if self.w_message is None: - raise OperationError(space.w_AttributeError, - space.wrap("message was deleted")) - msg = "BaseException.message has been deprecated as of Python 2.6" - space.warn(space.wrap(msg), space.w_DeprecationWarning) - return self.w_message - - def descr_message_set(self, space, w_new): - space.setitem(self.getdict(space), space.wrap("message"), w_new) - - def descr_message_del(self, space): - w_dict = self.w_dict - if w_dict is not None: - try: - space.delitem(w_dict, space.wrap("message")) - except OperationError, e: - if not e.match(space, space.w_KeyError): - raise - self.w_message = None - def _new(cls, basecls=None): if basecls is None: basecls = cls @@ -261,13 +224,9 @@ __repr__ = interp2app(W_BaseException.descr_repr), __dict__ = GetSetProperty(descr_get_dict, descr_set_dict, descr_del_dict, cls=W_BaseException), - __getitem__ = interp2app(W_BaseException.descr_getitem), __reduce__ = interp2app(W_BaseException.descr_reduce), __setstate__ = interp2app(W_BaseException.descr_setstate), with_traceback = interp2app(W_BaseException.descr_with_traceback), - message = GetSetProperty(W_BaseException.descr_message_get, - W_BaseException.descr_message_set, - W_BaseException.descr_message_del), args = GetSetProperty(W_BaseException.descr_getargs, W_BaseException.descr_setargs), __cause__ = GetSetProperty(W_BaseException.descr_getcause, @@ -547,7 +506,6 @@ W_BaseException.__init__(self, space) def descr_init(self, space, args_w): - # that's not a self.w_message!!! if len(args_w) > 0: self.w_msg = args_w[0] if len(args_w) == 2: diff --git a/pypy/module/exceptions/test/test_exc.py b/pypy/module/exceptions/test/test_exc.py --- a/pypy/module/exceptions/test/test_exc.py +++ b/pypy/module/exceptions/test/test_exc.py @@ -10,8 +10,8 @@ def test_baseexc(self): assert str(BaseException()) == '' assert repr(BaseException()) == 'BaseException()' - assert BaseException().message == '' - assert BaseException(3).message == 3 + raises(AttributeError, getattr, BaseException(), 'message') + raises(AttributeError, getattr, BaseException(3), 'message') assert repr(BaseException(3)) == 'BaseException(3,)' assert str(BaseException(3)) == '3' assert BaseException().args == () @@ -19,16 +19,14 @@ assert BaseException(3, "x").args == (3, "x") assert repr(BaseException(3, "x")) == "BaseException(3, 'x')" assert str(BaseException(3, "x")) == "(3, 'x')" - assert BaseException(3, "x").message == '' + raises(AttributeError, getattr, BaseException(3, "x"), 'message') x = BaseException() x.xyz = 3 assert x.xyz == 3 x.args = [42] assert x.args == (42,) assert str(x) == '42' - assert x[0] == 42 - x.args = (1, 2, 3) - assert x[1:2] == (2,) + raises(TypeError, 'x[0] == 42') x.message = "xyz" assert x.message == "xyz" del x.message @@ -71,7 +69,6 @@ assert ut.end == 5 assert ut.reason == 'bah' assert ut.args == ('x', 1, 5, 'bah') - assert ut.message == '' ut.object = 'y' assert ut.object == 'y' assert str(ut) == "can't translate characters in position 1-4: bah" @@ -151,7 +148,6 @@ assert ue.end == 5 assert ue.reason == 'bah' assert ue.args == ('x', 'y', 1, 5, 'bah') - assert ue.message == '' ue.object = 'z9' assert ue.object == 'z9' assert str(ue) == "'x' codec can't encode characters in position 1-4: bah" @@ -196,8 +192,8 @@ assert not isinstance(c, KeyError) def test_doc_and_module(self): - import __exceptions__ - for name, e in __exceptions__.__dict__.items(): + import builtins + for name, e in builtins.__dict__.items(): if isinstance(e, type) and issubclass(e, BaseException): assert e.__doc__, e assert e.__module__ == 'builtins', e @@ -227,7 +223,7 @@ assert e1.__cause__ is e2 e1.__cause__ = None raises(TypeError, setattr, e1, '__cause__', 1) - raises(AttributeError, delattr, e1, '__cause__') + raises((AttributeError, TypeError), delattr, e1, '__cause__') def test_context(self): e1 = TypeError() @@ -237,7 +233,7 @@ assert e1.__context__ is e2 e1.__context__ = None raises(TypeError, setattr, e1, '__context__', 1) - raises(AttributeError, delattr, e1, '__context__') + raises((AttributeError, TypeError), delattr, e1, '__context__') def test_traceback(self): assert ValueError().with_traceback(None).__traceback__ is None diff --git a/pypy/module/marshal/test/test_marshal.py b/pypy/module/marshal/test/test_marshal.py --- a/pypy/module/marshal/test/test_marshal.py +++ b/pypy/module/marshal/test/test_marshal.py @@ -178,7 +178,7 @@ def test_bad_typecode(self): import marshal exc = raises(ValueError, marshal.loads, b'\x01') - assert r"'\x01'" in exc.value.message + assert r"'\x01'" in str(exc.value) def test_bad_data(self): import marshal diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py @@ -517,7 +517,7 @@ dll.get_an_integer() assert len(w) == 1 assert issubclass(w[0].category, RuntimeWarning) - assert "C function without declared arguments called" in str(w[0].message) + assert "C function without declared arguments called" in str(w[0]) def test_errcheck(self): py.test.skip('fixme') @@ -540,7 +540,7 @@ dll.get_an_integer() assert len(w) == 1 assert issubclass(w[0].category, RuntimeWarning) - assert "C function without declared return type called" in str(w[0].message) + assert "C function without declared return type called" in str(w[0]) with warnings.catch_warnings(record=True) as w: dll.get_an_integer.restype = None diff --git a/pypy/module/test_lib_pypy/test_sqlite3.py b/pypy/module/test_lib_pypy/test_sqlite3.py --- a/pypy/module/test_lib_pypy/test_sqlite3.py +++ b/pypy/module/test_lib_pypy/test_sqlite3.py @@ -41,7 +41,7 @@ con = Connection(":memory:") e = pytest.raises(_sqlite3.ProgrammingError, "con.cursor()") - assert '__init__' in e.value.message + assert '__init__' in str(e.value) def test_cursor_check_init(con): class Cursor(_sqlite3.Cursor): @@ -50,7 +50,7 @@ cur = Cursor(con) e = pytest.raises(_sqlite3.ProgrammingError, "cur.execute('select 1')") - assert '__init__' in e.value.message + assert '__init__' in str(e.value) def test_connection_after_close(con): pytest.raises(TypeError, "con()") diff --git a/pypy/module/unicodedata/test/test_unicodedata.py b/pypy/module/unicodedata/test/test_unicodedata.py --- a/pypy/module/unicodedata/test/test_unicodedata.py +++ b/pypy/module/unicodedata/test/test_unicodedata.py @@ -71,7 +71,7 @@ try: unicodedata.name(char) except ValueError as e: - assert e.message == 'no such name' + assert str(e) == 'no such name' raises(KeyError, unicodedata.lookup, charname) def test_bug_1704793(self): # from CPython From noreply at buildbot.pypy.org Sat May 4 04:13:35 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 4 May 2013 04:13:35 +0200 (CEST) Subject: [pypy-commit] pypy py3k: braindump + move anto's old TODO, minus a couple finished things, here too Message-ID: <20130504021335.9950F1C3303@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63844:608621b8c9bb Date: 2013-05-03 19:12 -0700 http://bitbucket.org/pypy/pypy/changeset/608621b8c9bb/ Log: braindump + move anto's old TODO, minus a couple finished things, here too diff --git a/TODO b/TODO deleted file mode 100644 --- a/TODO +++ /dev/null @@ -1,24 +0,0 @@ -kill Exception.message - -what to do with the ListRangeStrategy? We also have __builtin__.functional.W_Range - -run coverage against the parser/astbuilder/astcompiler: it's probably full of -dead code because the grammar changed - -re-enable IntDictStrategy - -re-enable StdObjSpace.listview_str - -re-enable the kwargs dict strategy in dictmultiobject.py -re-enable view_as_kwargs - -check the "assert rbigint.SHIFT <= 32" in module/_random/interp_random.py, -which has been commented out for now - -unskip numpypy tests in module/test_lib_pypy/numpypy/ - -optimize W_UnicodeObject, right now it stores both an unicode and an utf8 -version of the same string - -re-enable BUILD_LIST_FROM_ARG: see the comment in astcompiler/codegen.py in -ast.ListComp.build_container \ No newline at end of file diff --git a/pypy/TODO b/pypy/TODO --- a/pypy/TODO +++ b/pypy/TODO @@ -6,10 +6,12 @@ It's important to be compatible, since other classes like Decimal and Fractions have to return the same hashes for equivalent values. IOW: int.__hash__ is part of the Python language specification. + The py3k-newhash branch has an updated float hash, int's hash is + still pending * test_fractions * test_numeric_tower - float.__hash__ has changed as well. + float.__hash__ has changed as well (fixed on py3k-newhash) * test_float nan = float('nan'); assert nan in [nan] @@ -20,7 +22,8 @@ FloatListStrategy.unwrap(). * test_memoryview - Needs bytes/str changes. Probably easy. + Needs bytes/str changes. Probably easy. Work for this has begun on + py3k-memoryview (by mjacob) * test_peepholer 'a in [1,2,3]' is rewritten as 'a in (1, 2, 3)' @@ -28,7 +31,9 @@ Likewise, a set becomes a frozenset. * test_pep263 - Tracebacks should be able to print unicode source code. + Tracebacks should be able to print unicode source code. This is + really due to the tokenizer not being fully unicode aware. The + parser can somewhat hack around this but maybe not completely * test_sqlite (Probably easy) Ports of CPython changeset fc6f90545cb4 and PyPy @@ -36,6 +41,53 @@ * test_sys * test_threading: - Missing sys.getswitchinterval(). + Missing sys.getswitchinterval(). https://bugs.pypy.org/issue1470 We would be interesting to implement the new thread switching logic, it's a lot of work though. + + +own-tests: + +* module/test_lib_pypy + These crash the buildbots (via SyntaxErrors): some were really made + to run under Python 2.x + +* interpreter.test.test_zzpickle_and_slow test_pickle_frame_with_exc + Due to W_OperationError not being pickleable. Probably be best for + the ExceptionHandlerBlock to push *sys.exc_info() instead of it, + like CPython does + +* module.bz2.test.test_bz2_file test_open_non_existent + Some really obscure GC stuff + +* module.cpyext.test.test_structseq test_StructSeq + structseq now subclasses tuple on py3, which breaks how + BaseCpyTypeDescr.realize allocates it + +* module.marshal.test.test_marshal + Handling of exceptions w/ bad data? Or is the test wrong? + +* objspace.std.test.test_floatobject test_from_string + The unicode-based number parsing routines don't raise UnicodeErrors, + but more importantly they raise unprintable exceptions + + +antocuni's older TODO: + +run coverage against the parser/astbuilder/astcompiler: it's probably full of +dead code because the grammar changed + +re-enable IntDictStrategy + +re-enable StdObjSpace.listview_str + +re-enable the kwargs dict strategy in dictmultiobject.py +re-enable view_as_kwargs + +unskip numpypy tests in module/test_lib_pypy/numpypy/ + +optimize W_UnicodeObject, right now it stores both an unicode and an utf8 +version of the same string + +re-enable BUILD_LIST_FROM_ARG: see the comment in astcompiler/codegen.py in +ast.ListComp.build_container From noreply at buildbot.pypy.org Sat May 4 11:26:40 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Sat, 4 May 2013 11:26:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Issue1473: Subclasses or ctypes.Structure without _fields_ should inherit the list of field names, not reset it. Message-ID: <20130504092640.458AE1C125E@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r63845:1236a55828ce Date: 2013-05-04 11:25 +0200 http://bitbucket.org/pypy/pypy/changeset/1236a55828ce/ Log: Issue1473: Subclasses or ctypes.Structure without _fields_ should inherit the list of field names, not reset it. diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -167,7 +167,6 @@ return if '_fields_' not in self.__dict__: self._fields_ = [] - self._names = [] _set_shape(self, [], self._is_union) __setattr__ = struct_setattr diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -230,6 +230,17 @@ pt = POINT(y=2, x=1) assert (pt.x, pt.y) == (1, 2) + def test_subclass_initializer(self): + class POINT(Structure): + _fields_ = [("x", c_int), ("y", c_int)] + + class POSITION(POINT): + # A subclass without _fields_ + pass + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) + + def test_invalid_field_types(self): class POINT(Structure): pass @@ -538,6 +549,7 @@ raises(AttributeError, setattr, X, "_fields_", []) Y.__fields__ = [] + class TestPatologicalCases(BaseCTypesTestChecker): def test_structure_overloading_getattr(self): class X(Structure): From noreply at buildbot.pypy.org Sat May 4 11:51:41 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Sat, 4 May 2013 11:51:41 +0200 (CEST) Subject: [pypy-commit] pypy py3k: Port CPython fc6f90545cb4 for sqlite: fix error message when a fetched value cannot be decoded from utf8. Message-ID: <20130504095141.74E301C02DA@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: py3k Changeset: r63846:c00110d1c1d0 Date: 2013-05-04 11:45 +0200 http://bitbucket.org/pypy/pypy/changeset/c00110d1c1d0/ Log: Port CPython fc6f90545cb4 for sqlite: fix error message when a fetched value cannot be decoded from utf8. diff --git a/lib_pypy/_sqlite3.py b/lib_pypy/_sqlite3.py --- a/lib_pypy/_sqlite3.py +++ b/lib_pypy/_sqlite3.py @@ -956,7 +956,19 @@ text = _lib.sqlite3_column_text(self.__statement._statement, i) text_len = _lib.sqlite3_column_bytes(self.__statement._statement, i) val = _ffi.buffer(text, text_len)[:] - val = self.__connection.text_factory(val) + try: + val = self.__connection.text_factory(val) + except Exception: + column_name = _lib.sqlite3_column_name( + self.__statement._statement, i) + if column_name: + column_name = _ffi.string(column_name).decode('utf-8') + else: + column_name = "" + val = val.decode('ascii', 'replace') + raise OperationalError( + "Could not decode to UTF-8 column '%s' with text '%s'" % ( + column_name, val)) elif typ == _lib.SQLITE_BLOB: blob = _lib.sqlite3_column_blob(self.__statement._statement, i) blob_len = _lib.sqlite3_column_bytes(self.__statement._statement, i) From noreply at buildbot.pypy.org Sat May 4 11:51:42 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Sat, 4 May 2013 11:51:42 +0200 (CEST) Subject: [pypy-commit] pypy py3k: Port pypy hacks to sqlite test suite. Message-ID: <20130504095142.A32941C02DA@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: py3k Changeset: r63847:ab1fa8ed1535 Date: 2013-05-04 11:50 +0200 http://bitbucket.org/pypy/pypy/changeset/ab1fa8ed1535/ Log: Port pypy hacks to sqlite test suite. diff --git a/lib-python/3/sqlite3/test/userfunctions.py b/lib-python/3/sqlite3/test/userfunctions.py --- a/lib-python/3/sqlite3/test/userfunctions.py +++ b/lib-python/3/sqlite3/test/userfunctions.py @@ -294,12 +294,14 @@ pass def CheckAggrNoStep(self): + # XXX it's better to raise OperationalError in order to stop + # the query earlier. cur = self.con.cursor() try: cur.execute("select nostep(t) from test") - self.fail("should have raised an AttributeError") - except AttributeError as e: - self.assertEqual(e.args[0], "'AggrNoStep' object has no attribute 'step'") + self.fail("should have raised an OperationalError") + except sqlite.OperationalError as e: + self.assertEqual(e.args[0], "user-defined aggregate's 'step' method raised error") def CheckAggrNoFinalize(self): cur = self.con.cursor() diff --git a/pypy/TODO b/pypy/TODO --- a/pypy/TODO +++ b/pypy/TODO @@ -35,10 +35,6 @@ really due to the tokenizer not being fully unicode aware. The parser can somewhat hack around this but maybe not completely -* test_sqlite - (Probably easy) Ports of CPython changeset fc6f90545cb4 and PyPy - 48d194e3ac07. - * test_sys * test_threading: Missing sys.getswitchinterval(). https://bugs.pypy.org/issue1470 From noreply at buildbot.pypy.org Sat May 4 19:56:02 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 4 May 2013 19:56:02 +0200 (CEST) Subject: [pypy-commit] pypy py3k: BaseException.message is dead Message-ID: <20130504175602.D0CA81C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63848:9391cb2a1566 Date: 2013-05-04 10:55 -0700 http://bitbucket.org/pypy/pypy/changeset/9391cb2a1566/ Log: BaseException.message is dead diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -455,7 +455,7 @@ try: float('abcdef') except ValueError as e: - assert 'abcdef' in e.message + assert 'abcdef' in str(e) else: assert False, 'did not raise' diff --git a/pypy/objspace/std/test/test_longobject.py b/pypy/objspace/std/test/test_longobject.py --- a/pypy/objspace/std/test/test_longobject.py +++ b/pypy/objspace/std/test/test_longobject.py @@ -340,7 +340,7 @@ try: int('hello àèìò') except ValueError as e: - assert 'hello àèìò' in e.message + assert 'hello àèìò' in str(e) else: assert False, 'did not raise' From noreply at buildbot.pypy.org Sat May 4 22:09:39 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 4 May 2013 22:09:39 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Make sure non-flexible dtypes are considered as such. Message-ID: <20130504200939.F32401C0130@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r63849:c4923f89dd03 Date: 2013-05-04 22:07 +0200 http://bitbucket.org/pypy/pypy/changeset/c4923f89dd03/ Log: Make sure non-flexible dtypes are considered as such. diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -244,7 +244,10 @@ fieldnames = space.getitem(w_data, space.wrap(2)) self.set_names(space, fieldnames) - self.set_fields(space, space.getitem(w_data, space.wrap(3))) + + fields = space.getitem(w_data, space.wrap(3)) + if fields != space.w_None: + self.set_fields(space, fields) class W_ComplexDtype(W_Dtype): def __init__(self, itemtype, num, kind, name, char, w_box_type, From noreply at buildbot.pypy.org Sat May 4 22:09:41 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 4 May 2013 22:09:41 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Add an optional track_allocation parameter to str2charp Message-ID: <20130504200941.74F961C02DA@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r63850:fe83fa4acdef Date: 2013-05-04 22:08 +0200 http://bitbucket.org/pypy/pypy/changeset/fe83fa4acdef/ Log: Add an optional track_allocation parameter to str2charp diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -446,7 +446,7 @@ TYPES += ['__int128_t'] except CompilationError: pass - + _TYPES_ARE_UNSIGNED = set(['size_t', 'uintptr_t']) # plus "unsigned *" if os.name != 'nt': TYPES.append('mode_t') @@ -693,10 +693,10 @@ builder_class = UnicodeBuilder # str -> char* - def str2charp(s): + def str2charp(s, track_allocation=True): """ str -> char* """ - array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw') + array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=track_allocation) i = len(s) array[i] = lastchar i -= 1 @@ -706,8 +706,8 @@ return array str2charp._annenforceargs_ = [strtype] - def free_charp(cp): - lltype.free(cp, flavor='raw') + def free_charp(cp, track_allocation=True): + lltype.free(cp, flavor='raw', track_allocation=track_allocation) # char* -> str # doesn't free char* From noreply at buildbot.pypy.org Sat May 4 22:09:42 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 4 May 2013 22:09:42 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Implement ndarray pickling Message-ID: <20130504200942.E25001C0328@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r63851:08efaffe4c1f Date: 2013-05-04 22:09 +0200 http://bitbucket.org/pypy/pypy/changeset/08efaffe4c1f/ Log: Implement ndarray pickling diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -325,13 +325,14 @@ return None class ConcreteArray(ConcreteArrayNotOwning): - def __init__(self, shape, dtype, order, strides, backstrides): - # we allocate the actual storage later because we need to compute - # self.size first + def __init__(self, shape, dtype, order, strides, backstrides, storage=None): null_storage = lltype.nullptr(RAW_STORAGE) ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides, null_storage) - self.storage = dtype.itemtype.malloc(self.size) + if storage is None: + self.storage = dtype.itemtype.malloc(self.size) + else: + self.storage = storage def __del__(self): free_raw_storage(self.storage, track_allocation=False) diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -18,11 +18,11 @@ def __init__(self, implementation): assert isinstance(implementation, BaseArrayImplementation) self.implementation = implementation - + @staticmethod def from_shape(shape, dtype, order='C'): from pypy.module.micronumpy.arrayimpl import concrete, scalar - + if not shape: impl = scalar.Scalar(dtype) else: @@ -32,12 +32,17 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(shape, storage, dtype, order='C'): + def from_shape_and_storage(shape, storage, dtype, order='C', owning=False): from pypy.module.micronumpy.arrayimpl import concrete assert shape strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, - backstrides, storage) + if owning: + # Will free storage when GCd + impl = concrete.ConcreteArray(shape, dtype, order, strides, + backstrides, storage=storage) + else: + impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, + backstrides, storage) return W_NDimArray(impl) @@ -60,7 +65,7 @@ def convert_to_array(space, w_obj): from pypy.module.micronumpy.interp_numarray import array from pypy.module.micronumpy import interp_ufuncs - + if isinstance(w_obj, W_NDimArray): return w_obj elif issequence_w(space, w_obj): diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -796,6 +796,17 @@ return space.newtuple([reconstruct, parameters, state]) + def descr_setstate(self, space, w_state): + from rpython.rtyper.lltypesystem import rffi + + shape = space.getitem(w_state, space.wrap(1)) + dtype = space.getitem(w_state, space.wrap(2)) + isfortran = space.getitem(w_state, space.wrap(3)) + storage = space.getitem(w_state, space.wrap(4)) + + self.implementation = W_NDimArray.from_shape_and_storage([space.int_w(i) for i in space.listview(shape)], rffi.str2charp(space.str_w(storage), track_allocation=False), dtype, owning=True).implementation + + @unwrap_spec(offset=int) def descr_new_array(space, w_subtype, w_shape, w_dtype=None, w_buffer=None, offset=0, w_strides=None, w_order=None): @@ -945,7 +956,8 @@ __pypy_data__ = GetSetProperty(W_NDimArray.fget___pypy_data__, W_NDimArray.fset___pypy_data__, W_NDimArray.fdel___pypy_data__), - __reduce__ = interp2app(W_NDimArray.descr_reduce) + __reduce__ = interp2app(W_NDimArray.descr_reduce), + __setstate__ = interp2app(W_NDimArray.descr_setstate), ) @unwrap_spec(ndmin=int, copy=bool, subok=bool) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1749,7 +1749,7 @@ assert data[2][4] == '\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00' pickled_data = dumps(a) - assert loads(pickled_data) == a + assert (loads(pickled_data) == a).all() class AppTestMultiDim(BaseNumpyAppTest): def test_init(self): From noreply at buildbot.pypy.org Sat May 4 23:17:04 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 4 May 2013 23:17:04 +0200 (CEST) Subject: [pypy-commit] pypy py3k: show the warnings when this sporadically fails on the buildbots Message-ID: <20130504211704.B0D421C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63852:00cc4cbb9284 Date: 2013-05-04 14:16 -0700 http://bitbucket.org/pypy/pypy/changeset/00cc4cbb9284/ Log: show the warnings when this sporadically fails on the buildbots diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py --- a/pypy/module/_socket/test/test_sock_app.py +++ b/pypy/module/_socket/test/test_sock_app.py @@ -579,7 +579,7 @@ warnings.simplefilter('always') s = None gc.collect() - assert len(w) == 1 + assert len(w) == 1, [str(warning) for warning in w] assert r in str(w[0]) From noreply at buildbot.pypy.org Sun May 5 00:31:50 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 5 May 2013 00:31:50 +0200 (CEST) Subject: [pypy-commit] pypy py3k: gc unexpected cruft before the test Message-ID: <20130504223150.A3A821C0130@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63853:725a332705f6 Date: 2013-05-04 15:31 -0700 http://bitbucket.org/pypy/pypy/changeset/725a332705f6/ Log: gc unexpected cruft before the test diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -340,6 +340,7 @@ f = open(*args, **kwargs) r = repr(f) + gc.collect() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') f = None diff --git a/pypy/module/_socket/test/test_sock_app.py b/pypy/module/_socket/test/test_sock_app.py --- a/pypy/module/_socket/test/test_sock_app.py +++ b/pypy/module/_socket/test/test_sock_app.py @@ -575,6 +575,7 @@ s = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) r = repr(s) + gc.collect() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') s = None From noreply at buildbot.pypy.org Sun May 5 06:31:17 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 5 May 2013 06:31:17 +0200 (CEST) Subject: [pypy-commit] pypy default: some random pep8 cleanups Message-ID: <20130505043117.598F61C13F4@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r63854:f6d1a5b22c1f Date: 2013-05-04 21:30 -0700 http://bitbucket.org/pypy/pypy/changeset/f6d1a5b22c1f/ Log: some random pep8 cleanups diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -39,12 +39,10 @@ def unicode_w(w_self, space): # Use the default encoding. - from pypy.objspace.std.unicodetype import unicode_from_string, \ - decode_object + from pypy.objspace.std.unicodetype import (unicode_from_string, + decode_object, _get_encoding_and_errors) w_defaultencoding = space.call_function(space.sys.get( 'getdefaultencoding')) - from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \ - unicode_from_string, decode_object encoding, errors = _get_encoding_and_errors(space, w_defaultencoding, space.w_None) if encoding is None and errors is None: @@ -236,7 +234,7 @@ def str_title__String(space, w_self): input = w_self._value builder = StringBuilder(len(input)) - prev_letter=' ' + prev_letter = ' ' for pos in range(len(input)): ch = input[pos] @@ -434,7 +432,7 @@ space.wrap("rjust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self = d * fillchar + u_self @@ -450,7 +448,7 @@ space.wrap("ljust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self += d * fillchar @@ -471,12 +469,12 @@ return space.newbool(self.find(sub) >= 0) def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.find(w_sub._value, start, end) return space.wrap(res) def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.rfind(w_sub._value, start, end) return space.wrap(res) @@ -511,7 +509,7 @@ def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.find(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -521,7 +519,7 @@ def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.rfind(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -728,7 +726,7 @@ while 1: #no sophisticated linebreak support now, '\r' just for passing adapted CPython test if u_token[offset-1] == "\n" or u_token[offset-1] == "\r": - break; + break distance += 1 offset -= 1 if offset == 0: @@ -738,7 +736,7 @@ #print '' % (offset, distance, u_tabsize, u_token) distance = (u_tabsize-distance) % u_tabsize if distance == 0: - distance=u_tabsize + distance = u_tabsize return distance @@ -760,14 +758,14 @@ for token in split: #print "%d#%d -%s-" % (_tabindent(oldtoken,u_tabsize), u_tabsize, token) - u_expanded += " " * _tabindent(oldtoken,u_tabsize) + token + u_expanded += " " * _tabindent(oldtoken, u_tabsize) + token oldtoken = token return wrapstr(space, u_expanded) def str_splitlines__String_ANY(space, w_self, w_keepends): - u_keepends = space.int_w(w_keepends) # truth value, but type checked + u_keepends = space.int_w(w_keepends) # truth value, but type checked data = w_self._value selflen = len(data) strs_w = [] @@ -876,7 +874,6 @@ return wrapchar(space, str[ival]) def getitem__String_Slice(space, w_str, w_slice): - w = space.wrap s = w_str._value length = len(s) start, stop, step, sl = w_slice.indices4(space, length) From noreply at buildbot.pypy.org Sun May 5 10:42:04 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 5 May 2013 10:42:04 +0200 (CEST) Subject: [pypy-commit] pypy default: split collection of module/test_lib_pypy during nightly runs Message-ID: <20130505084204.B021D1C018D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63855:1e0d170b3c7f Date: 2013-05-05 10:40 +0200 http://bitbucket.org/pypy/pypy/changeset/1e0d170b3c7f/ Log: split collection of module/test_lib_pypy during nightly runs diff --git a/pypy/pytest-A.py b/pypy/pytest-A.py --- a/pypy/pytest-A.py +++ b/pypy/pytest-A.py @@ -6,6 +6,7 @@ 'interpreter/pyparser/test', 'interpreter/test', 'interpreter/test2', + 'module/test_lib_pypy', 'objspace/std/test', ], } From noreply at buildbot.pypy.org Sun May 5 12:09:58 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 5 May 2013 12:09:58 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: extend a bit on provided builds Message-ID: <20130505100958.6CE1A1C0135@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: extradoc Changeset: r4969:2c2a6d3a67ad Date: 2013-05-05 12:09 +0200 http://bitbucket.org/pypy/extradoc/changeset/2c2a6d3a67ad/ Log: extend a bit on provided builds diff --git a/blog/draft/pypy-alpha-arm.rst b/blog/draft/pypy-alpha-arm.rst --- a/blog/draft/pypy-alpha-arm.rst +++ b/blog/draft/pypy-alpha-arm.rst @@ -10,15 +10,17 @@ This is the first release that supports a range of ARM devices - anything with ARMv6 (like the Raspberry Pi) or ARMv7 (like Beagleboard, Chromebook, -Cubieboard, etc) that supports VFPv3 should work. +Cubieboard, etc.) that supports VFPv3 should work. We provide builds with +support for both ARM EABI variants, hard-float and for some older operating +systems soft-float. This release comes with a list of limitations, consider it alpha quality, not suitable for production: -* stackless support does not work +* stackless support is missing. * assembler produced is not always correct, but we successfully managed to - run our extensive benchmark suite, so most stuff should work + run large parts of our extensive benchmark suite, so most stuff should work. You can download the PyPy 2.0 alpha ARM release here: @@ -34,8 +36,16 @@ PyPy is a very compliant Python interpreter, almost a drop-in replacement for CPython 2.7.3. It's fast due to its integrated tracing JIT compiler. -This release supports ARM machines running Linux 32bit. Both ``armel`` -and ``armhf`` builds are provided. +This release supports ARM machines running Linux 32bit. Both hard-float +``armhf`` and soft-float ``armel`` builds are provided. ``armhf`` builds are +created using the Raspberry Pi custom `cross-compilation toolchain`_ based on +gcc-arm-linux-gnueabihf and should work on ARMv6 and ARMv7 devices running at +least debian or ubuntu. ``armel`` builds are built using gcc-arm-linux-gnuebi +toolchain provided by ubuntu and currently target ARMv7. If there is interest +in other builds, such as gnueabi for ARMv6 or without requiring a VFP let us +know in the comments or in IRC. + +.. _`cross-compilation custom toolchain`: https://github.com/raspberrypi Benchmarks ========== From noreply at buildbot.pypy.org Sun May 5 12:25:54 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 5 May 2013 12:25:54 +0200 (CEST) Subject: [pypy-commit] cffi default: Fix for enums used as bitfields. (thanks jerith) Message-ID: <20130505102554.924FD1C0135@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1248:a3f43e99b02e Date: 2013-05-05 12:25 +0200 http://bitbucket.org/cffi/cffi/changeset/a3f43e99b02e/ Log: Fix for enums used as bitfields. (thanks jerith) diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py --- a/cffi/vengine_cpy.py +++ b/cffi/vengine_cpy.py @@ -427,9 +427,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py --- a/cffi/vengine_gen.py +++ b/cffi/vengine_gen.py @@ -216,9 +216,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/testing/backend_tests.py b/testing/backend_tests.py --- a/testing/backend_tests.py +++ b/testing/backend_tests.py @@ -970,6 +970,16 @@ s.c = -4 assert s.c == -4 + def test_bitfield_enum(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef(""" + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_anonymous_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("typedef struct { int a; } foo_t;") diff --git a/testing/test_verify.py b/testing/test_verify.py --- a/testing/test_verify.py +++ b/testing/test_verify.py @@ -521,6 +521,18 @@ py.test.raises(OverflowError, "s.b = 4") assert s.b == 3 +def test_struct_with_bitfield_enum(): + ffi = FFI() + code = """ + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """ + ffi.cdef(code) + ffi.verify(code) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_unsupported_struct_with_bitfield_ellipsis(): ffi = FFI() py.test.raises(NotImplementedError, ffi.cdef, From noreply at buildbot.pypy.org Sun May 5 13:21:19 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 5 May 2013 13:21:19 +0200 (CEST) Subject: [pypy-commit] pypy default: Use the same seed() as CPython 2.7. Message-ID: <20130505112119.C04F31C018D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63856:0a3ad482ff72 Date: 2013-05-05 13:20 +0200 http://bitbucket.org/pypy/pypy/changeset/0a3ad482ff72/ Log: Use the same seed() as CPython 2.7. diff --git a/pypy/module/_random/interp_random.py b/pypy/module/_random/interp_random.py --- a/pypy/module/_random/interp_random.py +++ b/pypy/module/_random/interp_random.py @@ -33,8 +33,8 @@ elif space.isinstance_w(w_n, space.w_long): w_n = space.abs(w_n) else: - # XXX not perfectly like CPython - w_n = space.abs(space.hash(w_n)) + n = space.hash_w(w_n) + w_n = space.wrap(r_uint(n)) key = [] w_one = space.newint(1) w_two = space.newint(2) diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -42,13 +42,14 @@ rnd1.setstate((-1, ) * 624 + (0, )) def test_seed(self): - import _random + import _random, sys rnd = _random.Random() rnd.seed() different_nums = [] + mask = sys.maxint * 2 + 1 for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]: nums = [] - for o in [obj, hash(obj), -hash(obj)]: + for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]: rnd.seed(o) nums.append([rnd.random() for i in range(100)]) n1 = nums[0] From noreply at buildbot.pypy.org Sun May 5 14:04:22 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 5 May 2013 14:04:22 +0200 (CEST) Subject: [pypy-commit] pypy default: skip test_array_of_floats if the JIT in pypy-c does not support singlefloats Message-ID: <20130505120422.109441C13A8@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63858:b8f74ad1ded0 Date: 2013-05-05 14:00 +0200 http://bitbucket.org/pypy/pypy/changeset/b8f74ad1ded0/ Log: skip test_array_of_floats if the JIT in pypy-c does not support singlefloats diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -119,6 +119,12 @@ """) def test_array_of_floats(self): + try: + from __pypy__ import jit_backend_features + if 'singlefloats' not in jit_backend_features: + py.test.skip("test requres singlefloats support from the JIT backend") + except ImportError: + pass def main(): from array import array img = array('f', [21.5]*1000) From noreply at buildbot.pypy.org Sun May 5 14:04:20 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 5 May 2013 14:04:20 +0200 (CEST) Subject: [pypy-commit] pypy default: expose the supports_FEATURE flags from the jit backends as a list in the applevel __pypy__ module Message-ID: <20130505120420.B682F1C018D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63857:807dc54ee576 Date: 2013-05-05 13:46 +0200 http://bitbucket.org/pypy/pypy/changeset/807dc54ee576/ Log: expose the supports_FEATURE flags from the jit backends as a list in the applevel __pypy__ module diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -85,3 +85,7 @@ from rpython.jit.backend import detect_cpu model = detect_cpu.autodetect_main_model_and_size() self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + if self.space.config.translation.jit: + features = detect_cpu.getcpufeatures(model) + self.extra_interpdef('jit_backend_features', + 'space.wrap(%r)' % features) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -62,3 +62,14 @@ assert list_strategy(l) == "empty" o = 5 raises(TypeError, list_strategy, 5) + + +class AppTestJitFeatures(object): + spaceconfig = {"translation.jit": True} + + def test_jit_backend_features(self): + from __pypy__ import jit_backend_features + supported_types = jit_backend_features + assert isinstance(supported_types, list) + for x in supported_types: + assert x in ['floats', 'singlefloats', 'longlong'] diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -115,6 +115,13 @@ mod = __import__(modname, {}, {}, clsname) return getattr(mod, clsname) + +def getcpufeatures(backend_name="auto"): + """NOT_RPYTHON""" + cpucls = getcpuclass(backend_name) + return [attr[len('supports_'):] for attr in dir(cpucls) + if attr.startswith('supports_')] + if __name__ == '__main__': print autodetect() print getcpuclassname() diff --git a/rpython/jit/backend/test/test_detect_cpu.py b/rpython/jit/backend/test/test_detect_cpu.py --- a/rpython/jit/backend/test/test_detect_cpu.py +++ b/rpython/jit/backend/test/test_detect_cpu.py @@ -31,3 +31,9 @@ def test_detect_main_model_and_size_from_platform(): info = autodetect_main_model_and_size() assert detect_main_model_and_size_from_platform() == info + +def test_getcpufeatures(): + features = getcpufeatures() + assert isinstance(features, list) + for x in features: + assert x in ['floats', 'singlefloats', 'longlong'] From noreply at buildbot.pypy.org Sun May 5 14:04:23 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 5 May 2013 14:04:23 +0200 (CEST) Subject: [pypy-commit] pypy default: add osx support to getnightly Message-ID: <20130505120423.4260A1C018D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63859:d0631e2712ae Date: 2013-05-05 13:57 +0200 http://bitbucket.org/pypy/pypy/changeset/d0631e2712ae/ Log: add osx support to getnightly diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -6,8 +6,14 @@ if sys.platform.startswith('linux'): arch = 'linux' + cmd = 'wget "%s"' + tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" +if sys.platform.startswith('darwin'): + arch = 'osx' + cmd = 'curl -O "%s"' + tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" else: - print 'Cannot determine the platform, please update this scrip' + print 'Cannot determine the platform, please update this script' sys.exit(1) if sys.maxint == 2**63 - 1: @@ -23,10 +29,9 @@ tmp = py.path.local.mkdtemp() mydir = tmp.chdir() print 'Downloading pypy to', tmp -if os.system('wget "%s"' % url) != 0: +if os.system(cmd % url) != 0: sys.exit(1) print 'Extracting pypy binary' mydir.chdir() -os.system("tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" % tmp.join(filename)) - +os.system(tar % tmp.join(filename)) From noreply at buildbot.pypy.org Sun May 5 14:04:24 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 5 May 2013 14:04:24 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130505120424.82CD51C018D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63860:6e75b7739261 Date: 2013-05-05 14:02 +0200 http://bitbucket.org/pypy/pypy/changeset/6e75b7739261/ Log: merge heads diff --git a/pypy/module/_random/interp_random.py b/pypy/module/_random/interp_random.py --- a/pypy/module/_random/interp_random.py +++ b/pypy/module/_random/interp_random.py @@ -33,8 +33,8 @@ elif space.isinstance_w(w_n, space.w_long): w_n = space.abs(w_n) else: - # XXX not perfectly like CPython - w_n = space.abs(space.hash(w_n)) + n = space.hash_w(w_n) + w_n = space.wrap(r_uint(n)) key = [] w_one = space.newint(1) w_two = space.newint(2) diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -42,13 +42,14 @@ rnd1.setstate((-1, ) * 624 + (0, )) def test_seed(self): - import _random + import _random, sys rnd = _random.Random() rnd.seed() different_nums = [] + mask = sys.maxint * 2 + 1 for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]: nums = [] - for o in [obj, hash(obj), -hash(obj)]: + for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]: rnd.seed(o) nums.append([rnd.random() for i in range(100)]) n1 = nums[0] From noreply at buildbot.pypy.org Sun May 5 14:56:07 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 5 May 2013 14:56:07 +0200 (CEST) Subject: [pypy-commit] cffi default: Document a more "real" implementation :-) Message-ID: <20130505125607.4D42E1C1033@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1249:5d2980c12007 Date: 2013-05-05 14:55 +0200 http://bitbucket.org/cffi/cffi/changeset/5d2980c12007/ Log: Document a more "real" implementation :-) diff --git a/demo/gmp.py b/demo/gmp.py --- a/demo/gmp.py +++ b/demo/gmp.py @@ -1,6 +1,12 @@ import sys import cffi +# +# This is only a demo based on the GMP library. +# There is a rather more complete version available at: +# http://bazaar.launchpad.net/~tolot-solar-empire/+junk/gmpy_cffi/files +# + ffi = cffi.FFI() ffi.cdef(""" From noreply at buildbot.pypy.org Sun May 5 16:10:11 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 5 May 2013 16:10:11 +0200 (CEST) Subject: [pypy-commit] pypy default: skip test_setitem_slice_performance on ARM Message-ID: <20130505141011.6CAA51C0135@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63861:c2fa8ac5a7c8 Date: 2013-05-05 09:03 -0500 http://bitbucket.org/pypy/pypy/changeset/c2fa8ac5a7c8/ Log: skip test_setitem_slice_performance on ARM diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -948,6 +948,9 @@ def test_setitem_slice_performance(self): # because of a complexity bug, this used to take forever on a # translated pypy. On CPython2.6 -A, it takes around 5 seconds. + import platform + if platform.machine().startswith('arm'): + skip("consumes too much memory for most ARM machines") if self.runappdirect: count = 16*1024*1024 else: From noreply at buildbot.pypy.org Sun May 5 16:10:12 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 5 May 2013 16:10:12 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130505141012.DB6321C0135@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63862:bc24f91f3054 Date: 2013-05-05 09:04 -0500 http://bitbucket.org/pypy/pypy/changeset/bc24f91f3054/ Log: merge heads diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -167,7 +167,6 @@ return if '_fields_' not in self.__dict__: self._fields_ = [] - self._names = [] _set_shape(self, [], self._is_union) __setattr__ = struct_setattr diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.0.rst @@ -0,0 +1,61 @@ +============================ +PyPy 2.0 - Einstein Sandwich +============================ + +We're pleased to announce PyPy 2.0. This is a stable release that brings +a swath of bugfixes, small performance improvements and compatibility fixes. + +You can download the PyPy 2.0 release here: + + http://pypy.org/download.html + +The two biggest changes since PyPy 1.9 are: + +* stackless is now supported including greenlets, which means eventlet + and gevent should work (but read below about gevent) + +* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which + is preferred way of calling C from Python that works well on PyPy + +.. _`cffi`: http://cffi.readthedocs.org + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Windows 64 work is still stalling, we would welcome a volunteer +to handle that. ARM support is on the way and we're expecting to release +an alpha ARM version shortly. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +* Stackless including greenlets should work. For gevent, you need to check + out `pypycore`_ and use the `pypy-hacks`_ branch of gevent. + +* cffi is now a module included with PyPy. (`cffi`_ also exists for + CPython; the two versions should be fully compatible.) It is the + preferred way of calling C from Python that works on PyPy. + +* Callbacks from C are now JITted, which means XML parsing is much faster. + +* A lot of speed improvements in various language corners, most of them small, + but speeding up some particular corners a lot. + +* The JIT was refactored to emit machine code which manipulates a "frame" + that lives on the heap rather than on the stack. This is what makes + Stackless work, and it could bring another future speed-up (not done yet). + +* A lot of stability issues fixed. + +.. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ +.. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks + +Cheers, +fijal, arigo and the PyPy team 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 @@ -5,4 +5,3 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 - diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -6,8 +6,14 @@ if sys.platform.startswith('linux'): arch = 'linux' + cmd = 'wget "%s"' + tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" +if sys.platform.startswith('darwin'): + arch = 'osx' + cmd = 'curl -O "%s"' + tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" else: - print 'Cannot determine the platform, please update this scrip' + print 'Cannot determine the platform, please update this script' sys.exit(1) if sys.maxint == 2**63 - 1: @@ -23,10 +29,9 @@ tmp = py.path.local.mkdtemp() mydir = tmp.chdir() print 'Downloading pypy to', tmp -if os.system('wget "%s"' % url) != 0: +if os.system(cmd % url) != 0: sys.exit(1) print 'Extracting pypy binary' mydir.chdir() -os.system("tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" % tmp.join(filename)) - +os.system(tar % tmp.join(filename)) diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -85,3 +85,7 @@ from rpython.jit.backend import detect_cpu model = detect_cpu.autodetect_main_model_and_size() self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + if self.space.config.translation.jit: + features = detect_cpu.getcpufeatures(model) + self.extra_interpdef('jit_backend_features', + 'space.wrap(%r)' % features) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -62,3 +62,14 @@ assert list_strategy(l) == "empty" o = 5 raises(TypeError, list_strategy, 5) + + +class AppTestJitFeatures(object): + spaceconfig = {"translation.jit": True} + + def test_jit_backend_features(self): + from __pypy__ import jit_backend_features + supported_types = jit_backend_features + assert isinstance(supported_types, list) + for x in supported_types: + assert x in ['floats', 'singlefloats', 'longlong'] diff --git a/pypy/module/_random/interp_random.py b/pypy/module/_random/interp_random.py --- a/pypy/module/_random/interp_random.py +++ b/pypy/module/_random/interp_random.py @@ -33,8 +33,8 @@ elif space.isinstance_w(w_n, space.w_long): w_n = space.abs(w_n) else: - # XXX not perfectly like CPython - w_n = space.abs(space.hash(w_n)) + n = space.hash_w(w_n) + w_n = space.wrap(r_uint(n)) key = [] w_one = space.newint(1) w_two = space.newint(2) diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -42,13 +42,14 @@ rnd1.setstate((-1, ) * 624 + (0, )) def test_seed(self): - import _random + import _random, sys rnd = _random.Random() rnd.seed() different_nums = [] + mask = sys.maxint * 2 + 1 for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]: nums = [] - for o in [obj, hash(obj), -hash(obj)]: + for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]: rnd.seed(o) nums.append([rnd.random() for i in range(100)]) n1 = nums[0] diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -119,6 +119,12 @@ """) def test_array_of_floats(self): + try: + from __pypy__ import jit_backend_features + if 'singlefloats' not in jit_backend_features: + py.test.skip("test requres singlefloats support from the JIT backend") + except ImportError: + pass def main(): from array import array img = array('f', [21.5]*1000) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -230,6 +230,17 @@ pt = POINT(y=2, x=1) assert (pt.x, pt.y) == (1, 2) + def test_subclass_initializer(self): + class POINT(Structure): + _fields_ = [("x", c_int), ("y", c_int)] + + class POSITION(POINT): + # A subclass without _fields_ + pass + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) + + def test_invalid_field_types(self): class POINT(Structure): pass @@ -538,6 +549,7 @@ raises(AttributeError, setattr, X, "_fields_", []) Y.__fields__ = [] + class TestPatologicalCases(BaseCTypesTestChecker): def test_structure_overloading_getattr(self): class X(Structure): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -39,12 +39,10 @@ def unicode_w(w_self, space): # Use the default encoding. - from pypy.objspace.std.unicodetype import unicode_from_string, \ - decode_object + from pypy.objspace.std.unicodetype import (unicode_from_string, + decode_object, _get_encoding_and_errors) w_defaultencoding = space.call_function(space.sys.get( 'getdefaultencoding')) - from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \ - unicode_from_string, decode_object encoding, errors = _get_encoding_and_errors(space, w_defaultencoding, space.w_None) if encoding is None and errors is None: @@ -236,7 +234,7 @@ def str_title__String(space, w_self): input = w_self._value builder = StringBuilder(len(input)) - prev_letter=' ' + prev_letter = ' ' for pos in range(len(input)): ch = input[pos] @@ -434,7 +432,7 @@ space.wrap("rjust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self = d * fillchar + u_self @@ -450,7 +448,7 @@ space.wrap("ljust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self += d * fillchar @@ -471,12 +469,12 @@ return space.newbool(self.find(sub) >= 0) def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.find(w_sub._value, start, end) return space.wrap(res) def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.rfind(w_sub._value, start, end) return space.wrap(res) @@ -511,7 +509,7 @@ def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.find(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -521,7 +519,7 @@ def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.rfind(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -728,7 +726,7 @@ while 1: #no sophisticated linebreak support now, '\r' just for passing adapted CPython test if u_token[offset-1] == "\n" or u_token[offset-1] == "\r": - break; + break distance += 1 offset -= 1 if offset == 0: @@ -738,7 +736,7 @@ #print '' % (offset, distance, u_tabsize, u_token) distance = (u_tabsize-distance) % u_tabsize if distance == 0: - distance=u_tabsize + distance = u_tabsize return distance @@ -760,14 +758,14 @@ for token in split: #print "%d#%d -%s-" % (_tabindent(oldtoken,u_tabsize), u_tabsize, token) - u_expanded += " " * _tabindent(oldtoken,u_tabsize) + token + u_expanded += " " * _tabindent(oldtoken, u_tabsize) + token oldtoken = token return wrapstr(space, u_expanded) def str_splitlines__String_ANY(space, w_self, w_keepends): - u_keepends = space.int_w(w_keepends) # truth value, but type checked + u_keepends = space.int_w(w_keepends) # truth value, but type checked data = w_self._value selflen = len(data) strs_w = [] @@ -876,7 +874,6 @@ return wrapchar(space, str[ival]) def getitem__String_Slice(space, w_str, w_slice): - w = space.wrap s = w_str._value length = len(s) start, stop, step, sl = w_slice.indices4(space, length) diff --git a/pypy/pytest-A.py b/pypy/pytest-A.py --- a/pypy/pytest-A.py +++ b/pypy/pytest-A.py @@ -6,6 +6,7 @@ 'interpreter/pyparser/test', 'interpreter/test', 'interpreter/test2', + 'module/test_lib_pypy', 'objspace/std/test', ], } diff --git a/rpython/jit/backend/arm/test/test_fficall.py b/rpython/jit/backend/arm/test/test_fficall.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/test/test_fficall.py @@ -0,0 +1,23 @@ +import py +from rpython.jit.metainterp.test import test_fficall +from rpython.jit.backend.arm.test.support import JitARMMixin + +class TestFfiCall(JitARMMixin, test_fficall.FfiCallTests): + # for the individual tests see + # ====> ../../../metainterp/test/test_fficall.py + + def _add_libffi_types_to_ll2types_maybe(self): + # this is needed by test_guard_not_forced_fails, because it produces a + # loop which reads the value of types.* in a variable, then a guard + # fail and we switch to blackhole: the problem is that at this point + # the blackhole interp has a real integer, but it needs to convert it + # back to a lltype pointer (which is handled by ll2ctypes, deeply in + # the logic). The workaround is to teach ll2ctypes in advance which + # are the addresses of the various types.* structures. + # Try to comment this code out and run the test to see how it fails :) + from rpython.rtyper.lltypesystem import rffi, lltype, ll2ctypes + from rpython.rlib.jit_libffi import types + for key, value in types.__dict__.iteritems(): + if isinstance(value, lltype._ptr): + addr = rffi.cast(lltype.Signed, value) + ll2ctypes._int2obj[addr] = value diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -115,6 +115,13 @@ mod = __import__(modname, {}, {}, clsname) return getattr(mod, clsname) + +def getcpufeatures(backend_name="auto"): + """NOT_RPYTHON""" + cpucls = getcpuclass(backend_name) + return [attr[len('supports_'):] for attr in dir(cpucls) + if attr.startswith('supports_')] + if __name__ == '__main__': print autodetect() print getcpuclassname() diff --git a/rpython/jit/backend/test/test_detect_cpu.py b/rpython/jit/backend/test/test_detect_cpu.py --- a/rpython/jit/backend/test/test_detect_cpu.py +++ b/rpython/jit/backend/test/test_detect_cpu.py @@ -31,3 +31,9 @@ def test_detect_main_model_and_size_from_platform(): info = autodetect_main_model_and_size() assert detect_main_model_and_size_from_platform() == info + +def test_getcpufeatures(): + features = getcpufeatures() + assert isinstance(features, list) + for x in features: + assert x in ['floats', 'singlefloats', 'longlong'] diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py --- a/rpython/memory/gctransform/transform.py +++ b/rpython/memory/gctransform/transform.py @@ -281,11 +281,11 @@ def finish_helpers(self, backendopt=True): if self.translator is not None: self.mixlevelannotator.finish_annotate() - self.finished_helpers = True if self.translator is not None: self.mixlevelannotator.finish_rtype() if backendopt: self.mixlevelannotator.backend_optimize() + self.finished_helpers = True # Make sure that the database also sees all finalizers now. # It is likely that the finalizers need special support there newgcdependencies = self.ll_finalizers_ptrs From noreply at buildbot.pypy.org Sun May 5 20:55:38 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 5 May 2013 20:55:38 +0200 (CEST) Subject: [pypy-commit] pypy py3k: help the test_bz2_file tests cleanup after themselves: have Message-ID: <20130505185538.A96991C1033@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63863:ed097f0bdea7 Date: 2013-05-05 11:46 -0700 http://bitbucket.org/pypy/pypy/changeset/ed097f0bdea7/ Log: help the test_bz2_file tests cleanup after themselves: have enqueue_for_destruction callbacks triggered by leakfinder invoke immediately instead of being scheduling for later (possibly never) diff --git a/pypy/conftest.py b/pypy/conftest.py --- a/pypy/conftest.py +++ b/pypy/conftest.py @@ -178,7 +178,23 @@ __multicall__.execute() def pytest_runtest_teardown(__multicall__, item): - __multicall__.execute() + user_del_action = None + if isinstance(item, py.test.collect.Function): + appclass = item.getparent(PyPyClassCollector) + if appclass is not None and not appclass.obj.runappdirect: + user_del_action = appclass.obj.space.user_del_action + + if user_del_action: + # if leakfinder triggers leftover __del__s, ensure their + # enqueue_for_destruction callbacks are invoked immediately + # instead of scheduled for later (potentially never) + user_del_action._invoke_immediately = True + try: + # leakfinder + __multicall__.execute() + finally: + if user_del_action: + user_del_action._invoke_immediately = False if 'pygame' in sys.modules: assert option.view, ("should not invoke Pygame " diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py --- a/pypy/interpreter/executioncontext.py +++ b/pypy/interpreter/executioncontext.py @@ -446,10 +446,14 @@ self.dying_objects = [] self.finalizers_lock_count = 0 self.enabled_at_app_level = True + self._invoke_immediately = False def register_callback(self, w_obj, callback, descrname): self.dying_objects.append((w_obj, callback, descrname)) - self.fire() + if not self._invoke_immediately: + self.fire() + else: + self.perform(None, None) def perform(self, executioncontext, frame): if self.finalizers_lock_count > 0: From noreply at buildbot.pypy.org Sun May 5 20:55:40 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 5 May 2013 20:55:40 +0200 (CEST) Subject: [pypy-commit] pypy py3k: always cleanup _decompressor/_compressor, aids cleanup when BZ2File() fails Message-ID: <20130505185540.413A91C13A8@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63864:5f367497a86c Date: 2013-05-05 11:47 -0700 http://bitbucket.org/pypy/pypy/changeset/5f367497a86c/ Log: always cleanup _decompressor/_compressor, aids cleanup when BZ2File() fails diff --git a/pypy/module/bz2/app_bz2file.py b/pypy/module/bz2/app_bz2file.py --- a/pypy/module/bz2/app_bz2file.py +++ b/pypy/module/bz2/app_bz2file.py @@ -92,11 +92,8 @@ if self._mode == _MODE_CLOSED: return try: - if self._mode in (_MODE_READ, _MODE_READ_EOF): - self._decompressor = None - elif self._mode == _MODE_WRITE: + if self._mode == _MODE_WRITE: self._fp.write(self._compressor.flush()) - self._compressor = None finally: try: if self._closefp: @@ -105,7 +102,7 @@ self._fp = None self._closefp = False self._mode = _MODE_CLOSED - self._buffer = None + self._buffer = self._decompressor = self._compressor = None @property def closed(self): From noreply at buildbot.pypy.org Sun May 5 20:55:41 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 5 May 2013 20:55:41 +0200 (CEST) Subject: [pypy-commit] pypy default: typo Message-ID: <20130505185541.9B0291C1457@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63865:ad2acb2c1076 Date: 2013-05-05 11:54 -0700 http://bitbucket.org/pypy/pypy/changeset/ad2acb2c1076/ Log: typo diff --git a/pypy/module/_io/__init__.py b/pypy/module/_io/__init__.py --- a/pypy/module/_io/__init__.py +++ b/pypy/module/_io/__init__.py @@ -38,5 +38,5 @@ def shutdown(self, space): # at shutdown, flush all open streams. Ignore I/O errors. - from pypy.module._io.interp_iobase import get_autoflushher - get_autoflushher(space).flush_all(space) + from pypy.module._io.interp_iobase import get_autoflusher + get_autoflusher(space).flush_all(space) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -47,7 +47,7 @@ self.w_dict = space.newdict() self.__IOBase_closed = False self.streamholder = None # needed by AutoFlusher - get_autoflushher(space).add(self) + get_autoflusher(space).add(self) def getdict(self, space): return self.w_dict @@ -103,7 +103,7 @@ space.call_method(self, "flush") finally: self.__IOBase_closed = True - get_autoflushher(space).remove(self) + get_autoflusher(space).remove(self) def flush_w(self, space): if self._CLOSED(): @@ -363,5 +363,5 @@ else: streamholder.autoflush(space) -def get_autoflushher(space): +def get_autoflusher(space): return space.fromcache(AutoFlusher) From noreply at buildbot.pypy.org Sun May 5 21:19:55 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 5 May 2013 21:19:55 +0200 (CEST) Subject: [pypy-commit] pypy default: collect subdirectories of test directories Message-ID: <20130505191955.E66A91C0135@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63866:f9afe3b56890 Date: 2013-05-05 21:19 +0200 http://bitbucket.org/pypy/pypy/changeset/f9afe3b56890/ Log: collect subdirectories of test directories diff --git a/testrunner/runner.py b/testrunner/runner.py --- a/testrunner/runner.py +++ b/testrunner/runner.py @@ -329,7 +329,7 @@ self.collect_one_testdir(testdirs, reldir, [self.reltoroot(t) for t in entries if self.is_test_py_file(t)]) - return + break for p1 in entries: if p1.check(dir=1, link=0): From noreply at buildbot.pypy.org Sun May 5 21:41:54 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 5 May 2013 21:41:54 +0200 (CEST) Subject: [pypy-commit] pypy py3k: Backed out changeset 5f367497a86c: this actually isn't necessary Message-ID: <20130505194154.E00011C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63867:15ae2a6b2fd8 Date: 2013-05-05 12:23 -0700 http://bitbucket.org/pypy/pypy/changeset/15ae2a6b2fd8/ Log: Backed out changeset 5f367497a86c: this actually isn't necessary diff --git a/pypy/module/bz2/app_bz2file.py b/pypy/module/bz2/app_bz2file.py --- a/pypy/module/bz2/app_bz2file.py +++ b/pypy/module/bz2/app_bz2file.py @@ -92,8 +92,11 @@ if self._mode == _MODE_CLOSED: return try: - if self._mode == _MODE_WRITE: + if self._mode in (_MODE_READ, _MODE_READ_EOF): + self._decompressor = None + elif self._mode == _MODE_WRITE: self._fp.write(self._compressor.flush()) + self._compressor = None finally: try: if self._closefp: @@ -102,7 +105,7 @@ self._fp = None self._closefp = False self._mode = _MODE_CLOSED - self._buffer = self._decompressor = self._compressor = None + self._buffer = None @property def closed(self): From noreply at buildbot.pypy.org Sun May 5 22:30:48 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 5 May 2013 22:30:48 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix Message-ID: <20130505203048.D584F1C13A8@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63868:c334eced9ccb Date: 2013-05-05 13:29 -0700 http://bitbucket.org/pypy/pypy/changeset/c334eced9ccb/ Log: fix diff --git a/pypy/conftest.py b/pypy/conftest.py --- a/pypy/conftest.py +++ b/pypy/conftest.py @@ -181,7 +181,9 @@ user_del_action = None if isinstance(item, py.test.collect.Function): appclass = item.getparent(PyPyClassCollector) - if appclass is not None and not appclass.obj.runappdirect: + if (appclass is not None and + not getattr(appclass.obj, 'runappdirect', False) and + hasattr(appclass.obj, 'space')): user_del_action = appclass.obj.space.user_del_action if user_del_action: From noreply at buildbot.pypy.org Mon May 6 08:12:29 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 6 May 2013 08:12:29 +0200 (CEST) Subject: [pypy-commit] pypy default: only expose supported_xxx flags that are true Message-ID: <20130506061229.8C15F1C1324@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r63869:6eb78b19aeaa Date: 2013-05-06 08:11 +0200 http://bitbucket.org/pypy/pypy/changeset/6eb78b19aeaa/ Log: only expose supported_xxx flags that are true diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -120,7 +120,8 @@ """NOT_RPYTHON""" cpucls = getcpuclass(backend_name) return [attr[len('supports_'):] for attr in dir(cpucls) - if attr.startswith('supports_')] + if attr.startswith('supports_') + and getattr(cpucls, attr)] if __name__ == '__main__': print autodetect() From noreply at buildbot.pypy.org Mon May 6 10:02:11 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Mon, 6 May 2013 10:02:11 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added test for no-context-switch: Message-ID: <20130506080211.64F511C0307@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r374:1038e524af02 Date: 2013-05-06 10:01 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/1038e524af02/ Log: added test for no-context-switch: testing for not calling quick_check_for_interrupts on closure activation diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py --- a/spyvm/test/test_primitives.py +++ b/spyvm/test/test_primitives.py @@ -638,6 +638,46 @@ assert w_2.getclass(space) is space.w_Array assert w_1 is not w_2 +def test_primitive_value_no_context_switch(monkeypatch): + class Context_switched(Exception): + pass + class Stepping(Exception): + pass + + def quick_check_for_interrupt(s_frame, dec=1): + raise Context_switched + def step(s_frame): + raise Stepping + + from test_interpreter import new_frame + w_frame, s_initial_context = new_frame("", + space=space) + + closure = space.newClosure(w_frame, 4, 0, []) + s_frame = w_frame.as_methodcontext_get_shadow(space) + interp = interpreter.Interpreter(space, image_name=IMAGENAME) + interp._loop = True + + try: + monkeypatch.setattr(interp, "quick_check_for_interrupt", quick_check_for_interrupt) + monkeypatch.setattr(interp, "step", step) + try: + s_frame.push(closure) + prim_table[primitives.CLOSURE_VALUE](interp, s_frame, 0) + except Context_switched: + assert True + except Stepping: + assert False + try: + s_frame.push(closure) + prim_table[primitives.CLOSURE_VALUE_NO_CONTEXT_SWITCH](interp, s_frame, 0) + except Context_switched: + assert False + except Stepping: + assert True + finally: + monkeypatch.undo() + def test_primitive_be_display(): # XXX: Patch SDLDisplay -> get_pixelbuffer() to circumvent # double-free bug From noreply at buildbot.pypy.org Mon May 6 13:00:50 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 6 May 2013 13:00:50 +0200 (CEST) Subject: [pypy-commit] pypy default: cppyy depends on cpyext. This will automatically disable cppyy too when translating "--withoutmod-cpyext". Message-ID: <20130506110050.8680E1C32FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63870:e675c7552c85 Date: 2013-05-06 13:03 +0200 http://bitbucket.org/pypy/pypy/changeset/e675c7552c85/ Log: cppyy depends on cpyext. This will automatically disable cppyy too when translating "--withoutmod-cpyext". diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -84,6 +84,7 @@ '_multiprocessing': [('objspace.usemodules.rctime', True), ('objspace.usemodules.thread', True)], 'cpyext': [('objspace.usemodules.array', True)], + 'cppyy': [('objspace.usemodules.cpyext', True)], } module_suggests = { # the reason you want _rawffi is for ctypes, which From noreply at buildbot.pypy.org Mon May 6 13:35:02 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 6 May 2013 13:35:02 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix on x86 32-bit. Message-ID: <20130506113502.20C811C0307@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63871:5fa8bdf60774 Date: 2013-05-06 11:37 +0000 http://bitbucket.org/pypy/pypy/changeset/5fa8bdf60774/ Log: Fix on x86 32-bit. diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -96,7 +96,7 @@ def getcpuclassname(backend_name="auto"): if backend_name == "auto": backend_name = autodetect() - if backend_name == 'x86': + if backend_name == 'x86' or backend_name == 'x86_32': return "rpython.jit.backend.x86.runner", "CPU" elif backend_name == 'x86-without-sse2': return "rpython.jit.backend.x86.runner", "CPU386_NO_SSE2" From noreply at buildbot.pypy.org Mon May 6 14:32:00 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 6 May 2013 14:32:00 +0200 (CEST) Subject: [pypy-commit] pypy default: Slim down the mess in detect_cpu. Message-ID: <20130506123200.83B9B1C13A8@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63876:ca87dbabe3df Date: 2013-05-06 14:31 +0200 http://bitbucket.org/pypy/pypy/changeset/ca87dbabe3df/ Log: Slim down the mess in detect_cpu. diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -82,9 +82,16 @@ PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) # - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + try: + from rpython.jit.backend import detect_cpu + model = detect_cpu.autodetect() + self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + except Exception: + if self.space.config.translation.jit: + raise + else: + pass # ok fine to ignore in this case + # if self.space.config.translation.jit: features = detect_cpu.getcpufeatures(model) self.extra_interpdef('jit_backend_features', diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -4,7 +4,7 @@ parse_log_counts) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys -from rpython.jit.backend.detect_cpu import autodetect_main_model +from rpython.jit.backend.detect_cpu import autodetect def parse(input, **kwds): return SimpleParser.parse_from_input(input, **kwds) @@ -189,7 +189,7 @@ assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" dump_start = 0x7f3b0b2e63d5 @@ -218,7 +218,7 @@ assert 'jmp' in loop.operations[-1].asm def test_parsing_arm_assembler(): - if not autodetect_main_model() == 'arm': + if not autodetect().startswith('arm'): py.test.skip('ARM only test') backend_dump = "F04F2DE9108B2DED2CD04DE20DB0A0E17CC302E3DFC040E300409CE5085084E2086000E3006084E504B084E500508CE508D04BE20000A0E10000A0E1B0A10DE30EA044E300A09AE501A08AE2B0910DE30E9044E300A089E5C0910DE30E9044E3009099E5019089E2C0A10DE30EA044E300908AE5010050E1700020E124A092E500C08AE00C90DCE5288000E3090058E10180A0030080A013297000E3090057E10170A0030070A013077088E1200059E30180A0030080A013099049E2050059E30190A0330090A023099088E1000059E30190A0130090A003099087E1000059E3700020E1010080E204200BE5D0210DE30E2044E3002092E5012082E2D0910DE30E9044E3002089E5010050E1700020E100C08AE00C90DCE5282000E3090052E10120A0030020A013297000E3090057E10170A0030070A013077082E1200059E30120A0030020A013099049E2050059E30190A0330090A023099082E1000059E30190A0130090A003099087E1000059E3700020E1010080E20D005BE10FF0A0A1700020E1D8FFFFEA68C100E301C04BE33CFF2FE105010803560000000000000068C100E301C04BE33CFF2FE105010803570000000000000068C100E301C04BE33CFF2FE105014003580000000000000068C100E301C04BE33CFF2FE1050140035900000000000000" dump_start = int(-0x4ffee930) @@ -272,7 +272,7 @@ def test_import_log(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) @@ -281,7 +281,7 @@ assert 'jge' in loops[0].operations[3].asm def test_import_log_2(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -10,31 +10,31 @@ pass -def detect_main_model_and_size_from_platform(): +MODEL_X86 = 'x86' +MODEL_X86_NO_SSE2 = 'x86-without-sse2' +MODEL_X86_64 = 'x86-64' +MODEL_ARM = 'arm' +MODEL_PPC_64 = 'ppc-64' +# don't use '_' in the model strings; they are replaced by '-' + + +def detect_model_from_c_compiler(): # based on http://sourceforge.net/p/predef/wiki/Architectures/ mapping = { - ('x86', '64'): [ - '__amd64__', '__amd64', '__x86_64__', '__x86_64', # AMD64 - ], - ('arm', '32'): ['__arm__', '__thumb__'], - ('x86', '32'): ['i386', '__i386', '__i386__', '__i686__',], - ('ppc', '64'): ['__powerpc64__'], + MODEL_X86_64: ['__amd64__', '__amd64', '__x86_64__', '__x86_64'], + MODEL_ARM: ['__arm__', '__thumb__'], + MODEL_X86: ['i386', '__i386', '__i386__', '__i686__'], + MODEL_PPC_64: ['__powerpc64__'], } for k, v in mapping.iteritems(): for macro in v: if not getdefined(macro, ''): continue - return '_'.join(k) + return k raise ProcessorAutodetectError, "Cannot detect processor using compiler macros" -def detect_main_model_from_platform(): - return detect_main_model_and_size_from_platform()[0] - - -def autodetect_main_model(): - if not is_host_build(): - return detect_main_model_from_platform() +def detect_model_from_host_platform(): mach = None try: import platform @@ -44,67 +44,64 @@ if not mach: platform = sys.platform.lower() if platform.startswith('win'): # assume an Intel Windows - return 'x86' + return MODEL_X86 # assume we have 'uname' mach = os.popen('uname -m', 'r').read().strip() if not mach: raise ProcessorAutodetectError, "cannot run 'uname -m'" - try: - return {'i386': 'x86', - 'i486': 'x86', - 'i586': 'x86', - 'i686': 'x86', - 'i86pc': 'x86', # Solaris/Intel - 'x86': 'x86', # Apple - 'Power Macintosh': 'ppc', - 'x86_64': 'x86', - 'amd64': 'x86', # freebsd - 'AMD64': 'x86', # win64 - 'armv7l': 'arm', - 'armv6l': 'arm', - }[mach] - except KeyError: - return mach + # + result ={'i386': MODEL_X86, + 'i486': MODEL_X86, + 'i586': MODEL_X86, + 'i686': MODEL_X86, + 'i86pc': MODEL_X86, # Solaris/Intel + 'x86': MODEL_X86, # Apple + 'Power Macintosh': MODEL_PPC_64, + 'x86_64': MODEL_X86, + 'amd64': MODEL_X86, # freebsd + 'AMD64': MODEL_X86, # win64 + 'armv7l': MODEL_ARM, + 'armv6l': MODEL_ARM, + }[mach] + # + if result.startswith('x86'): + if sys.maxint == 2**63-1: + result = MODEL_X86_64 + else: + assert sys.maxint == 2**31-1 + from rpython.jit.backend.x86.detect_sse2 import detect_sse2 + if detect_sse2(): + result = MODEL_X86 + else: + result = MODEL_X86_NO_SSE2 + # + if result.startswith('arm'): + from rpython.jit.backend.arm.detect import detect_float + assert detect_float(), 'the JIT-compiler requires a vfp unit' + # + return result -def autodetect_main_model_and_size(): - if not is_host_build(): - return detect_main_model_and_size_from_platform() - model = autodetect_main_model() - if sys.maxint == 2**31-1: - model += '_32' - elif sys.maxint == 2**63-1: - model += '_64' - else: - raise AssertionError, "bad value for sys.maxint" - return model def autodetect(): - model = autodetect_main_model() - if sys.maxint == 2**63-1: - model += '_64' + if not is_host_build(): + return detect_model_from_c_compiler() else: - assert sys.maxint == 2**31-1 - if model == 'x86': - from rpython.jit.backend.x86.detect_sse2 import detect_sse2 - if not detect_sse2(): - model = 'x86-without-sse2' - if model.startswith('arm'): - from rpython.jit.backend.arm.detect import detect_hardfloat, detect_float - assert detect_float(), 'the JIT-compiler requires a vfp unit' - return model + return detect_model_from_host_platform() + def getcpuclassname(backend_name="auto"): if backend_name == "auto": backend_name = autodetect() - if backend_name == 'x86' or backend_name == 'x86_32': + backend_name = backend_name.replace('_', '-') + if backend_name == MODEL_X86: return "rpython.jit.backend.x86.runner", "CPU" - elif backend_name == 'x86-without-sse2': + elif backend_name == MODEL_X86_NO_SSE2: return "rpython.jit.backend.x86.runner", "CPU386_NO_SSE2" - elif backend_name == 'x86_64': + elif backend_name == MODEL_X86_64: return "rpython.jit.backend.x86.runner", "CPU_X86_64" - elif backend_name == 'cli': - return "rpython.jit.backend.cli.runner", "CliCPU" - elif backend_name.startswith('arm'): + #elif backend_name == 'cli': + # return "rpython.jit.backend.cli.runner", "CliCPU" + elif backend_name == MODEL_ARM: return "rpython.jit.backend.arm.runner", "CPU_ARM" else: raise ProcessorAutodetectError, ( @@ -124,5 +121,13 @@ and getattr(cpucls, attr)] if __name__ == '__main__': - print autodetect() - print getcpuclassname() + if len(sys.argv) > 1: + name = sys.argv[1] + x = name + else: + name = 'auto' + x = autodetect() + x = (x, getcpuclassname(name), getcpufeatures(name)) + print 'autodetect: ', x[0] + print 'getcpuclassname:', x[1] + print 'getcpufeatures: ', x[2] diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -18,7 +18,7 @@ from rpython.jit.codewriter import heaptracker, longlong from rpython.rlib import longlong2float from rpython.rlib.rarithmetic import intmask, is_valid_int -from rpython.jit.backend.detect_cpu import autodetect_main_model_and_size +from rpython.jit.backend.detect_cpu import autodetect from rpython.jit.backend.llsupport import jitframe @@ -3539,7 +3539,7 @@ looptoken) self.cpu.assembler.set_debug(True) # always on untranslated assert info.asmlen != 0 - cpuname = autodetect_main_model_and_size() + cpuname = autodetect() # XXX we have to check the precise assembler, otherwise # we don't quite know if borders are correct diff --git a/rpython/jit/backend/test/test_detect_cpu.py b/rpython/jit/backend/test/test_detect_cpu.py --- a/rpython/jit/backend/test/test_detect_cpu.py +++ b/rpython/jit/backend/test/test_detect_cpu.py @@ -28,9 +28,10 @@ assert issubclass(cpu, AbstractCPU) -def test_detect_main_model_and_size_from_platform(): - info = autodetect_main_model_and_size() - assert detect_main_model_and_size_from_platform() == info +def test_detect_model_from_c_compiler(): + info1 = detect_model_from_host_platform() + info2 = detect_model_from_c_compiler() + assert info1 == info2 def test_getcpufeatures(): features = getcpufeatures() diff --git a/rpython/jit/backend/tool/viewcode.py b/rpython/jit/backend/tool/viewcode.py --- a/rpython/jit/backend/tool/viewcode.py +++ b/rpython/jit/backend/tool/viewcode.py @@ -50,9 +50,12 @@ def machine_code_dump(data, originaddr, backend_name, label_list=None): objdump_backend_option = { 'x86': 'i386', + 'x86-without-sse2': 'i386', 'x86_32': 'i386', 'x86_64': 'x86-64', + 'x86-64': 'x86-64', 'i386': 'i386', + 'arm': 'arm', 'arm_32': 'arm', } cmd = find_objdump() diff --git a/rpython/jit/backend/x86/test/conftest.py b/rpython/jit/backend/x86/test/conftest.py --- a/rpython/jit/backend/x86/test/conftest.py +++ b/rpython/jit/backend/x86/test/conftest.py @@ -3,7 +3,7 @@ cpu = detect_cpu.autodetect() def pytest_runtest_setup(item): - if cpu not in ('x86', 'x86_64'): + if not cpu.startswith('x86'): py.test.skip("x86/x86_64 tests skipped: cpu is %r" % (cpu,)) if cpu == 'x86_64': if os.name == "nt": diff --git a/rpython/translator/c/gcc/test/conftest.py b/rpython/translator/c/gcc/test/conftest.py --- a/rpython/translator/c/gcc/test/conftest.py +++ b/rpython/translator/c/gcc/test/conftest.py @@ -2,5 +2,5 @@ from rpython.jit.backend import detect_cpu cpu = detect_cpu.autodetect() def pytest_runtest_setup(item): - if cpu not in ('x86', 'x86_64'): + if not cpu.startswith('x86'): py.test.skip("x86 directory skipped: cpu is %r" % (cpu,)) From noreply at buildbot.pypy.org Mon May 6 14:41:30 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 6 May 2013 14:41:30 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix this to not depend on the cpumodel. Message-ID: <20130506124130.E387D1C1324@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63877:987f44a927f7 Date: 2013-05-06 14:40 +0200 http://bitbucket.org/pypy/pypy/changeset/987f44a927f7/ Log: Fix this to not depend on the cpumodel. diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -1,25 +1,21 @@ -import os +import sys, os from ctypes_configure import dumpcache -from rpython.jit.backend import detect_cpu def dumpcache2(basename, config): - model = detect_cpu.autodetect_main_model_and_size() - filename = '_%s_%s_.py' % (basename, model) + size = 32 if sys.maxint <= 2**32 else 64 + filename = '_%s_%s_.py' % (basename, size) dumpcache.dumpcache(__file__, filename, config) # filename = os.path.join(os.path.dirname(__file__), '_%s_cache.py' % (basename,)) g = open(filename, 'w') print >> g, '''\ -try: - from __pypy__ import cpumodel -except ImportError: - from rpython.jit.backend import detect_cpu - cpumodel = detect_cpu.autodetect_main_model_and_size() +import sys +_size = 32 if sys.maxint <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib -mod = __import__("_%s_%%s_" %% (cpumodel,), - globals(), locals(), ["*"]) -globals().update(mod.__dict__)\ +_mod = __import__("_%s_%%s_" %% (_size,), + globals(), locals(), ["*"]) +globals().update(_mod.__dict__)\ ''' % (basename,) g.close() diff --git a/lib_pypy/ctypes_config_cache/rebuild.py b/lib_pypy/ctypes_config_cache/rebuild.py --- a/lib_pypy/ctypes_config_cache/rebuild.py +++ b/lib_pypy/ctypes_config_cache/rebuild.py @@ -25,13 +25,12 @@ sys.path[:] = path def try_rebuild(): - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - # remove the files '_*_model_.py' + size = 32 if sys.maxint <= 2**32 else 64 + # remove the files '_*_size_.py' left = {} for p in os.listdir(_dirpath): - if p.startswith('_') and (p.endswith('_%s_.py' % model) or - p.endswith('_%s_.pyc' % model)): + if p.startswith('_') and (p.endswith('_%s_.py' % size) or + p.endswith('_%s_.pyc' % size)): os.unlink(os.path.join(_dirpath, p)) elif p.startswith('_') and (p.endswith('_.py') or p.endswith('_.pyc')): From noreply at buildbot.pypy.org Mon May 6 15:00:00 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Mon, 6 May 2013 15:00:00 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added method_str to contexts to have a really short printing method Message-ID: <20130506130000.D1DD11C0135@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r375:59ed4dafb700 Date: 2013-05-06 14:13 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/59ed4dafb700/ Log: added method_str to contexts to have a really short printing method diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -967,7 +967,7 @@ if argcount == 0: return '%s%s (rcvr: %s) [pc: %d]' % ( block, - self.w_method().get_identifier_string(), + self.method_str(), self.w_receiver().as_repr_string(), self.pc() + 1 ) @@ -976,12 +976,15 @@ args += ': %s' % self.peek(i).as_repr_string() return '%s%s (rcvr: %s) [pc: %d] (%s)' % ( block, - self.w_method().get_identifier_string(), + self.method_str(), self.w_receiver().as_repr_string(), self.pc() + 1, args ) + def method_str(self): + return self.w_method().get_identifier_string() + class CompiledMethodShadow(object): _attr_ = ["_w_self", "bytecode", "literals[*]", "bytecodeoffset", From noreply at buildbot.pypy.org Mon May 6 15:00:02 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Mon, 6 May 2013 15:00:02 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added ensure:/ifCurtailed: checks when unwinding Message-ID: <20130506130002.8578A1C0135@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r376:46932f9d0142 Date: 2013-05-06 14:15 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/46932f9d0142/ Log: added ensure:/ifCurtailed: checks when unwinding added tests to be executed in the benchmarks 4.5 image because this is the only one where there is an #ensure:-Implementation added two tests for ensure diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -75,6 +75,8 @@ s_new_context = s_sender while s_new_context is not nlr.s_target_context: s_sender = s_new_context.s_sender() + if not s_new_context.is_closure_context() and s_new_context.s_method().primitive() == 198: + s_new_context.activate_unwind_context(self) s_new_context.mark_returned() s_new_context = s_sender s_new_context.push(nlr.value) @@ -105,6 +107,8 @@ self.step(s_context) except Return, nlr: if nlr.s_target_context is not s_context: + if not s_context.is_closure_context() and s_context.s_method().primitive() == 198: + s_context.activate_unwind_context(self) s_context.mark_returned() raise nlr else: @@ -414,6 +418,20 @@ print '%s<- %s' % (interp.padding(), return_value.as_repr_string()) raise Return(return_value, s_return_to) + def activate_unwind_context(self, interp): + # the first temp is executed flag for both #ensure: and #ifCurtailed: + if self.gettemp(1) is self.space.w_nil: + self.settemp(1, self.space.w_true) # mark unwound + self.push(self.gettemp(0)) # push the first argument + try: + self.bytecodePrimValue(interp, 0) + except Return, nlr: + if self is nlr.s_target_context: + return + else: + self.mark_returned() + raise nlr + def returnReceiver(self, interp, current_bytecode): return self._return(self.w_receiver(), interp, self.s_home().s_sender()) diff --git a/spyvm/test/test_bootstrappedimage.py b/spyvm/test/test_bootstrappedimage.py --- a/spyvm/test/test_bootstrappedimage.py +++ b/spyvm/test/test_bootstrappedimage.py @@ -15,7 +15,7 @@ return each def initialize_class(w_class): - initialize_symbol = find_symbol_in_methoddict_of("initialize", + initialize_symbol = find_symbol_in_methoddict_of("initialize", w_class.shadow_of_my_class(tools.space)) perform(w_class, initialize_symbol) @@ -35,7 +35,7 @@ def test_retrieve_symbol(): """asSymbol - "This is the only place that new Symbols are created. A Symbol is created + "This is the only place that new Symbols are created. A Symbol is created if and only if there is not already a Symbol with its contents in existance." Symbol allInstancesDo: [ :sym | diff --git a/spyvm/test/test_in_squeak_4_5_image.py b/spyvm/test/test_in_squeak_4_5_image.py new file mode 100644 --- /dev/null +++ b/spyvm/test/test_in_squeak_4_5_image.py @@ -0,0 +1,84 @@ +import py +from spyvm import squeakimage, model, constants +from spyvm import interpreter, shadow, objspace +from spyvm.test import test_miniimage as tools +from spyvm.test.test_miniimage import perform, w + +tools.setup_module(tools, filename='Squeak4.5-12568.image') + +def find_symbol_in_methoddict_of(string, s_class): + s_methoddict = s_class.s_methoddict() + s_methoddict.sync_cache() + methoddict_w = s_methoddict.methoddict + for each in methoddict_w.keys(): + if each.as_string() == string: + return each + +def test_all_pointers_are_valid(): + tools.test_all_pointers_are_valid() + tools.test_lookup_abs_in_integer() + +def create_method_shadow(bytes, literals=[], islarge=0, argsize=0, tempsize=0): + w_method = model.W_CompiledMethod(len(bytes)) + w_method.bytes = bytes + w_method.islarge = islarge + w_method.argsize = argsize + w_method.tempsize = tempsize + + w_method.setliterals(literals) + s_method = w_method.as_compiledmethod_get_shadow(tools.space) + return s_method + +def test_ensure(): + space = tools.space + #ensure + # [^'b1'] ensure: [^'b2'] + import operator + bytes = reduce(operator.add, map(chr, [0x8F, 0, 0, 2, 0x21, 0x7c, + 0x8F, 0, 0, 2, 0x22, 0x7c, + 0xe0, 0x87, 0x78])) + + s_class = space.w_BlockClosure.as_class_get_shadow(space) + ensure_ = find_symbol_in_methoddict_of('ensure:', s_class) + assert ensure_ is not None, 'Using image without #ensure:-method.' + + s_method = create_method_shadow(bytes, [ensure_, w('b1'), w('b2'), + w('ensure'), space.w_BlockClosure]) + + # create a frame for our newly crafted method with a valid sender (to avoid raising returnFromTop to early) + s_initial_frame = create_method_shadow(chr(0x7c)).create_frame(space, w(0), []) + w_frame = s_method.create_frame(space, w(0), [], sender=s_initial_frame).w_self() + + try: + tools.interp.loop(w_frame) + except interpreter.ReturnFromTopLevel, e: + assert e.object.as_string() == 'b2' + except interpreter.StackOverflow, e: + assert False + +def test_ensure_save_original_nlr(): + space = tools.space + #ensure + # [^'b1'] ensure: ['b2'] + import operator + bytes = reduce(operator.add, map(chr, [0x8F, 0, 0, 2, 0x21, 0x7c, + 0x8F, 0, 0, 2, 0x22, 0x7d, + 0xe0, 0x87, 0x78])) + + s_class = space.w_BlockClosure.as_class_get_shadow(space) + ensure_ = find_symbol_in_methoddict_of('ensure:', s_class) + assert ensure_ is not None, 'Using image without #ensure:-method.' + + s_method = create_method_shadow(bytes, [ensure_, w('b1'), w('b2'), + w('ensure'), space.w_BlockClosure]) + + # create a frame for our newly crafted method with a valid sender (to avoid raising returnFromTop to early) + s_initial_frame = create_method_shadow(chr(0x7c)).create_frame(space, w(0), []) + w_frame = s_method.create_frame(space, w(0), [], sender=s_initial_frame).w_self() + + try: + tools.interp.loop(w_frame) + except interpreter.ReturnFromTopLevel, e: + assert e.object.as_string() == 'b1' + except interpreter.StackOverflow, e: + assert False From noreply at buildbot.pypy.org Mon May 6 15:00:03 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Mon, 6 May 2013 15:00:03 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed problem with terminate: when setting the stackpointer of an object, switch based on the existence of a shadow, don't assume it is already existent Message-ID: <20130506130003.ADB471C0135@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r377:e325aacc62e1 Date: 2013-05-06 14:58 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/e325aacc62e1/ Log: fixed problem with terminate: when setting the stackpointer of an object, switch based on the existence of a shadow, don't assume it is already existent diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -487,8 +487,11 @@ assert stackp >= 0 if not isinstance(w_frame, model.W_PointersObject): raise PrimitiveFailedError - s_frame = w_frame.as_context_get_shadow(interp.space) - s_frame.store_stackpointer(stackp) + if w_frame.has_shadow(): + s_frame = w_frame.as_context_get_shadow(interp.space) + s_frame.store_stackpointer(stackp) + else: + w_frame.store(interp.space, constants.CTXPART_STACKP_INDEX, stackp) return w_frame @expose_primitive(SOME_INSTANCE, unwrap_spec=[object]) From noreply at buildbot.pypy.org Mon May 6 15:00:04 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Mon, 6 May 2013 15:00:04 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: using method_str for stack_printing instead of short_str Message-ID: <20130506130004.C50F71C0135@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r378:b1e526621495 Date: 2013-05-06 14:59 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/b1e526621495/ Log: using method_str for stack_printing instead of short_str added block switch to method_str diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -712,7 +712,7 @@ padding = ret_str = '' if self.s_sender() is not None: padding, ret_str = self.s_sender().print_stack() - return padding + ' ', '%s\n%s%s' % (ret_str, padding, self.short_str(0)) + return padding + ' ', '%s\n%s%s' % (ret_str, padding, self.method_str()) class BlockContextShadow(ContextPartShadow): @@ -963,10 +963,8 @@ return retval def short_str(self, argcount): - block = '[] of ' if self.is_closure_context() else '' if argcount == 0: - return '%s%s (rcvr: %s) [pc: %d]' % ( - block, + return '%s (rcvr: %s) [pc: %d]' % ( self.method_str(), self.w_receiver().as_repr_string(), self.pc() + 1 @@ -974,8 +972,7 @@ args = '%d' % argcount for i in range(argcount - 1, -1, -1): args += ': %s' % self.peek(i).as_repr_string() - return '%s%s (rcvr: %s) [pc: %d] (%s)' % ( - block, + return '%s (rcvr: %s) [pc: %d] (%s)' % ( self.method_str(), self.w_receiver().as_repr_string(), self.pc() + 1, @@ -983,7 +980,8 @@ ) def method_str(self): - return self.w_method().get_identifier_string() + block = '[] of ' if self.is_closure_context() else '' + return '%s%s' % (block, self.w_method().get_identifier_string()) class CompiledMethodShadow(object): _attr_ = ["_w_self", "bytecode", From noreply at buildbot.pypy.org Mon May 6 16:20:19 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:19 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Move table of contents into its own document. Message-ID: <20130506142019.B5AFF1C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63878:bbfc387f4a48 Date: 2013-03-06 12:33 +0100 http://bitbucket.org/pypy/pypy/changeset/bbfc387f4a48/ Log: Move table of contents into its own document. diff --git a/rpython/doc/contents.rst b/rpython/doc/contents.rst new file mode 100644 --- /dev/null +++ b/rpython/doc/contents.rst @@ -0,0 +1,19 @@ +Table of Contents +=================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + getting-started + faq + rpython + rlib + rffi + translation + rtyper + garbage_collection + cli-backend + windows + diff --git a/rpython/doc/index.rst b/rpython/doc/index.rst --- a/rpython/doc/index.rst +++ b/rpython/doc/index.rst @@ -1,22 +1,7 @@ Welcome to RPython's documentation! =================================== -Contents: - -.. toctree:: - :maxdepth: 2 - - getting-started - faq - rpython - rlib - rffi - translation - rtyper - garbage_collection - cli-backend - windows - +* :doc:`contents` Indices and tables ================== From noreply at buildbot.pypy.org Mon May 6 16:20:21 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:21 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: hg merge Message-ID: <20130506142021.1D77B1C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63879:765f31793ccd Date: 2013-05-06 14:43 +0200 http://bitbucket.org/pypy/pypy/changeset/765f31793ccd/ Log: hg merge diff --git a/rpython/doc/contents.rst b/rpython/doc/contents.rst new file mode 100644 --- /dev/null +++ b/rpython/doc/contents.rst @@ -0,0 +1,19 @@ +Table of Contents +=================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + getting-started + faq + rpython + rlib + rffi + translation + rtyper + garbage_collection + cli-backend + windows + diff --git a/rpython/doc/index.rst b/rpython/doc/index.rst --- a/rpython/doc/index.rst +++ b/rpython/doc/index.rst @@ -1,22 +1,7 @@ Welcome to RPython's documentation! =================================== -Contents: - -.. toctree:: - :maxdepth: 2 - - getting-started - faq - rpython - rlib - rffi - translation - rtyper - garbage_collection - cli-backend - windows - +* :doc:`contents` Indices and tables ================== From noreply at buildbot.pypy.org Mon May 6 16:20:22 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:22 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Move new release announcements to pypy/doc/releases. Message-ID: <20130506142022.547541C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63880:025df81ade11 Date: 2013-05-06 15:01 +0200 http://bitbucket.org/pypy/pypy/changeset/025df81ade11/ Log: Move new release announcements to pypy/doc/releases. diff --git a/pypy/doc/release-2.0.0-beta2.rst b/pypy/doc/releases/2.0.0-beta2.rst rename from pypy/doc/release-2.0.0-beta2.rst rename to pypy/doc/releases/2.0.0-beta2.rst diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/releases/2.0.0.rst rename from pypy/doc/release-2.0.0.rst rename to pypy/doc/releases/2.0.0.rst diff --git a/pypy/doc/releases/index.rst b/pypy/doc/releases/index.rst --- a/pypy/doc/releases/index.rst +++ b/pypy/doc/releases/index.rst @@ -3,6 +3,8 @@ .. toctree:: + 2.0.0 + 2.0.0-beta2 2.0.0-beta1 1.9.0 1.8.0 From noreply at buildbot.pypy.org Mon May 6 16:20:23 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:23 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: needswork.txt was removed. Message-ID: <20130506142023.851381C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63881:e75950eb15bf Date: 2013-05-06 15:03 +0200 http://bitbucket.org/pypy/pypy/changeset/e75950eb15bf/ Log: needswork.txt was removed. diff --git a/pypy/doc/glossary.rst b/pypy/doc/glossary.rst --- a/pypy/doc/glossary.rst +++ b/pypy/doc/glossary.rst @@ -1,5 +1,3 @@ -.. include:: needswork.txt - .. _glossary: ******** From noreply at buildbot.pypy.org Mon May 6 16:20:24 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:24 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Fix hidden toctree. Some documents were (re)moved. Message-ID: <20130506142024.AA99A1C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63882:d3bc26f2cd8c Date: 2013-05-06 15:05 +0200 http://bitbucket.org/pypy/pypy/changeset/d3bc26f2cd8c/ Log: Fix hidden toctree. Some documents were (re)moved. diff --git a/pypy/doc/project-documentation.rst b/pypy/doc/project-documentation.rst --- a/pypy/doc/project-documentation.rst +++ b/pypy/doc/project-documentation.rst @@ -138,16 +138,6 @@ interpreter-optimizations.rst configuration.rst parser.rst - rlib.rst - rtyper.rst - rffi.rst - - translation.rst - jit/index.rst - jit/overview.rst - jit/pyjitpl5.rst - - index-of-release-notes.rst ctypes-implementation.rst @@ -160,8 +150,6 @@ discussions.rst - cleanup.rst - sprint-reports.rst eventhistory.rst From noreply at buildbot.pypy.org Mon May 6 16:20:25 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:25 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Cleanup whitespaces and underlines. Message-ID: <20130506142025.DABFB1C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63883:351d8295b587 Date: 2013-05-06 15:11 +0200 http://bitbucket.org/pypy/pypy/changeset/351d8295b587/ Log: Cleanup whitespaces and underlines. diff --git a/pypy/doc/architecture.rst b/pypy/doc/architecture.rst --- a/pypy/doc/architecture.rst +++ b/pypy/doc/architecture.rst @@ -1,15 +1,15 @@ -================================================== -Goals and Architecture Overview -================================================== +=============================== +Goals and Architecture Overview +=============================== .. contents:: This document gives an overview of the goals and architecture of PyPy. -See `getting started`_ for a practical introduction and starting points. +See `getting started`_ for a practical introduction and starting points. -Mission statement -==================== +Mission statement +================= We aim to provide: @@ -18,8 +18,8 @@ separation between language specification and implementation aspects. We call this the `RPython toolchain`_. - * a compliant, flexible and fast implementation of the Python_ Language - which uses the above toolchain to enable new advanced high-level features + * a compliant, flexible and fast implementation of the Python_ Language + which uses the above toolchain to enable new advanced high-level features without having to encode the low-level details. We call this PyPy. By separating concerns in this way, our implementation @@ -27,24 +27,24 @@ generate a Just-in-Time compiler for any dynamic language. It also allows a mix-and-match approach to implementation decisions, including many that have historically been outside of a user's control, such as -target platform, memory and -threading models, garbage collection strategies, and optimizations applied, +target platform, memory and +threading models, garbage collection strategies, and optimizations applied, including whether or not to have a JIT in the first place. High Level Goals -============================= +================ RPython - the Translation Toolchain ------------------------------------------------ +----------------------------------- Traditionally, language interpreters are written in a target platform language -such as C/Posix, Java or C#. Each implementation provides -a fundamental mapping between application source code and the target -environment. One of +such as C/Posix, Java or C#. Each implementation provides +a fundamental mapping between application source code and the target +environment. One of the goals of the "all-encompassing" environments, such as the .NET framework and to some extent the Java virtual machine, is to provide standardized and higher level functionalities in order to support language implementers -for writing language implementations. +for writing language implementations. PyPy is experimenting with a more ambitious approach. We are using a subset of the high-level language Python, called RPython_, in which we @@ -62,7 +62,7 @@ * ``l``: the language that we analyze can be evolved or entirely replaced; -* ``o``: we can tweak and optimize the translation process to produce +* ``o``: we can tweak and optimize the translation process to produce platform specific code based on different models and trade-offs; * ``p``: we can write new translator back-ends to target different @@ -71,8 +71,8 @@ By contrast, a standardized target environment - say .NET - enforces ``p=1`` as far as it's concerned. This helps making ``o`` a bit smaller by providing a higher-level base to build upon. Still, -we believe that enforcing the use of one common environment -is not necessary. PyPy's goal is to give weight to this claim - at least +we believe that enforcing the use of one common environment +is not necessary. PyPy's goal is to give weight to this claim - at least as far as language implementation is concerned - showing an approach to the ``l * o * p`` problem that does not rely on standardization. @@ -84,7 +84,7 @@ PyPy - the Python Interpreter --------------------------------------------- +----------------------------- Our main motivation for developing the translation framework is to provide a full featured, customizable, fast_ and `very compliant`_ Python @@ -106,19 +106,19 @@ and fully orthogonal to the interpreter source code. -PyPy Architecture -=========================== +PyPy Architecture +================= As you would expect from a project implemented using ideas from the world of `Extreme Programming`_, the architecture of PyPy has evolved over time -and continues to evolve. Nevertheless, the high level architecture is +and continues to evolve. Nevertheless, the high level architecture is stable. As described above, there are two rather independent basic subsystems: the `PyPy Python Interpreter`_ and the `RPython Translation Toolchain`_. .. _`translation framework`: RPython Translation Toolchain -------------------------- +----------------------------- The job of the RPython toolchain is to translate RPython_ programs into an efficient version of that program for one of the various target @@ -171,20 +171,20 @@ .. _`document about the RPython toolchain`: translation.html .. _`garbage collector`: garbage_collection.html .. _`RPython toolchain`: translation.html -.. _`standard interpreter`: -.. _`python interpreter`: +.. _`standard interpreter`: +.. _`python interpreter`: PyPy Python Interpreter -------------------------------------- +----------------------- PyPy's *Python Interpreter* is written in RPython and implements the full Python language. This interpreter very closely emulates the behavior of CPython. It contains the following key components: -- a bytecode compiler responsible for producing Python code objects +- a bytecode compiler responsible for producing Python code objects from the source code of a user application; -- a `bytecode evaluator`_ responsible for interpreting +- a `bytecode evaluator`_ responsible for interpreting Python code objects; - a `standard object space`_, responsible for creating and manipulating @@ -201,8 +201,8 @@ truth-value-testing. This division between bytecode evaluator and object space is very -important, as it gives a lot of flexibility. One can plug in -different `object spaces`_ to get different or enriched behaviours +important, as it gives a lot of flexibility. One can plug in +different `object spaces`_ to get different or enriched behaviours of the Python objects. Additionally, a special more abstract object space, the `flow object space`_, allows us to reuse the bytecode evaluator for our translation framework. From noreply at buildbot.pypy.org Mon May 6 16:20:27 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:27 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: There is no target 'this'. Message-ID: <20130506142027.33F2F1C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63884:55b45c8d7580 Date: 2013-05-06 15:25 +0200 http://bitbucket.org/pypy/pypy/changeset/55b45c8d7580/ Log: There is no target 'this'. diff --git a/pypy/doc/arm.rst b/pypy/doc/arm.rst --- a/pypy/doc/arm.rst +++ b/pypy/doc/arm.rst @@ -114,7 +114,7 @@ ----------- Having performed all the preliminary steps we should now be able to cross -translate a program for ARM. You can use this_ minimal +translate a program for ARM. You can use this minimal target to test your setup before applying it to a larger project. Before starting the translator we need to set two environment variables, so the From noreply at buildbot.pypy.org Mon May 6 16:20:28 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:28 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Re-add missing labels to 'Wrapping rules'. Message-ID: <20130506142028.77D031C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63885:1e287474f9a2 Date: 2013-05-06 15:32 +0200 http://bitbucket.org/pypy/pypy/changeset/1e287474f9a2/ Log: Re-add missing labels to 'Wrapping rules'. diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -173,6 +173,9 @@ for pure integer objects, for instance. +.. _`wrapping rules`: +.. _`wrapped`: + Wrapping rules ============== From noreply at buildbot.pypy.org Mon May 6 16:20:29 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:29 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Use sphinx' extlinks extension in pypy/doc/, too. Message-ID: <20130506142029.A7C881C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63886:c8722dd21e7b Date: 2013-05-06 16:01 +0200 http://bitbucket.org/pypy/pypy/changeset/c8722dd21e7b/ Log: Use sphinx' extlinks extension in pypy/doc/, too. diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -22,7 +22,7 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.graphviz', 'pypyconfig'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.graphviz', 'pypyconfig'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -204,3 +204,5 @@ u'fast, compliant alternative implementation of the Python language', u'The PyPy Project', 1) ] + +extlinks = {'source': ('https://bitbucket.org/pypy/pypy/src/default/%s', '')} diff --git a/pypy/doc/dir-reference.rst b/pypy/doc/dir-reference.rst --- a/pypy/doc/dir-reference.rst +++ b/pypy/doc/dir-reference.rst @@ -4,105 +4,105 @@ Here is a fully referenced alphabetical two-level deep directory overview of PyPy: -================================= ============================================ -Directory explanation/links -================================= ============================================ -`pypy/bin/`_ command-line scripts, mainly - `pypy/bin/pyinteractive.py`_ +======================================== ============================================ +Directory explanation/links +======================================== ============================================ +:source:`pypy/bin/` command-line scripts, mainly + :source:`pypy/bin/pyinteractive.py` -`pypy/config/`_ handles the numerous options for building - and running PyPy +:source:`pypy/config/` handles the numerous options for building + and running PyPy -`pypy/doc/`_ text versions of PyPy developer - documentation +:source:`pypy/doc/` text versions of PyPy developer + documentation -`pypy/doc/config/`_ documentation for the numerous translation - options +:source:`pypy/doc/config/` documentation for the numerous translation + options -`pypy/doc/discussion/`_ drafts of ideas and documentation +:source:`pypy/doc/discussion/` drafts of ideas and documentation -``doc/*/`` other specific documentation topics or tools +``doc/*/`` other specific documentation topics or tools -`pypy/interpreter/`_ `bytecode interpreter`_ and related objects - (frames, functions, modules,...) +:source:`pypy/interpreter/` `bytecode interpreter`_ and related objects + (frames, functions, modules,...) -`pypy/interpreter/pyparser/`_ interpreter-level Python source parser +:source:`pypy/interpreter/pyparser/` interpreter-level Python source parser -`pypy/interpreter/astcompiler/`_ interpreter-level bytecode compiler, - via an AST representation +:source:`pypy/interpreter/astcompiler/` interpreter-level bytecode compiler, + via an AST representation -`pypy/module/`_ contains `mixed modules`_ - implementing core modules with - both application and interpreter level code. - Not all are finished and working. Use - the ``--withmod-xxx`` - or ``--allworkingmodules`` translation - options. +:source:`pypy/module/` contains `mixed modules`_ + implementing core modules with + both application and interpreter level code. + Not all are finished and working. Use + the ``--withmod-xxx`` + or ``--allworkingmodules`` translation + options. -`pypy/objspace/`_ `object space`_ implementations +:source:`pypy/objspace/` `object space`_ implementations -`pypy/objspace/std/`_ the StdObjSpace_ implementing CPython's - objects and types +:source:`pypy/objspace/std/` the StdObjSpace_ implementing CPython's + objects and types -`pypy/tool/`_ various utilities and hacks used - from various places +:source:`pypy/tool/` various utilities and hacks used + from various places -`pypy/tool/algo/`_ general-purpose algorithmic and mathematic - tools +:source:`pypy/tool/algo/` general-purpose algorithmic and mathematic + tools -`pypy/tool/pytest/`_ support code for our `testing methods`_ +:source:`pypy/tool/pytest/` support code for our `testing methods`_ -`rpython/annotator/`_ `type inferencing code`_ for - `RPython`_ programs +:source:`rpython/annotator/` `type inferencing code`_ for + `RPython`_ programs -`rpython/config/`_ handles the numerous options for RPython +:source:`rpython/config/` handles the numerous options for RPython -`rpython/flowspace/`_ the FlowObjSpace_ implementing - `abstract interpretation`_ +:source:`rpython/flowspace/` the FlowObjSpace_ implementing + `abstract interpretation`_ -`rpython/rlib/`_ a `"standard library"`_ for RPython_ - programs +:source:`rpython/rlib/` a `"standard library"`_ for RPython_ + programs -`rpython/rtyper/`_ the `RPython Typer`_ +:source:`rpython/rtyper/` the `RPython Typer`_ -`rpython/rtyper/lltypesystem/`_ the `low-level type system`_ for - C-like backends +:source:`rpython/rtyper/lltypesystem/` the `low-level type system`_ for + C-like backends -`rpython/rtyper/ootypesystem/`_ the `object-oriented type system`_ - for OO backends +:source:`rpython/rtyper/ootypesystem/` the `object-oriented type system`_ + for OO backends -`rpython/memory/`_ the `garbage collector`_ construction - framework +:source:`rpython/memory/` the `garbage collector`_ construction + framework -`rpython/translator/`_ translation_ backends and support code +:source:`rpython/translator/` translation_ backends and support code -`rpython/translator/backendopt/`_ general optimizations that run before a - backend generates code +:source:`rpython/translator/backendopt/` general optimizations that run before a + backend generates code -`rpython/translator/c/`_ the `GenC backend`_, producing C code - from an - RPython program (generally via the rtyper_) +:source:`rpython/translator/c/` the `GenC backend`_, producing C code + from an + RPython program (generally via the rtyper_) -`rpython/translator/cli/`_ the `CLI backend`_ for `.NET`_ - (Microsoft CLR or Mono_) +:source:`rpython/translator/cli/` the `CLI backend`_ for `.NET`_ + (Microsoft CLR or Mono_) -`pypy/goal/`_ our `main PyPy-translation scripts`_ - live here +:source:`pypy/goal/` our `main PyPy-translation scripts`_ + live here -`rpython/translator/jvm/`_ the Java backend +:source:`rpython/translator/jvm/` the Java backend -`rpython/translator/tool/`_ helper tools for translation +:source:`rpython/translator/tool/` helper tools for translation -`dotviewer/`_ `graph viewer`_ +:source:`dotviewer/` `graph viewer`_ -``*/test/`` many directories have a test subdirectory - containing test - modules (see `Testing in PyPy`_) +``*/test/`` many directories have a test subdirectory + containing test + modules (see `Testing in PyPy`_) -``_cache/`` holds cache files from various purposes -================================= ============================================ +``_cache/`` holds cache files from various purposes +======================================== ============================================ .. _`bytecode interpreter`: interpreter.html .. _`Testing in PyPy`: coding-guide.html#testing-in-pypy From noreply at buildbot.pypy.org Mon May 6 16:20:30 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 16:20:30 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Cleanup whitespaces and underlines. Message-ID: <20130506142030.D4C851C0135@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63887:9fc6184559ee Date: 2013-05-06 16:18 +0200 http://bitbucket.org/pypy/pypy/changeset/9fc6184559ee/ Log: Cleanup whitespaces and underlines. diff --git a/pypy/doc/getting-started-dev.rst b/pypy/doc/getting-started-dev.rst --- a/pypy/doc/getting-started-dev.rst +++ b/pypy/doc/getting-started-dev.rst @@ -4,20 +4,21 @@ .. contents:: -.. _`start reading sources`: +.. _`start reading sources`: + Where to start reading the sources ----------------------------------- +---------------------------------- PyPy is made from parts that are relatively independent of each other. You should start looking at the part that attracts you most (all paths are -relative to the PyPy top level directory). You may look at our `directory reference`_ +relative to the PyPy top level directory). You may look at our `directory reference`_ or start off at one of the following points: * `pypy/interpreter`_ contains the bytecode interpreter: bytecode dispatcher in `pypy/interpreter/pyopcode.py`_, frame and code objects in `pypy/interpreter/eval.py`_ and `pypy/interpreter/pyframe.py`_, function objects and argument passing in `pypy/interpreter/function.py`_ and `pypy/interpreter/argument.py`_, the object space interface definition in `pypy/interpreter/baseobjspace.py`_, modules in - `pypy/interpreter/module.py`_ and `pypy/interpreter/mixedmodule.py`_. Core types supporting the bytecode + `pypy/interpreter/module.py`_ and `pypy/interpreter/mixedmodule.py`_. Core types supporting the bytecode interpreter are defined in `pypy/interpreter/typedef.py`_. * `pypy/interpreter/pyparser`_ contains a recursive descent parser, @@ -34,7 +35,7 @@ ``xxxobject.py`` contain respectively the definition of the type and its (default) implementation. -.. _optionaltool: +.. _optionaltool: Running PyPy's unit tests @@ -65,7 +66,7 @@ # or for running tests of a whole subdirectory py.test pypy/interpreter/ -See `py.test usage and invocations`_ for some more generic info +See `py.test usage and invocations`_ for some more generic info on how you can run tests. Beware trying to run "all" pypy tests by pointing to the root @@ -133,14 +134,14 @@ .. _`interpreter-level and app-level`: coding-guide.html#interpreter-level -.. _`trace example`: +.. _`trace example`: Tracing bytecode and operations on objects -++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++ You can use the trace object space to monitor the interpretation -of bytecodes in connection with object space operations. To enable -it, set ``__pytrace__=1`` on the interactive PyPy console:: +of bytecodes in connection with object space operations. To enable +it, set ``__pytrace__=1`` on the interactive PyPy console:: >>>> __pytrace__ = 1 Tracing enabled @@ -165,25 +166,25 @@ .. _`example-interpreter`: https://bitbucket.org/pypy/example-interpreter -Additional Tools for running (and hacking) PyPy +Additional Tools for running (and hacking) PyPy ----------------------------------------------- -We use some optional tools for developing PyPy. They are not required to run +We use some optional tools for developing PyPy. They are not required to run the basic tests or to get an interactive PyPy prompt but they help to -understand and debug PyPy especially for the translation process. +understand and debug PyPy especially for the translation process. graphviz & pygame for flow graph viewing (highly recommended) +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ graphviz and pygame are both necessary if you -want to look at generated flow graphs: +want to look at generated flow graphs: - graphviz: http://www.graphviz.org/Download.php + graphviz: http://www.graphviz.org/Download.php pygame: http://www.pygame.org/download.shtml -py.test and the py lib -+++++++++++++++++++++++ +py.test and the py lib +++++++++++++++++++++++ The `py.test testing tool`_ drives all our testing needs. @@ -193,8 +194,8 @@ You don't necessarily need to install these two libraries because we also ship them inlined in the PyPy source tree. -Getting involved ------------------ +Getting involved +---------------- PyPy employs an open development process. You are invited to join our `pypy-dev mailing list`_ or look at the other `contact diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -6,7 +6,7 @@ PyPy's Python interpreter is a very compliant Python -interpreter implemented in RPython. When compiled, it passes most of +interpreter implemented in RPython. When compiled, it passes most of `CPythons core language regression tests`_ and comes with many of the extension modules included in the standard library including ``ctypes``. It can run large libraries such as Django_ and Twisted_. There are some small behavioral @@ -18,8 +18,8 @@ .. _`CPython differences`: cpython_differences.html -To actually use PyPy's Python interpreter, the first thing to do is to -`download a pre-built PyPy`_ for your architecture. +To actually use PyPy's Python interpreter, the first thing to do is to +`download a pre-built PyPy`_ for your architecture. .. _`download a pre-built PyPy`: http://pypy.org/download.html @@ -71,9 +71,9 @@ 3. Translation is time-consuming -- 45 minutes on a very fast machine -- - and RAM-hungry. As of March 2011, you will need **at least** 2 GB of - memory on a - 32-bit machine and 4GB on a 64-bit machine. If your memory resources + and RAM-hungry. As of March 2011, you will need **at least** 2 GB of + memory on a + 32-bit machine and 4GB on a 64-bit machine. If your memory resources are constrained, or your machine is slow you might want to pick the `optimization level`_ `1` in the next step. A level of `2` or `3` or `jit` gives much better results, though. But if all @@ -82,7 +82,7 @@ Let me stress this again: at ``--opt=1`` you get the Boehm GC, which is here mostly for historical and for testing reasons. - You really do not want to pick it for a program you intend to use. + You really do not want to pick it for a program you intend to use. The resulting ``pypy-c`` is slow. 4. Run:: @@ -92,7 +92,7 @@ possibly replacing ``--opt=jit`` with another `optimization level`_ of your choice like ``--opt=2`` if you do not want to include the JIT - compiler, which makes the Python interpreter much slower. + compiler, which makes the Python interpreter much slower. .. _`optimization level`: config/opt.html @@ -119,7 +119,7 @@ >>>> pystone.main() Pystone(1.1) time for 50000 passes = 0.060004 This machine benchmarks at 833278 pystones/second - >>>> + >>>> Note that pystone gets faster as the JIT kicks in. This executable can be moved around or copied on other machines; see @@ -134,7 +134,7 @@ .. _`configuration sections`: config/index.html Translating with non-standard options -++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++ It is possible to have non-standard features enabled for translation, but they are not really tested any more. Look, for example, at the @@ -142,7 +142,7 @@ .. _`objspace proxies`: objspace-proxies.html -.. _`CLI code`: +.. _`CLI code`: Translating using the CLI backend +++++++++++++++++++++++++++++++++ @@ -163,7 +163,7 @@ [PyPy 1.6.0] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``distopian and utopian chairs'' - >>>> + >>>> Moreover, at the moment it's not possible to do the full translation using only the tools provided by the Microsoft .NET SDK, since @@ -182,7 +182,7 @@ .. not working now: - .. _`JVM code`: + .. _`JVM code`: Translating using the JVM backend +++++++++++++++++++++++++++++++++ @@ -195,12 +195,12 @@ script ``pypy-jvm`` for executing it. To try it out, simply run ``./pypy-jvm``:: - $ ./pypy-jvm + $ ./pypy-jvm Python 2.7.0 (61ef2a11b56a, Mar 02 2011, 03:00:11) [PyPy 1.6.0] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``# assert did not crash'' - >>>> + >>>> Alternatively, you can run it using ``java -jar pypy-jvm.jar``. At the moment the executable does not provide any interesting features, like integration with @@ -247,10 +247,10 @@ .. _`pyinteractive.py interpreter`: Running the Python Interpreter Without Translation ---------------------------------------------------- +-------------------------------------------------- The pyinteractive.py interpreter -+++++++++++++++++++++ +++++++++++++++++++++++++++++++++ To start interpreting Python with PyPy, install a C compiler that is supported by distutils and use Python 2.5 or greater to run PyPy:: @@ -258,26 +258,26 @@ cd pypy python bin/pyinteractive.py -After a few seconds (remember: this is running on top of CPython), -you should be at the PyPy prompt, which is the same as the Python +After a few seconds (remember: this is running on top of CPython), +you should be at the PyPy prompt, which is the same as the Python prompt, but with an extra ">". Now you are ready to start running Python code. Most Python -modules should work if they don't involve CPython extension +modules should work if they don't involve CPython extension modules. **This is slow, and most C modules are not present by default even if they are standard!** Here is an example of -determining PyPy's performance in pystones:: +determining PyPy's performance in pystones:: - >>>> from test import pystone + >>>> from test import pystone >>>> pystone.main(10) The parameter is the number of loops to run through the test. The default is 50000, which is far too many to run in a non-translated -PyPy version (i.e. when PyPy's interpreter itself is being interpreted +PyPy version (i.e. when PyPy's interpreter itself is being interpreted by CPython). pyinteractive.py options -+++++++++++++ +++++++++++++++++++++++++ To list the PyPy interpreter command line options, type:: From noreply at buildbot.pypy.org Mon May 6 17:03:27 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 17:03:27 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Kill _ref.txt and fix references. Message-ID: <20130506150327.E940D1C13A8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63888:3d8f4d764dae Date: 2013-05-06 16:39 +0200 http://bitbucket.org/pypy/pypy/changeset/3d8f4d764dae/ Log: Kill _ref.txt and fix references. diff --git a/pypy/doc/_ref.txt b/pypy/doc/_ref.txt deleted file mode 100644 --- a/pypy/doc/_ref.txt +++ /dev/null @@ -1,116 +0,0 @@ -.. _`ctypes_configure/doc/sample.py`: https://bitbucket.org/pypy/pypy/src/default/ctypes_configure/doc/sample.py -.. _`dotviewer/`: https://bitbucket.org/pypy/pypy/src/default/dotviewer/ -.. _`lib-python/`: https://bitbucket.org/pypy/pypy/src/default/lib-python/ -.. _`lib-python/2.7/dis.py`: https://bitbucket.org/pypy/pypy/src/default/lib-python/2.7/dis.py -.. _`lib_pypy/`: https://bitbucket.org/pypy/pypy/src/default/lib_pypy/ -.. _`lib_pypy/greenlet.py`: https://bitbucket.org/pypy/pypy/src/default/lib_pypy/greenlet.py -.. _`lib_pypy/pypy_test/`: https://bitbucket.org/pypy/pypy/src/default/lib_pypy/pypy_test/ -.. _`lib_pypy/tputil.py`: https://bitbucket.org/pypy/pypy/src/default/lib_pypy/tputil.py -.. _`pypy/bin/`: https://bitbucket.org/pypy/pypy/src/default/pypy/bin/ -.. _`pypy/bin/pyinteractive.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/bin/pyinteractive.py -.. _`pypy/config/`: https://bitbucket.org/pypy/pypy/src/default/pypy/config/ -.. _`pypy/config/pypyoption.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/config/pypyoption.py -.. _`pypy/doc/`: https://bitbucket.org/pypy/pypy/src/default/pypy/doc/ -.. _`pypy/doc/config/`: https://bitbucket.org/pypy/pypy/src/default/pypy/doc/config/ -.. _`pypy/doc/discussion/`: https://bitbucket.org/pypy/pypy/src/default/pypy/doc/discussion/ -.. _`pypy/goal/`: https://bitbucket.org/pypy/pypy/src/default/pypy/goal/ -.. _`pypy/interpreter`: -.. _`pypy/interpreter/`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/ -.. _`pypy/interpreter/argument.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/argument.py -.. _`pypy/interpreter/astcompiler`: -.. _`pypy/interpreter/astcompiler/`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/ -.. _`pypy/interpreter/astcompiler/assemble.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/assemble.py -.. _`pypy/interpreter/astcompiler/ast.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/ast.py -.. _`pypy/interpreter/astcompiler/astbuilder.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/astbuilder.py -.. _`pypy/interpreter/astcompiler/asthelpers.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/asthelpers.py -.. _`pypy/interpreter/astcompiler/codegen.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/codegen.py -.. _`pypy/interpreter/astcompiler/optimize.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/optimize.py -.. _`pypy/interpreter/astcompiler/symtable.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/symtable.py -.. _`pypy/interpreter/astcompiler/tools/Python.asdl`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/tools/Python.asdl -.. _`pypy/interpreter/astcompiler/tools/asdl_py.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/astcompiler/tools/asdl_py.py -.. _`pypy/interpreter/baseobjspace.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/baseobjspace.py -.. _`pypy/interpreter/eval.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/eval.py -.. _`pypy/interpreter/executioncontext.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/executioncontext.py -.. _`pypy/interpreter/function.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/function.py -.. _`pypy/interpreter/gateway.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/gateway.py -.. _`pypy/interpreter/mixedmodule.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/mixedmodule.py -.. _`pypy/interpreter/module.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/module.py -.. _`pypy/interpreter/nestedscope.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/nestedscope.py -.. _`pypy/interpreter/pyframe.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyframe.py -.. _`pypy/interpreter/pyopcode.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyopcode.py -.. _`pypy/interpreter/pyparser`: -.. _`pypy/interpreter/pyparser/`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyparser/ -.. _`pypy/interpreter/pyparser/future.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyparser/future.py -.. _`pypy/interpreter/pyparser/metaparser.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyparser/metaparser.py -.. _`pypy/interpreter/pyparser/parser.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyparser/parser.py -.. _`pypy/interpreter/pyparser/pyparse.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyparser/pyparse.py -.. _`pypy/interpreter/pyparser/pytokenizer.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/pyparser/pytokenizer.py -.. _`pypy/interpreter/typedef.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/interpreter/typedef.py -.. _`pypy/module`: -.. _`pypy/module/`: https://bitbucket.org/pypy/pypy/src/default/pypy/module/ -.. _`pypy/module/__builtin__/__init__.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/module/__builtin__/__init__.py -.. _`pypy/objspace/`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/ -.. _`pypy/objspace/flow/`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/flow/ -.. _`pypy/objspace/std`: -.. _`pypy/objspace/std/`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/ -.. _`pypy/objspace/std/listtype.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/listtype.py -.. _`pypy/objspace/std/multimethod.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/multimethod.py -.. _`pypy/objspace/std/objspace.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/objspace.py -.. _`pypy/objspace/std/proxy_helpers.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/proxy_helpers.py -.. _`pypy/objspace/std/proxyobject.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/proxyobject.py -.. _`pypy/objspace/std/stringtype.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/stringtype.py -.. _`pypy/objspace/std/transparent.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/transparent.py -.. _`pypy/objspace/std/tupleobject.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/tupleobject.py -.. _`pypy/objspace/std/tupletype.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/objspace/std/tupletype.py -.. _`pypy/tool/`: https://bitbucket.org/pypy/pypy/src/default/pypy/tool/ -.. _`pypy/tool/algo/`: https://bitbucket.org/pypy/pypy/src/default/pypy/tool/algo/ -.. _`pypy/tool/pytest/`: https://bitbucket.org/pypy/pypy/src/default/pypy/tool/pytest/ -.. _`rpython/annotator`: -.. _`rpython/annotator/`: https://bitbucket.org/pypy/pypy/src/default/rpython/annotator/ -.. _`rpython/annotator/annrpython.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/annotator/annrpython.py -.. _`rpython/annotator/binaryop.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/annotator/binaryop.py -.. _`rpython/annotator/builtin.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/annotator/builtin.py -.. _`rpython/bin/translatorshell.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/bin/translatorshell.py -.. _`rpython/config/`: https://bitbucket.org/pypy/pypy/src/default/rpython/config/ -.. _`rpython/config/translationoption.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/config/translationoption.py -.. _`rpython/flowspace/`: https://bitbucket.org/pypy/pypy/src/default/rpython/flowspace/ -.. _`rpython/flowspace/model.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/flowspace/model.py -.. _`rpython/rlib`: -.. _`rpython/rlib/`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/ -.. _`rpython/rlib/listsort.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/listsort.py -.. _`rpython/rlib/nonconst.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/nonconst.py -.. _`rpython/rlib/objectmodel.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/objectmodel.py -.. _`rpython/rlib/parsing/`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/parsing/ -.. _`rpython/rlib/parsing/tree.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/parsing/tree.py -.. _`rpython/rlib/rarithmetic.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/rarithmetic.py -.. _`rpython/rlib/rbigint.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/rbigint.py -.. _`rpython/rlib/rrandom.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/rrandom.py -.. _`rpython/rlib/rsocket.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/rsocket.py -.. _`rpython/rlib/streamio.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/streamio.py -.. _`rpython/rlib/test`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/test/ -.. _`rpython/rlib/unroll.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rlib/unroll.py -.. _`rpython/rtyper`: -.. _`rpython/rtyper/`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/ -.. _`rpython/rtyper/lltypesystem/`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/lltypesystem/ -.. _`rpython/rtyper/lltypesystem/lltype.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/lltypesystem/lltype.py -.. _`rpython/rtyper/memory/`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/memory/ -.. _`rpython/rtyper/memory/gc/generation.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/memory/gc/generation.py -.. _`rpython/rtyper/memory/gc/hybrid.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/memory/gc/hybrid.py -.. _`rpython/rtyper/memory/gc/minimarkpage.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/memory/gc/minimarkpage.py -.. _`rpython/rtyper/memory/gc/semispace.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/memory/gc/semispace.py -.. _`rpython/rtyper/ootypesystem/`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/ootypesystem/ -.. _`rpython/rtyper/ootypesystem/ootype.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/ootypesystem/ootype.py -.. _`rpython/rtyper/rint.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/rint.py -.. _`rpython/rtyper/rlist.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/rlist.py -.. _`rpython/rtyper/rmodel.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/rmodel.py -.. _`rpython/rtyper/rtyper.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/rtyper.py -.. _`rpython/rtyper/test/test_llinterp.py`: https://bitbucket.org/pypy/pypy/src/default/rpython/rtyper/test/test_llinterp.py -.. _`rpython/translator`: -.. _`rpython/translator/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/ -.. _`rpython/translator/backendopt/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/backendopt/ -.. _`rpython/translator/c/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/c/ -.. _`rpython/translator/c/src/stacklet/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/c/src/stacklet/ -.. _`rpython/translator/c/src/stacklet/stacklet.h`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/c/src/stacklet/stacklet.h -.. _`rpython/translator/cli/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/cli/ -.. _`rpython/translator/jvm/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/jvm/ -.. _`rpython/translator/tool/`: https://bitbucket.org/pypy/pypy/src/default/rpython/translator/tool/ diff --git a/pypy/doc/architecture.rst b/pypy/doc/architecture.rst --- a/pypy/doc/architecture.rst +++ b/pypy/doc/architecture.rst @@ -258,6 +258,3 @@ .. _`generate Just-In-Time Compilers`: jit/index.html .. _`JIT Generation in PyPy`: jit/index.html .. _`implement your own interpreter`: http://morepypy.blogspot.com/2011/04/tutorial-writing-interpreter-with-pypy.html - -.. include:: _ref.txt - diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -159,7 +159,7 @@ elegant: For the definition of all the opcodes of the Python interpreter, the module ``dis`` is imported and used to initialize our bytecode interpreter. (See ``__initclass__`` in -`pypy/interpreter/pyopcode.py`_). This +:source:`pypy/interpreter/pyopcode.py`). This saves us from adding extra modules to PyPy. The import code is run at startup time, and we are allowed to use the CPython builtin import function. @@ -304,11 +304,11 @@ because they rely on implementation details of CPython. If we don't just modify an original CPython module but need to rewrite -it from scratch we put it into `lib_pypy/`_ as a pure application level +it from scratch we put it into :source:`lib_pypy/` as a pure application level module. When we need access to interpreter-level objects we put the module into -`pypy/module`_. Such modules use a `mixed module mechanism`_ +:source:`pypy/module`. Such modules use a `mixed module mechanism`_ which makes it convenient to use both interpreter- and application-level parts for the implementation. Note that there is no extra facility for pure-interpreter level modules, you just write a mixed module and leave the @@ -381,7 +381,7 @@ If a module needs to access PyPy's interpreter level then it is implemented as a mixed module. -Mixed modules are directories in `pypy/module`_ with an `__init__.py` +Mixed modules are directories in :source:`pypy/module` with an `__init__.py` file containing specifications where each name in a module comes from. Only specified names will be exported to a Mixed Module's applevel namespace. @@ -399,7 +399,7 @@ Application level specifications are found in the `appleveldefs` dictionary found in ``__init__.py`` files of directories in ``pypy/module``. -For example, in `pypy/module/__builtin__/__init__.py`_ you find the following +For example, in :source:`pypy/module/__builtin__/__init__.py` you find the following entry specifying where ``__builtin__.locals`` comes from:: ... @@ -415,7 +415,7 @@ Interpreter level specifications are found in the ``interpleveldefs`` dictionary found in ``__init__.py`` files of directories in ``pypy/module``. -For example, in `pypy/module/__builtin__/__init__.py`_ the following +For example, in :source:`pypy/module/__builtin__/__init__.py` the following entry specifies where ``__builtin__.len`` comes from:: ... @@ -453,11 +453,11 @@ Testing modules in ``lib_pypy/`` -------------------------------- -You can go to the `lib_pypy/pypy_test/`_ directory and invoke the testing tool +You can go to the :source:`lib_pypy/pypy_test/` directory and invoke the testing tool ("py.test" or "python ../../pypy/test_all.py") to run tests against the -lib_pypy hierarchy. Note, that tests in `lib_pypy/pypy_test/`_ are allowed +lib_pypy hierarchy. Note, that tests in :source:`lib_pypy/pypy_test/` are allowed and encouraged to let their tests run at interpreter level although -`lib_pypy/`_ modules eventually live at PyPy's application level. +:source:`lib_pypy/` modules eventually live at PyPy's application level. This allows us to quickly test our python-coded reimplementations against CPython. @@ -472,7 +472,7 @@ ----------------------------------- In order to let CPython's regression tests run against PyPy -you can switch to the `lib-python/`_ directory and run +you can switch to the :source:`lib-python/` directory and run the testing tool in order to start compliance tests. (XXX check windows compatibility for producing test reports). @@ -710,6 +710,3 @@ make linkcheck which will check that remote URLs are reachable. - - -.. include:: _ref.txt diff --git a/pypy/doc/configuration.rst b/pypy/doc/configuration.rst --- a/pypy/doc/configuration.rst +++ b/pypy/doc/configuration.rst @@ -188,8 +188,6 @@ toolchain`_ toolchain, have two separate sets of options. The translation toolchain options can be found on the ``config`` attribute of all ``TranslationContext`` -instances and are described in `rpython/config/translationoption.py`_. The interpreter options +instances and are described in :source:`rpython/config/translationoption.py`. The interpreter options are attached to the object space, also under the name ``config`` and are -described in `pypy/config/pypyoption.py`_. - -.. include:: _ref.txt +described in :source:`pypy/config/pypyoption.py`. 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 @@ -16,7 +16,7 @@ List of extension modules that we support: -* Supported as built-in modules (in `pypy/module/`_): +* Supported as built-in modules (in :source:`pypy/module/`): __builtin__ `__pypy__`_ @@ -77,7 +77,7 @@ zlib When translated to Java or .NET, the list is smaller; see - `pypy/config/pypyoption.py`_ for details. + :source:`pypy/config/pypyoption.py` for details. When translated on Windows, a few Unix-only modules are skipped, and the following module is built instead: @@ -85,14 +85,14 @@ _winreg * Supported by being rewritten in pure Python (possibly using ``ctypes``): - see the `lib_pypy/`_ directory. Examples of modules that we + see the :source:`lib_pypy/` directory. Examples of modules that we support this way: ``ctypes``, ``cPickle``, ``cmath``, ``dbm``, ``datetime``... Note that some modules are both in there and in the list above; by default, the built-in module is used (but can be disabled at translation time). The extension modules (i.e. modules written in C, in the standard CPython) -that are neither mentioned above nor in `lib_pypy/`_ are not available in PyPy. +that are neither mentioned above nor in :source:`lib_pypy/` are not available in PyPy. (You may have a chance to use them anyway with `cpyext`_.) .. the nonstandard modules are listed below... @@ -316,6 +316,3 @@ opposed to a dict proxy like in CPython. Mutating the dict will change the type and vice versa. For builtin types, a dictionary will be returned that cannot be changed (but still looks and behaves like a normal dictionary). - - -.. include:: _ref.txt diff --git a/pypy/doc/ctypes-implementation.rst b/pypy/doc/ctypes-implementation.rst --- a/pypy/doc/ctypes-implementation.rst +++ b/pypy/doc/ctypes-implementation.rst @@ -1,6 +1,6 @@ -============================= -PyPy's ctypes implementation -============================= +============================ +PyPy's ctypes implementation +============================ Summary ======== @@ -33,12 +33,12 @@ Low-level part: ``_rawffi`` ============================ -This PyPy extension module (``pypy/module/_rawffi``) exposes a simple interface +This PyPy extension module (:source:`pypy/module/_rawffi`) exposes a simple interface to create C objects (arrays and structures) and calling functions in dynamic libraries through libffi. Freeing objects in most cases and making sure that objects referring to each other are kept alive is responsibility of the higher levels. -This module uses bindings to libffi which are defined in ``rpython/rlib/libffi.py``. +This module uses bindings to libffi which are defined in :source:`rpython/rlib/libffi.py`. We tried to keep this module as small as possible. It is conceivable that other implementations (e.g. Jython) could use our ctypes @@ -101,7 +101,7 @@ We tried pyglet checking it out from its repository at revision 1984. From pyglet, the following examples are known to work: - + - opengl.py - multiple_windows.py - events.py @@ -157,7 +157,4 @@ usage ----- -`ctypes_configure/doc/sample.py`_ explains in details how to use it. - - -.. include:: _ref.txt +:source:`ctypes_configure/doc/sample.py` explains in details how to use it. diff --git a/pypy/doc/getting-started-dev.rst b/pypy/doc/getting-started-dev.rst --- a/pypy/doc/getting-started-dev.rst +++ b/pypy/doc/getting-started-dev.rst @@ -14,24 +14,24 @@ relative to the PyPy top level directory). You may look at our `directory reference`_ or start off at one of the following points: -* `pypy/interpreter`_ contains the bytecode interpreter: bytecode dispatcher - in `pypy/interpreter/pyopcode.py`_, frame and code objects in `pypy/interpreter/eval.py`_ and `pypy/interpreter/pyframe.py`_, - function objects and argument passing in `pypy/interpreter/function.py`_ and `pypy/interpreter/argument.py`_, - the object space interface definition in `pypy/interpreter/baseobjspace.py`_, modules in - `pypy/interpreter/module.py`_ and `pypy/interpreter/mixedmodule.py`_. Core types supporting the bytecode - interpreter are defined in `pypy/interpreter/typedef.py`_. +* :source:`pypy/interpreter` contains the bytecode interpreter: bytecode dispatcher + in :source:`pypy/interpreter/pyopcode.py`, frame and code objects in :source:`pypy/interpreter/eval.py` and :source:`pypy/interpreter/pyframe.py`, + function objects and argument passing in :source:`pypy/interpreter/function.py` and :source:`pypy/interpreter/argument.py`, + the object space interface definition in :source:`pypy/interpreter/baseobjspace.py`, modules in + :source:`pypy/interpreter/module.py` and :source:`pypy/interpreter/mixedmodule.py`. Core types supporting the bytecode + interpreter are defined in :source:`pypy/interpreter/typedef.py`. -* `pypy/interpreter/pyparser`_ contains a recursive descent parser, +* :source:`pypy/interpreter/pyparser` contains a recursive descent parser, and grammar files that allow it to parse the syntax of various Python versions. Once the grammar has been processed, the parser can be translated by the above machinery into efficient code. -* `pypy/interpreter/astcompiler`_ contains the compiler. This +* :source:`pypy/interpreter/astcompiler` contains the compiler. This contains a modified version of the compiler package from CPython that fixes some bugs and is translatable. -* `pypy/objspace/std`_ contains the `Standard object space`_. The main file - is `pypy/objspace/std/objspace.py`_. For each type, the files ``xxxtype.py`` and +* :source:`pypy/objspace/std` contains the `Standard object space`_. The main file + is :source:`pypy/objspace/std/objspace.py`. For each type, the files ``xxxtype.py`` and ``xxxobject.py`` contain respectively the definition of the type and its (default) implementation. @@ -227,5 +227,3 @@ .. _unit tests: coding-guide.html#test-design .. _`directory reference`: index.html#pypy-directory-reference - -.. include:: _ref.txt diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -304,5 +304,3 @@ .. _`Boehm-Demers-Weiser garbage collector`: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ .. _clr: clr-module.html .. _`CPythons core language regression tests`: http://buildbot.pypy.org/summary?category=applevel&branch=%3Ctrunk%3E - -.. include:: _ref.txt diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -177,6 +177,3 @@ .. _`Using the development tracker`: coding-guide.html#using-development-tracker .. _bug reports: https://bugs.pypy.org/ - - -.. include:: _ref.txt diff --git a/pypy/doc/glossary.rst b/pypy/doc/glossary.rst --- a/pypy/doc/glossary.rst +++ b/pypy/doc/glossary.rst @@ -167,5 +167,3 @@ .. _Python: http://www.python.org .. _`RPython Typer`: rtyper.html .. _`subsystem implementing the Python language`: architecture.html#standard-interpreter - -.. include:: _ref.txt diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -115,5 +115,3 @@ .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html .. _`more stuff`: project-documentation.html - -.. include:: _ref.txt diff --git a/pypy/doc/interpreter.rst b/pypy/doc/interpreter.rst --- a/pypy/doc/interpreter.rst +++ b/pypy/doc/interpreter.rst @@ -14,7 +14,7 @@ PyPy's bytecode interpreter has a structure reminiscent of CPython's Virtual Machine: It processes code objects parsed and compiled from -Python source code. It is implemented in the `pypy/interpreter/`_ directory. +Python source code. It is implemented in the :source:`pypy/interpreter/` directory. People familiar with the CPython implementation will easily recognize similar concepts there. The major differences are the overall usage of the `object space`_ indirection to perform operations on objects, and @@ -28,7 +28,7 @@ abstract syntax tree builder and bytecode generator). The latter passes are based on the ``compiler`` package from the standard library of CPython, with various improvements and bug fixes. The bytecode compiler -(living under `pypy/interpreter/astcompiler/`_) is now integrated and is +(living under :source:`pypy/interpreter/astcompiler/`) is now integrated and is translated with the rest of PyPy. Code objects contain @@ -38,7 +38,7 @@ calling its ``frame.eval()`` method. This main entry point initialize appropriate namespaces and then interprets each bytecode instruction. Python's standard library contains -the `lib-python/2.7/dis.py`_ module which allows to inspection +the :source:`lib-python/2.7/dis.py` module which allows to inspection of the virtual machine's bytecode instructions:: >>> import dis @@ -149,12 +149,12 @@ the actual bytecodes found in a code object. The methods of the ``PyFrame`` class are added in various files: -- the class ``PyFrame`` is defined in `pypy/interpreter/pyframe.py`_. +- the class ``PyFrame`` is defined in :source:`pypy/interpreter/pyframe.py`. -- the file `pypy/interpreter/pyopcode.py`_ add support for all Python opcode. +- the file :source:`pypy/interpreter/pyopcode.py` add support for all Python opcode. - nested scope support is added to the ``PyFrame`` class in - `pypy/interpreter/nestedscope.py`_. + :source:`pypy/interpreter/nestedscope.py`. .. _Code: @@ -195,7 +195,7 @@ Function and Method classes ---------------------------- -The PyPy ``Function`` class (in `pypy/interpreter/function.py`_) +The PyPy ``Function`` class (in :source:`pypy/interpreter/function.py`) represents a Python function. A ``Function`` carries the following main attributes: @@ -218,7 +218,7 @@ Arguments Class -------------------- -The Argument class (in `pypy/interpreter/argument.py`_) is +The Argument class (in :source:`pypy/interpreter/argument.py`) is responsible for parsing arguments passed to functions. Python has rather complex argument-passing concepts: @@ -257,10 +257,10 @@ Apart from the basic Module used for importing application-level files there is a more refined -``MixedModule`` class (see `pypy/interpreter/mixedmodule.py`_) +``MixedModule`` class (see :source:`pypy/interpreter/mixedmodule.py`) which allows to define name-value bindings both at application level and at interpreter level. See the ``__builtin__`` -module's `pypy/module/__builtin__/__init__.py`_ file for an +module's :source:`pypy/module/__builtin__/__init__.py` file for an example and the higher level `chapter on Modules in the coding guide`_. @@ -275,7 +275,7 @@ A unique PyPy property is the ability to easily cross the barrier between interpreted and machine-level code (often referred to as the difference between `interpreter-level and application-level`_). -Be aware that the according code (in `pypy/interpreter/gateway.py`_) +Be aware that the according code (in :source:`pypy/interpreter/gateway.py`) for crossing the barrier in both directions is somewhat involved, mostly due to the fact that the type-inferring annotator needs to keep track of the types of objects flowing @@ -361,7 +361,7 @@ The ``find_metaclass`` interpreter-level hook is invoked with five arguments from the ``BUILD_CLASS`` opcode implementation -in `pypy/interpreter/pyopcode.py`_:: +in :source:`pypy/interpreter/pyopcode.py`:: def BUILD_CLASS(f): w_methodsdict = f.valuestack.pop() @@ -398,8 +398,6 @@ a wrapped object for its type via a ``getclass`` method and then calls the type's ``lookup(name)`` function in order to receive a descriptor function. Most of PyPy's internal object descriptors are defined at the -end of `pypy/interpreter/typedef.py`_. You can use these definitions +end of :source:`pypy/interpreter/typedef.py`. You can use these definitions as a reference for the exact attributes of interpreter classes visible at application level. - -.. include:: _ref.txt diff --git a/pypy/doc/objspace-proxies.rst b/pypy/doc/objspace-proxies.rst --- a/pypy/doc/objspace-proxies.rst +++ b/pypy/doc/objspace-proxies.rst @@ -61,7 +61,7 @@ ---------------------------------------------------- Suppose we want to have a list which stores all operations performed on -it for later analysis. We can use the small `lib_pypy/tputil.py`_ module to help +it for later analysis. We can use the small :source:`lib_pypy/tputil.py` module to help with transparently proxying builtin instances:: from tputil import make_proxy @@ -113,7 +113,7 @@ tputil helper module ---------------------------- -The `lib_pypy/tputil.py`_ module provides: +The :source:`lib_pypy/tputil.py` module provides: * ``make_proxy(controller, type, obj)``: function which creates a transparent proxy controlled by the given @@ -171,8 +171,8 @@ to application level code. Transparent proxies are implemented on top of the `standard object -space`_, in `pypy/objspace/std/proxy_helpers.py`_, `pypy/objspace/std/proxyobject.py`_ and -`pypy/objspace/std/transparent.py`_. To use them you will need to pass a +space`_, in :source:`pypy/objspace/std/proxy_helpers.py`, :source:`pypy/objspace/std/proxyobject.py` and +:source:`pypy/objspace/std/transparent.py`. To use them you will need to pass a `--objspace-std-withtproxy`_ option to ``py.py`` or ``translate.py``. This registers implementations named ``W_TransparentXxx`` - which usually correspond to an @@ -186,5 +186,3 @@ .. [D12.1] `High-Level Backends and Interpreter Feature Prototypes`, PyPy EU-Report, 2007, http://codespeak.net/pypy/extradoc/eu-report/D12.1_H-L-Backends_and_Feature_Prototypes-2007-03-22.pdf - -.. include:: _ref.txt diff --git a/pypy/doc/objspace.rst b/pypy/doc/objspace.rst --- a/pypy/doc/objspace.rst +++ b/pypy/doc/objspace.rst @@ -52,7 +52,7 @@ The present document gives a description of the above object spaces. The sources of PyPy contain the various object spaces in the directory -`pypy/objspace/`_. +:source:`pypy/objspace/`. .. _`application-level`: coding-guide.html#application-level .. _`interpreter-level`: coding-guide.html#interpreter-level @@ -71,11 +71,11 @@ ``getexecutioncontext():`` Return current active execution context - (`pypy/interpreter/executioncontext.py`_). + (:source:`pypy/interpreter/executioncontext.py`). ``getbuiltinmodule(name):`` Return a Module object for the built-in module given by name - (`pypy/interpreter/module.py`_). + (:source:`pypy/interpreter/module.py`). Operations on Objects in the Object Space ----------------------------------------- @@ -291,7 +291,7 @@ Introduction ------------ -The Standard Object Space (`pypy/objspace/std/`_) is the direct equivalent of CPython's +The Standard Object Space (:source:`pypy/objspace/std/`) is the direct equivalent of CPython's object library (the "Objects/" subdirectory in the distribution). It is an implementation of the common Python types in a lower-level language. @@ -339,7 +339,7 @@ Object types ------------ -The larger part of the `pypy/objspace/std/`_ package defines and implements the +The larger part of the :source:`pypy/objspace/std/` package defines and implements the library of Python's standard built-in object types. Each type (int, float, list, tuple, str, type, etc.) is typically implemented by two modules: @@ -348,17 +348,17 @@ * the *implementation* module, called ``xxxobject.py``. The ``xxxtype.py`` module basically defines the type object itself. For -example, `pypy/objspace/std/listtype.py`_ contains the specification of the object you get when -you type ``list`` in a PyPy prompt. `pypy/objspace/std/listtype.py`_ enumerates the methods +example, :source:`pypy/objspace/std/listtype.py` contains the specification of the object you get when +you type ``list`` in a PyPy prompt. :source:`pypy/objspace/std/listtype.py` enumerates the methods specific to lists, like ``append()``. A particular method implemented by all types is the ``__new__()`` special method, which in Python's new-style-classes world is responsible for creating an instance of the type. In PyPy, ``__new__()`` locates and imports the module implementing *instances* of the type, and creates such an instance based on the -arguments the user supplied to the constructor. For example, `pypy/objspace/std/tupletype.py`_ +arguments the user supplied to the constructor. For example, :source:`pypy/objspace/std/tupletype.py` defines ``__new__()`` to import the class ``W_TupleObject`` from -`pypy/objspace/std/tupleobject.py`_ and instantiate it. The `pypy/objspace/std/tupleobject.py`_ then contains a +:source:`pypy/objspace/std/tupleobject.py` and instantiate it. The :source:`pypy/objspace/std/tupleobject.py` then contains a "real" implementation of tuples: the way the data is stored in the ``W_TupleObject`` class, how the operations work, etc. @@ -374,9 +374,9 @@ same Python type. PyPy knows that (e.g.) the application-level type of its interpreter-level ``W_StringObject`` instances is str because there is a ``typedef`` class attribute in ``W_StringObject`` which -points back to the string type specification from `pypy/objspace/std/stringtype.py`_; all +points back to the string type specification from :source:`pypy/objspace/std/stringtype.py`; all other implementations of strings use the same ``typedef`` from -`pypy/objspace/std/stringtype.py`_. +:source:`pypy/objspace/std/stringtype.py`. For other examples of multiple implementations of the same Python type, see `Standard Interpreter Optimizations`_. @@ -390,7 +390,7 @@ The Standard Object Space allows multiple object implementations per Python type - this is based on multimethods_. For a description of the multimethod variant that we implemented and which features it supports, -see the comment at the start of `pypy/objspace/std/multimethod.py`_. However, multimethods +see the comment at the start of :source:`pypy/objspace/std/multimethod.py`. However, multimethods alone are not enough for the Standard Object Space: the complete picture spans several levels in order to emulate the exact Python semantics. @@ -491,7 +491,7 @@ Introduction ------------ -The task of the FlowObjSpace (the source is at `pypy/objspace/flow/`_) is to generate a control-flow graph from a +The task of the FlowObjSpace (the source is at :source:`pypy/objspace/flow/`) is to generate a control-flow graph from a function. This graph will also contain a trace of the individual operations, so that it is actually just an alternate representation for the function. @@ -570,5 +570,3 @@ PyPy can do for your objects`_. .. _`What PyPy can do for your objects`: objspace-proxies.html - -.. include:: _ref.txt diff --git a/pypy/doc/parser.rst b/pypy/doc/parser.rst --- a/pypy/doc/parser.rst +++ b/pypy/doc/parser.rst @@ -12,7 +12,7 @@ --------- At the moment, the tokenizer is implemented as a single function -(``generate_tokens`` in `pypy/interpreter/pyparser/pytokenizer.py`_) that builds +(``generate_tokens`` in :source:`pypy/interpreter/pyparser/pytokenizer.py`) that builds a list of tokens. The tokens are then fed to the parser. Parser @@ -24,7 +24,7 @@ *************************** The python grammar is built at startup from the pristine CPython grammar file -(see `pypy/interpreter/pyparser/metaparser.py`_). The grammar builder first +(see :source:`pypy/interpreter/pyparser/metaparser.py`). The grammar builder first represents the grammar as rules corresponding to a set of Nondeterministic Finite Automatons (NFAs). It then converts them to a set of Deterministic Finite Automatons (DFAs). The difference between a NFA and a DFA is that a NFA @@ -32,7 +32,7 @@ have one. DFAs are therefore more limiting, but far more efficient to use in parsing. Finally, the assigns the grammar builder assigns each DFA state a number and packs them into a list for the parser to use. The final product is -an instance of the ``Grammar`` class in `pypy/interpreter/pyparser/parser.py`_. +an instance of the ``Grammar`` class in :source:`pypy/interpreter/pyparser/parser.py`. Parser implementation ********************* @@ -48,11 +48,11 @@ ************** The glue code between the tokenizer and the parser as well as extra Python -specific code is in `pypy/interpreter/pyparser/pyparse.py`_. The +specific code is in :source:`pypy/interpreter/pyparser/pyparse.py`. The ``parse_source`` method takes a string of Python code and returns the parse tree. It also detects the coding cookie if there is one and decodes the source. Note that __future__ imports are handled before the parser is invoked by -manually parsing the source in `pypy/interpreter/pyparser/future.py`_. +manually parsing the source in :source:`pypy/interpreter/pyparser/future.py`. Compiler -------- @@ -63,21 +63,21 @@ Building AST ************ -Python's AST is described in `pypy/interpreter/astcompiler/tools/Python.asdl`_. -From this definition, `pypy/interpreter/astcompiler/tools/asdl_py.py`_ generates -`pypy/interpreter/astcompiler/ast.py`_, which RPython classes for the compiler +Python's AST is described in :source:`pypy/interpreter/astcompiler/tools/Python.asdl`. +From this definition, :source:`pypy/interpreter/astcompiler/tools/asdl_py.py` generates +:source:`pypy/interpreter/astcompiler/ast.py`, which RPython classes for the compiler as well as bindings to application level code for the AST. Some custom extensions to the AST classes are in -`pypy/interpreter/astcompiler/asthelpers.py`_. +:source:`pypy/interpreter/astcompiler/asthelpers.py`. -`pypy/interpreter/astcompiler/astbuilder.py`_ is responsible for converting +:source:`pypy/interpreter/astcompiler/astbuilder.py` is responsible for converting parse trees into AST. It walks down the parse tree building nodes as it goes. The result is a toplevel ``mod`` node. AST Optimization **************** -`pypy/interpreter/astcompiler/optimize.py`_ contains the AST optimizer. It does +:source:`pypy/interpreter/astcompiler/optimize.py` contains the AST optimizer. It does constant folding of expressions, and other simple transformations like making a load of the name "None" into a constant. @@ -85,7 +85,7 @@ *************** Before writing bytecode, a symbol table is built in -`pypy/interpreter/astcompiler/symtable.py`_. It determines if every name in the +:source:`pypy/interpreter/astcompiler/symtable.py`. It determines if every name in the source is local, implicitly global (no global declaration), explicitly global (there's a global declaration of the name in the scope), a cell (the name in used in nested scopes), or free (it's used in a nested function). @@ -93,11 +93,9 @@ Bytecode generation ******************* -Bytecode is emitted in `pypy/interpreter/astcompiler/codegen.py`_. Each +Bytecode is emitted in :source:`pypy/interpreter/astcompiler/codegen.py`. Each bytecode is represented temporarily by the ``Instruction`` class in -`pypy/interpreter/astcompiler/assemble.py`_. After all bytecodes have been +:source:`pypy/interpreter/astcompiler/assemble.py`. After all bytecodes have been emitted, it's time to build the code object. Jump offsets and bytecode information like the line number table and stack depth are computed. Finally, everything is passed to a brand new ``PyCode`` object. - -.. include:: _ref.txt diff --git a/pypy/doc/project-documentation.rst b/pypy/doc/project-documentation.rst --- a/pypy/doc/project-documentation.rst +++ b/pypy/doc/project-documentation.rst @@ -161,5 +161,3 @@ * :ref:`genindex` * :ref:`search` * :ref:`glossary` - -.. include:: _ref.txt diff --git a/pypy/doc/stackless.rst b/pypy/doc/stackless.rst --- a/pypy/doc/stackless.rst +++ b/pypy/doc/stackless.rst @@ -29,7 +29,7 @@ on 32-bit or a complete megabyte on 64-bit. Moreover, the feature is only available (so far) on x86 and x86-64 CPUs; for other CPUs you need to add a short page of custom assembler to -`rpython/translator/c/src/stacklet/`_. +:source:`rpython/translator/c/src/stacklet/`. Theory @@ -185,7 +185,7 @@ Greenlets +++++++++ -Greenlets are implemented on top of continulets in `lib_pypy/greenlet.py`_. +Greenlets are implemented on top of continulets in :source:`lib_pypy/greenlet.py`. See the official `documentation of the greenlets`_. Note that unlike the CPython greenlets, this version does not suffer @@ -271,7 +271,7 @@ Continulets are internally implemented using stacklets, which is the generic RPython-level building block for "one-shot continuations". For more information about them please see the documentation in the C source -at `rpython/translator/c/src/stacklet/stacklet.h`_. +at :source:`rpython/translator/c/src/stacklet/stacklet.h`. The module ``rpython.rlib.rstacklet`` is a thin wrapper around the above functions. The key point is that new() and switch() always return a @@ -411,5 +411,3 @@ .. _`Stackless Python`: http://www.stackless.com .. _`documentation of the greenlets`: http://packages.python.org/greenlet/ - -.. include:: _ref.txt From noreply at buildbot.pypy.org Mon May 6 17:03:29 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 17:03:29 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Fix project-documentation.rst. Message-ID: <20130506150329.431441C13A8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63889:4ca1e419bd6e Date: 2013-05-06 16:56 +0200 http://bitbucket.org/pypy/pypy/changeset/4ca1e419bd6e/ Log: Fix project-documentation.rst. diff --git a/pypy/doc/project-documentation.rst b/pypy/doc/project-documentation.rst --- a/pypy/doc/project-documentation.rst +++ b/pypy/doc/project-documentation.rst @@ -2,15 +2,15 @@ Project Documentation ===================================== -`architecture`_ gives a complete view of PyPy's basic design. +`architecture`_ gives a complete view of PyPy's basic design. `coding guide`_ helps you to write code for PyPy (especially also describes -coding in RPython a bit). +coding in RPython a bit). `sprint reports`_ lists reports written at most of our sprints, from 2003 to the present. -`papers, talks and related projects`_ lists presentations +`papers, talks and related projects`_ lists presentations and related projects as well as our published papers. `PyPy video documentation`_ is a page linking to the videos (e.g. of talks and @@ -21,7 +21,7 @@ `development methodology`_ describes our sprint-driven approach. -`LICENSE`_ contains licensing details (basically a straight MIT-license). +`LICENSE`_ contains licensing details (basically a straight MIT-license). `Glossary`_ of PyPy words to help you align your inner self with the PyPy universe. @@ -29,20 +29,17 @@ Source Code Documentation =============================================== -`object spaces`_ discusses the object space interface -and several implementations. +`object spaces`_ discusses the object space interface +and several implementations. -`bytecode interpreter`_ explains the basic mechanisms -of the bytecode interpreter and virtual machine. +`bytecode interpreter`_ explains the basic mechanisms +of the bytecode interpreter and virtual machine. `interpreter optimizations`_ describes our various strategies for improving the performance of our interpreter, including alternative object implementations (for strings, dictionaries and lists) in the standard object space. -`translation`_ is a detailed overview of our translation process. The -rtyper_ is the largest component of our translation process. - `dynamic-language translation`_ is a paper that describes the translation process, especially the flow object space and the annotator in detail. (This document is one @@ -56,32 +53,17 @@ properties into our interpreter during the translation process. This document is also part of the `EU reports`_. -`garbage collector`_ strategies that can be used by the virtual -machines produced by the translation process. - `parser`_ contains (outdated, unfinished) documentation about the parser. -`rlib`_ describes some modules that can be used when implementing programs in -RPython. - `configuration documentation`_ describes the various configuration options that allow you to customize PyPy. -`pypy on windows`_ - `command line reference`_ -`CLI backend`_ describes the details of the .NET backend. - -`JIT Generation in PyPy`_ describes how we produce the Python Just-in-time Compiler -from our Python interpreter. - `directory cross-reference`_ -.. _`garbage collector`: garbage_collection.html .. _`directory cross-reference`: dir-reference.html -.. _`pypy on windows`: windows.html .. _`command line reference`: commandline_ref.html .. _`FAQ`: faq.html .. _Glossary: glossary.html @@ -90,24 +72,22 @@ .. _`development methodology`: dev_method.html .. _`sprint reports`: sprint-reports.html .. _`papers, talks and related projects`: extradoc.html -.. _`object spaces`: objspace.html -.. _`interpreter optimizations`: interpreter-optimizations.html -.. _`translation`: translation.html +.. _`object spaces`: objspace.html +.. _`interpreter optimizations`: interpreter-optimizations.html .. _`dynamic-language translation`: https://bitbucket.org/pypy/extradoc/raw/tip/eu-report/D05.1_Publish_on_translating_a_very-high-level_description.pdf .. _`low-level encapsulation`: low-level-encapsulation.html .. _`translation aspects`: translation-aspects.html .. _`configuration documentation`: config/ -.. _`coding guide`: coding-guide.html -.. _`Architecture`: architecture.html -.. _`getting started`: getting-started.html -.. _`bytecode interpreter`: interpreter.html +.. _`coding guide`: coding-guide.html +.. _`Architecture`: architecture.html +.. _`getting started`: getting-started.html +.. _`bytecode interpreter`: interpreter.html .. _`EU reports`: index-report.html .. _`Technical reports`: index-report.html .. _`summary`: http://buildbot.pypy.org/summary .. _`ideas for PyPy related projects`: project-ideas.html .. _`Nightly builds and benchmarks`: http://tuatara.cs.uni-duesseldorf.de/benchmark.html -.. _`directory reference`: -.. _`rlib`: rlib.html +.. _`directory reference`: .. _`Sandboxing Python code`: sandbox.html .. _`LICENSE`: https://bitbucket.org/pypy/pypy/src/default/LICENSE From noreply at buildbot.pypy.org Mon May 6 17:03:30 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 6 May 2013 17:03:30 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add pytest link. Message-ID: <20130506150330.887E61C13A8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63890:2883e06facc5 Date: 2013-05-06 17:01 +0200 http://bitbucket.org/pypy/pypy/changeset/2883e06facc5/ Log: Add pytest link. diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -25,6 +25,8 @@ since this is a tool we use for tests. This leads to the next issue: +.. _`pytest`: http://pytest.org/ + Layers ------ From noreply at buildbot.pypy.org Mon May 6 17:11:44 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Mon, 6 May 2013 17:11:44 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Make the translator happy Message-ID: <20130506151144.922AD1C13A8@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r63891:44b9969e7d20 Date: 2013-05-06 17:10 +0200 http://bitbucket.org/pypy/pypy/changeset/44b9969e7d20/ Log: Make the translator happy diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -325,11 +325,11 @@ return None class ConcreteArray(ConcreteArrayNotOwning): - def __init__(self, shape, dtype, order, strides, backstrides, storage=None): + def __init__(self, shape, dtype, order, strides, backstrides, storage=lltype.nullptr(RAW_STORAGE)): null_storage = lltype.nullptr(RAW_STORAGE) ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides, null_storage) - if storage is None: + if storage == lltype.nullptr(RAW_STORAGE): self.storage = dtype.itemtype.malloc(self.size) else: self.storage = storage diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -132,14 +132,16 @@ def set_fields(self, space, w_fields): if w_fields == space.w_None: - self.fields = {} + self.fields = None else: iter = space.iter(w_fields) while True: try: key = space.next(iter) value = space.getitem(w_fields, key) - self.fields[space.str_w(space.next(iter))] = space.int_w(space.getitem(value, 1)), space.getitem(value, 0) + dtype = space.getitem(value, space.wrap(0)) + assert isinstance(dtype, W_Dtype) + self.fields[space.str_w(space.next(iter))] = space.int_w(space.getitem(value, space.wrap(1))), dtype except OperationError, e: if not e.match(space, space.w_StopIteration): raise @@ -223,7 +225,9 @@ #TODO: Change this when alignment is implemented : size = 0 for key in self.fields: - size += self.fields[key].get_size() + dtype = self.fields[key][1] + assert isinstance(dtype, W_Dtype) + size += dtype.get_size() w_size = space.wrap(size) alignment = space.wrap(1) else: @@ -240,14 +244,13 @@ if space.int_w(space.getitem(w_data, space.wrap(0))) != 3: raise OperationError(space.w_NotImplementedError, space.wrap("Pickling protocol version not supported")) - self.native = space.getitem(w_data, space.wrap(1)) == byteorder_prefix + self.native = space.str_w(space.getitem(w_data, space.wrap(1))) == byteorder_prefix fieldnames = space.getitem(w_data, space.wrap(2)) self.set_names(space, fieldnames) fields = space.getitem(w_data, space.wrap(3)) - if fields != space.w_None: - self.set_fields(space, fields) + self.set_fields(space, fields) class W_ComplexDtype(W_Dtype): def __init__(self, itemtype, num, kind, name, char, w_box_type, diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -778,8 +778,13 @@ def descr_reduce(self, space): from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rstring import StringBuilder + from pypy.interpreter.mixedmodule import MixedModule - reconstruct = space.getbuiltinmodule("_numpypy").get("multiarray").get("_reconstruct") + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + reconstruct = multiarray.get("_reconstruct") parameters = space.newtuple([space.gettypefor(W_NDimArray), space.newtuple([space.wrap(0)]), space.wrap("b")]) @@ -801,6 +806,7 @@ shape = space.getitem(w_state, space.wrap(1)) dtype = space.getitem(w_state, space.wrap(2)) + assert isinstance(dtype, interp_dtype.W_Dtype) isfortran = space.getitem(w_state, space.wrap(3)) storage = space.getitem(w_state, space.wrap(4)) @@ -1035,6 +1041,7 @@ return space.wrap(arr) def _reconstruct(space, w_subtype, w_shape, w_dtype): + assert isinstance(w_dtype, interp_dtype.W_Dtype) return descr_new_array(space, w_subtype, w_shape, w_dtype) W_FlatIterator.typedef = TypeDef( diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -696,7 +696,10 @@ def str2charp(s, track_allocation=True): """ str -> char* """ - array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=track_allocation) + if track_allocation: + array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=True) + else: + array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=False) i = len(s) array[i] = lastchar i -= 1 @@ -704,10 +707,13 @@ array[i] = s[i] i -= 1 return array - str2charp._annenforceargs_ = [strtype] + str2charp._annenforceargs_ = [strtype, bool] def free_charp(cp, track_allocation=True): - lltype.free(cp, flavor='raw', track_allocation=track_allocation) + if track_allocation: + lltype.free(cp, flavor='raw', track_allocation=True) + else: + lltype.free(cp, flavor='raw', track_allocation=False) # char* -> str # doesn't free char* From noreply at buildbot.pypy.org Mon May 6 20:13:20 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 6 May 2013 20:13:20 +0200 (CEST) Subject: [pypy-commit] pypy gc-del: A failing test. Message-ID: <20130506181320.3BB951C0307@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: gc-del Changeset: r63892:6fed217ef39c Date: 2013-05-06 20:12 +0200 http://bitbucket.org/pypy/pypy/changeset/6fed217ef39c/ Log: A failing test. diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1047,6 +1047,22 @@ import gc; gc.collect() assert not seen + def test_change_type_to_add_del(self): + seen = [] + class A(object): + def __del__(self): + seen.append(1) + class B(object): + pass + b = B() + b.__class__ = A + b = 42 + for i in range(5): + if seen: + break + import gc; gc.collect() + assert seen + class AppTestWithMethodCacheCounter: spaceconfig = {"objspace.std.withmethodcachecounter": True} From noreply at buildbot.pypy.org Mon May 6 21:25:17 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 6 May 2013 21:25:17 +0200 (CEST) Subject: [pypy-commit] pypy default: For JIT backends without support for LONGLONGs or single FLOATs: hack Message-ID: <20130506192517.6A8291C0307@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63893:05c73d13ade5 Date: 2013-05-06 21:24 +0200 http://bitbucket.org/pypy/pypy/changeset/05c73d13ade5/ Log: For JIT backends without support for LONGLONGs or single FLOATs: hack hack hack. :-/ 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 @@ -56,10 +56,15 @@ return rffi.cast(lltype.Unsigned, rffi.cast(TPP, target)[0]) raise NotImplementedError("bad integer size") + at specialize.arg(0) +def _read_raw_float_data_tp(TPP, target): + # in its own function: FLOAT may make the whole function jit-opaque + return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0]) + def read_raw_float_data(target, size): for TP, TPP in _prim_float_types: if size == rffi.sizeof(TP): - return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0]) + return _read_raw_float_data_tp(TPP, target) raise NotImplementedError("bad float size") def read_raw_longdouble_data(target): @@ -82,10 +87,15 @@ raise NotImplementedError("bad integer size") + at specialize.arg(0, 1) +def _write_raw_float_data_tp(TP, TPP, target, source): + # in its own function: FLOAT may make the whole function jit-opaque + rffi.cast(TPP, target)[0] = rffi.cast(TP, source) + def write_raw_float_data(target, source, size): for TP, TPP in _prim_float_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, target)[0] = rffi.cast(TP, source) + _write_raw_float_data_tp(TP, TPP, target, source) return raise NotImplementedError("bad float size") @@ -263,13 +273,18 @@ # ____________________________________________________________ + at specialize.arg(0) +def _raw_memcopy_tp(TPP, source, dest): + # in its own function: LONGLONG may make the whole function jit-opaque + rffi.cast(TPP, dest)[0] = rffi.cast(TPP, source)[0] + def _raw_memcopy(source, dest, size): if jit.isconstant(size): # for the JIT: first handle the case where 'size' is known to be # a constant equal to 1, 2, 4, 8 for TP, TPP in _prim_unsigned_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, dest)[0] = rffi.cast(TPP, source)[0] + _raw_memcopy_tp(TPP, source, dest) return _raw_memcopy_opaque(source, dest, size) @@ -283,10 +298,15 @@ llmemory.cast_ptr_to_adr(dest) + zero, size * llmemory.sizeof(lltype.Char)) + at specialize.arg(0, 1) +def _raw_memclear_tp(TP, TPP, dest): + # in its own function: LONGLONG may make the whole function jit-opaque + rffi.cast(TPP, dest)[0] = rffi.cast(TP, 0) + def _raw_memclear(dest, size): # for now, only supports the cases of size = 1, 2, 4, 8 for TP, TPP in _prim_unsigned_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, dest)[0] = rffi.cast(TP, 0) + _raw_memclear_tp(TP, TPP, dest) return raise NotImplementedError("bad clear size") From noreply at buildbot.pypy.org Mon May 6 21:45:59 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 6 May 2013 21:45:59 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: merge default Message-ID: <20130506194559.618691C1324@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: release-2.0.x Changeset: r63894:85f4226e0b7a Date: 2013-05-06 21:44 +0200 http://bitbucket.org/pypy/pypy/changeset/85f4226e0b7a/ Log: merge default diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -167,7 +167,6 @@ return if '_fields_' not in self.__dict__: self._fields_ = [] - self._names = [] _set_shape(self, [], self._is_union) __setattr__ = struct_setattr diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -1,25 +1,21 @@ -import os +import sys, os from ctypes_configure import dumpcache -from rpython.jit.backend import detect_cpu def dumpcache2(basename, config): - model = detect_cpu.autodetect_main_model_and_size() - filename = '_%s_%s_.py' % (basename, model) + size = 32 if sys.maxint <= 2**32 else 64 + filename = '_%s_%s_.py' % (basename, size) dumpcache.dumpcache(__file__, filename, config) # filename = os.path.join(os.path.dirname(__file__), '_%s_cache.py' % (basename,)) g = open(filename, 'w') print >> g, '''\ -try: - from __pypy__ import cpumodel -except ImportError: - from rpython.jit.backend import detect_cpu - cpumodel = detect_cpu.autodetect_main_model_and_size() +import sys +_size = 32 if sys.maxint <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib -mod = __import__("_%s_%%s_" %% (cpumodel,), - globals(), locals(), ["*"]) -globals().update(mod.__dict__)\ +_mod = __import__("_%s_%%s_" %% (_size,), + globals(), locals(), ["*"]) +globals().update(_mod.__dict__)\ ''' % (basename,) g.close() diff --git a/lib_pypy/ctypes_config_cache/rebuild.py b/lib_pypy/ctypes_config_cache/rebuild.py --- a/lib_pypy/ctypes_config_cache/rebuild.py +++ b/lib_pypy/ctypes_config_cache/rebuild.py @@ -25,13 +25,12 @@ sys.path[:] = path def try_rebuild(): - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - # remove the files '_*_model_.py' + size = 32 if sys.maxint <= 2**32 else 64 + # remove the files '_*_size_.py' left = {} for p in os.listdir(_dirpath): - if p.startswith('_') and (p.endswith('_%s_.py' % model) or - p.endswith('_%s_.pyc' % model)): + if p.startswith('_') and (p.endswith('_%s_.py' % size) or + p.endswith('_%s_.pyc' % size)): os.unlink(os.path.join(_dirpath, p)) elif p.startswith('_') and (p.endswith('_.py') or p.endswith('_.pyc')): diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -84,6 +84,7 @@ '_multiprocessing': [('objspace.usemodules.rctime', True), ('objspace.usemodules.thread', True)], 'cpyext': [('objspace.usemodules.array', True)], + 'cppyy': [('objspace.usemodules.cpyext', True)], } module_suggests = { # the reason you want _rawffi is for ctypes, which diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -3,18 +3,18 @@ ============================ We're pleased to announce PyPy 2.0. This is a stable release that brings -swath of bugfixes, small performance improvements and compatibility fixes. +a swath of bugfixes, small performance improvements and compatibility fixes. You can download the PyPy 2.0 release here: http://pypy.org/download.html -Two biggest changes since PyPy 1.9 are: +The two biggest changes since PyPy 1.9 are: * stackless is now supported including greenlets, which means eventlet and gevent should work (but read below about gevent) -* PyPy now contains a release 0.6 of `cffi`_ as a builtin module, which +* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which is preferred way of calling C from Python that works well on PyPy .. _`cffi`: http://cffi.readthedocs.org @@ -37,17 +37,22 @@ ========== * Stackless including greenlets should work. For gevent, you need to check - out `pypycore`_ and use `pypy-hacks`_ branch of gevent. + out `pypycore`_ and use the `pypy-hacks`_ branch of gevent. -* cffi is not a module included with PyPy. It's a preferred way of calling - C from Python that works on PyPy. +* cffi is now a module included with PyPy. (`cffi`_ also exists for + CPython; the two versions should be fully compatible.) It is the + preferred way of calling C from Python that works on PyPy. -* Callbacks from C are now JITted, which means XML parsing is much faster +* Callbacks from C are now JITted, which means XML parsing is much faster. * A lot of speed improvements in various language corners, most of them small, - but speeding up a particular corner a lot + but speeding up some particular corners a lot. -* A lot of stability issues fixed +* The JIT was refactored to emit machine code which manipulates a "frame" + that lives on the heap rather than on the stack. This is what makes + Stackless work, and it could bring another future speed-up (not done yet). + +* A lot of stability issues fixed. .. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ .. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -6,8 +6,14 @@ if sys.platform.startswith('linux'): arch = 'linux' + cmd = 'wget "%s"' + tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" +if sys.platform.startswith('darwin'): + arch = 'osx' + cmd = 'curl -O "%s"' + tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" else: - print 'Cannot determine the platform, please update this scrip' + print 'Cannot determine the platform, please update this script' sys.exit(1) if sys.maxint == 2**63 - 1: @@ -23,10 +29,9 @@ tmp = py.path.local.mkdtemp() mydir = tmp.chdir() print 'Downloading pypy to', tmp -if os.system('wget "%s"' % url) != 0: +if os.system(cmd % url) != 0: sys.exit(1) print 'Extracting pypy binary' mydir.chdir() -os.system("tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" % tmp.join(filename)) - +os.system(tar % tmp.join(filename)) diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -82,6 +82,17 @@ PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) # - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + try: + from rpython.jit.backend import detect_cpu + model = detect_cpu.autodetect() + self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + except Exception: + if self.space.config.translation.jit: + raise + else: + pass # ok fine to ignore in this case + # + if self.space.config.translation.jit: + features = detect_cpu.getcpufeatures(model) + self.extra_interpdef('jit_backend_features', + 'space.wrap(%r)' % features) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -62,3 +62,14 @@ assert list_strategy(l) == "empty" o = 5 raises(TypeError, list_strategy, 5) + + +class AppTestJitFeatures(object): + spaceconfig = {"translation.jit": True} + + def test_jit_backend_features(self): + from __pypy__ import jit_backend_features + supported_types = jit_backend_features + assert isinstance(supported_types, list) + for x in supported_types: + assert x in ['floats', 'singlefloats', 'longlong'] 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 @@ -56,10 +56,15 @@ return rffi.cast(lltype.Unsigned, rffi.cast(TPP, target)[0]) raise NotImplementedError("bad integer size") + at specialize.arg(0) +def _read_raw_float_data_tp(TPP, target): + # in its own function: FLOAT may make the whole function jit-opaque + return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0]) + def read_raw_float_data(target, size): for TP, TPP in _prim_float_types: if size == rffi.sizeof(TP): - return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0]) + return _read_raw_float_data_tp(TPP, target) raise NotImplementedError("bad float size") def read_raw_longdouble_data(target): @@ -82,10 +87,15 @@ raise NotImplementedError("bad integer size") + at specialize.arg(0, 1) +def _write_raw_float_data_tp(TP, TPP, target, source): + # in its own function: FLOAT may make the whole function jit-opaque + rffi.cast(TPP, target)[0] = rffi.cast(TP, source) + def write_raw_float_data(target, source, size): for TP, TPP in _prim_float_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, target)[0] = rffi.cast(TP, source) + _write_raw_float_data_tp(TP, TPP, target, source) return raise NotImplementedError("bad float size") @@ -263,13 +273,18 @@ # ____________________________________________________________ + at specialize.arg(0) +def _raw_memcopy_tp(TPP, source, dest): + # in its own function: LONGLONG may make the whole function jit-opaque + rffi.cast(TPP, dest)[0] = rffi.cast(TPP, source)[0] + def _raw_memcopy(source, dest, size): if jit.isconstant(size): # for the JIT: first handle the case where 'size' is known to be # a constant equal to 1, 2, 4, 8 for TP, TPP in _prim_unsigned_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, dest)[0] = rffi.cast(TPP, source)[0] + _raw_memcopy_tp(TPP, source, dest) return _raw_memcopy_opaque(source, dest, size) @@ -283,10 +298,15 @@ llmemory.cast_ptr_to_adr(dest) + zero, size * llmemory.sizeof(lltype.Char)) + at specialize.arg(0, 1) +def _raw_memclear_tp(TP, TPP, dest): + # in its own function: LONGLONG may make the whole function jit-opaque + rffi.cast(TPP, dest)[0] = rffi.cast(TP, 0) + def _raw_memclear(dest, size): # for now, only supports the cases of size = 1, 2, 4, 8 for TP, TPP in _prim_unsigned_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, dest)[0] = rffi.cast(TP, 0) + _raw_memclear_tp(TP, TPP, dest) return raise NotImplementedError("bad clear size") diff --git a/pypy/module/_io/__init__.py b/pypy/module/_io/__init__.py --- a/pypy/module/_io/__init__.py +++ b/pypy/module/_io/__init__.py @@ -38,5 +38,5 @@ def shutdown(self, space): # at shutdown, flush all open streams. Ignore I/O errors. - from pypy.module._io.interp_iobase import get_autoflushher - get_autoflushher(space).flush_all(space) + from pypy.module._io.interp_iobase import get_autoflusher + get_autoflusher(space).flush_all(space) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -47,7 +47,7 @@ self.w_dict = space.newdict() self.__IOBase_closed = False self.streamholder = None # needed by AutoFlusher - get_autoflushher(space).add(self) + get_autoflusher(space).add(self) def getdict(self, space): return self.w_dict @@ -103,7 +103,7 @@ space.call_method(self, "flush") finally: self.__IOBase_closed = True - get_autoflushher(space).remove(self) + get_autoflusher(space).remove(self) def flush_w(self, space): if self._CLOSED(): @@ -363,5 +363,5 @@ else: streamholder.autoflush(space) -def get_autoflushher(space): +def get_autoflusher(space): return space.fromcache(AutoFlusher) diff --git a/pypy/module/_random/interp_random.py b/pypy/module/_random/interp_random.py --- a/pypy/module/_random/interp_random.py +++ b/pypy/module/_random/interp_random.py @@ -33,8 +33,8 @@ elif space.isinstance_w(w_n, space.w_long): w_n = space.abs(w_n) else: - # XXX not perfectly like CPython - w_n = space.abs(space.hash(w_n)) + n = space.hash_w(w_n) + w_n = space.wrap(r_uint(n)) key = [] w_one = space.newint(1) w_two = space.newint(2) diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -42,13 +42,14 @@ rnd1.setstate((-1, ) * 624 + (0, )) def test_seed(self): - import _random + import _random, sys rnd = _random.Random() rnd.seed() different_nums = [] + mask = sys.maxint * 2 + 1 for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]: nums = [] - for o in [obj, hash(obj), -hash(obj)]: + for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]: rnd.seed(o) nums.append([rnd.random() for i in range(100)]) n1 = nums[0] diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py --- a/pypy/module/imp/importing.py +++ b/pypy/module/imp/importing.py @@ -16,6 +16,8 @@ from rpython.rlib.objectmodel import we_are_translated, specialize from pypy.module.sys.version import PYPY_VERSION +_WIN32 = sys.platform == 'win32' + SEARCH_ERROR = 0 PY_SOURCE = 1 PY_COMPILED = 2 @@ -27,12 +29,8 @@ # PY_CODERESOURCE = 8 IMP_HOOK = 9 -if sys.platform == 'win32': - SO = ".pyd" -else: - SO = ".so" +SO = '.pyd' if _WIN32 else '.so' DEFAULT_SOABI = 'pypy-%d%d' % PYPY_VERSION[:2] -CHECK_FOR_PYW = sys.platform == 'win32' @specialize.memo() def get_so_extension(space): @@ -64,7 +62,7 @@ return PY_SOURCE, ".py", "U" # on Windows, also check for a .pyw file - if CHECK_FOR_PYW: + if _WIN32: pyfile = filepart + ".pyw" if file_exists(pyfile): return PY_SOURCE, ".pyw", "U" diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -119,6 +119,12 @@ """) def test_array_of_floats(self): + try: + from __pypy__ import jit_backend_features + if 'singlefloats' not in jit_backend_features: + py.test.skip("test requres singlefloats support from the JIT backend") + except ImportError: + pass def main(): from array import array img = array('f', [21.5]*1000) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -230,6 +230,17 @@ pt = POINT(y=2, x=1) assert (pt.x, pt.y) == (1, 2) + def test_subclass_initializer(self): + class POINT(Structure): + _fields_ = [("x", c_int), ("y", c_int)] + + class POSITION(POINT): + # A subclass without _fields_ + pass + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) + + def test_invalid_field_types(self): class POINT(Structure): pass @@ -538,6 +549,7 @@ raises(AttributeError, setattr, X, "_fields_", []) Y.__fields__ = [] + class TestPatologicalCases(BaseCTypesTestChecker): def test_structure_overloading_getattr(self): class X(Structure): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -39,12 +39,10 @@ def unicode_w(w_self, space): # Use the default encoding. - from pypy.objspace.std.unicodetype import unicode_from_string, \ - decode_object + from pypy.objspace.std.unicodetype import (unicode_from_string, + decode_object, _get_encoding_and_errors) w_defaultencoding = space.call_function(space.sys.get( 'getdefaultencoding')) - from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \ - unicode_from_string, decode_object encoding, errors = _get_encoding_and_errors(space, w_defaultencoding, space.w_None) if encoding is None and errors is None: @@ -236,7 +234,7 @@ def str_title__String(space, w_self): input = w_self._value builder = StringBuilder(len(input)) - prev_letter=' ' + prev_letter = ' ' for pos in range(len(input)): ch = input[pos] @@ -434,7 +432,7 @@ space.wrap("rjust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self = d * fillchar + u_self @@ -450,7 +448,7 @@ space.wrap("ljust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self += d * fillchar @@ -471,12 +469,12 @@ return space.newbool(self.find(sub) >= 0) def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.find(w_sub._value, start, end) return space.wrap(res) def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.rfind(w_sub._value, start, end) return space.wrap(res) @@ -511,7 +509,7 @@ def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.find(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -521,7 +519,7 @@ def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.rfind(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -728,7 +726,7 @@ while 1: #no sophisticated linebreak support now, '\r' just for passing adapted CPython test if u_token[offset-1] == "\n" or u_token[offset-1] == "\r": - break; + break distance += 1 offset -= 1 if offset == 0: @@ -738,7 +736,7 @@ #print '' % (offset, distance, u_tabsize, u_token) distance = (u_tabsize-distance) % u_tabsize if distance == 0: - distance=u_tabsize + distance = u_tabsize return distance @@ -760,14 +758,14 @@ for token in split: #print "%d#%d -%s-" % (_tabindent(oldtoken,u_tabsize), u_tabsize, token) - u_expanded += " " * _tabindent(oldtoken,u_tabsize) + token + u_expanded += " " * _tabindent(oldtoken, u_tabsize) + token oldtoken = token return wrapstr(space, u_expanded) def str_splitlines__String_ANY(space, w_self, w_keepends): - u_keepends = space.int_w(w_keepends) # truth value, but type checked + u_keepends = space.int_w(w_keepends) # truth value, but type checked data = w_self._value selflen = len(data) strs_w = [] @@ -876,7 +874,6 @@ return wrapchar(space, str[ival]) def getitem__String_Slice(space, w_str, w_slice): - w = space.wrap s = w_str._value length = len(s) start, stop, step, sl = w_slice.indices4(space, length) diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -948,6 +948,9 @@ def test_setitem_slice_performance(self): # because of a complexity bug, this used to take forever on a # translated pypy. On CPython2.6 -A, it takes around 5 seconds. + import platform + if platform.machine().startswith('arm'): + skip("consumes too much memory for most ARM machines") if self.runappdirect: count = 16*1024*1024 else: diff --git a/pypy/pytest-A.py b/pypy/pytest-A.py --- a/pypy/pytest-A.py +++ b/pypy/pytest-A.py @@ -6,6 +6,7 @@ 'interpreter/pyparser/test', 'interpreter/test', 'interpreter/test2', + 'module/test_lib_pypy', 'objspace/std/test', ], } diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -4,7 +4,7 @@ parse_log_counts) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys -from rpython.jit.backend.detect_cpu import autodetect_main_model +from rpython.jit.backend.detect_cpu import autodetect def parse(input, **kwds): return SimpleParser.parse_from_input(input, **kwds) @@ -189,7 +189,7 @@ assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" dump_start = 0x7f3b0b2e63d5 @@ -218,7 +218,7 @@ assert 'jmp' in loop.operations[-1].asm def test_parsing_arm_assembler(): - if not autodetect_main_model() == 'arm': + if not autodetect().startswith('arm'): py.test.skip('ARM only test') backend_dump = "F04F2DE9108B2DED2CD04DE20DB0A0E17CC302E3DFC040E300409CE5085084E2086000E3006084E504B084E500508CE508D04BE20000A0E10000A0E1B0A10DE30EA044E300A09AE501A08AE2B0910DE30E9044E300A089E5C0910DE30E9044E3009099E5019089E2C0A10DE30EA044E300908AE5010050E1700020E124A092E500C08AE00C90DCE5288000E3090058E10180A0030080A013297000E3090057E10170A0030070A013077088E1200059E30180A0030080A013099049E2050059E30190A0330090A023099088E1000059E30190A0130090A003099087E1000059E3700020E1010080E204200BE5D0210DE30E2044E3002092E5012082E2D0910DE30E9044E3002089E5010050E1700020E100C08AE00C90DCE5282000E3090052E10120A0030020A013297000E3090057E10170A0030070A013077082E1200059E30120A0030020A013099049E2050059E30190A0330090A023099082E1000059E30190A0130090A003099087E1000059E3700020E1010080E20D005BE10FF0A0A1700020E1D8FFFFEA68C100E301C04BE33CFF2FE105010803560000000000000068C100E301C04BE33CFF2FE105010803570000000000000068C100E301C04BE33CFF2FE105014003580000000000000068C100E301C04BE33CFF2FE1050140035900000000000000" dump_start = int(-0x4ffee930) @@ -272,7 +272,7 @@ def test_import_log(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) @@ -281,7 +281,7 @@ assert 'jge' in loops[0].operations[3].asm def test_import_log_2(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) diff --git a/rpython/jit/backend/arm/test/test_fficall.py b/rpython/jit/backend/arm/test/test_fficall.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/test/test_fficall.py @@ -0,0 +1,23 @@ +import py +from rpython.jit.metainterp.test import test_fficall +from rpython.jit.backend.arm.test.support import JitARMMixin + +class TestFfiCall(JitARMMixin, test_fficall.FfiCallTests): + # for the individual tests see + # ====> ../../../metainterp/test/test_fficall.py + + def _add_libffi_types_to_ll2types_maybe(self): + # this is needed by test_guard_not_forced_fails, because it produces a + # loop which reads the value of types.* in a variable, then a guard + # fail and we switch to blackhole: the problem is that at this point + # the blackhole interp has a real integer, but it needs to convert it + # back to a lltype pointer (which is handled by ll2ctypes, deeply in + # the logic). The workaround is to teach ll2ctypes in advance which + # are the addresses of the various types.* structures. + # Try to comment this code out and run the test to see how it fails :) + from rpython.rtyper.lltypesystem import rffi, lltype, ll2ctypes + from rpython.rlib.jit_libffi import types + for key, value in types.__dict__.iteritems(): + if isinstance(value, lltype._ptr): + addr = rffi.cast(lltype.Signed, value) + ll2ctypes._int2obj[addr] = value diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -10,31 +10,31 @@ pass -def detect_main_model_and_size_from_platform(): +MODEL_X86 = 'x86' +MODEL_X86_NO_SSE2 = 'x86-without-sse2' +MODEL_X86_64 = 'x86-64' +MODEL_ARM = 'arm' +MODEL_PPC_64 = 'ppc-64' +# don't use '_' in the model strings; they are replaced by '-' + + +def detect_model_from_c_compiler(): # based on http://sourceforge.net/p/predef/wiki/Architectures/ mapping = { - ('x86', '64'): [ - '__amd64__', '__amd64', '__x86_64__', '__x86_64', # AMD64 - ], - ('arm', '32'): ['__arm__', '__thumb__'], - ('x86', '32'): ['i386', '__i386', '__i386__', '__i686__',], - ('ppc', '64'): ['__powerpc64__'], + MODEL_X86_64: ['__amd64__', '__amd64', '__x86_64__', '__x86_64'], + MODEL_ARM: ['__arm__', '__thumb__'], + MODEL_X86: ['i386', '__i386', '__i386__', '__i686__'], + MODEL_PPC_64: ['__powerpc64__'], } for k, v in mapping.iteritems(): for macro in v: if not getdefined(macro, ''): continue - return '_'.join(k) + return k raise ProcessorAutodetectError, "Cannot detect processor using compiler macros" -def detect_main_model_from_platform(): - return detect_main_model_and_size_from_platform()[0] - - -def autodetect_main_model(): - if not is_host_build(): - return detect_main_model_from_platform() +def detect_model_from_host_platform(): mach = None try: import platform @@ -44,67 +44,64 @@ if not mach: platform = sys.platform.lower() if platform.startswith('win'): # assume an Intel Windows - return 'x86' + return MODEL_X86 # assume we have 'uname' mach = os.popen('uname -m', 'r').read().strip() if not mach: raise ProcessorAutodetectError, "cannot run 'uname -m'" - try: - return {'i386': 'x86', - 'i486': 'x86', - 'i586': 'x86', - 'i686': 'x86', - 'i86pc': 'x86', # Solaris/Intel - 'x86': 'x86', # Apple - 'Power Macintosh': 'ppc', - 'x86_64': 'x86', - 'amd64': 'x86', # freebsd - 'AMD64': 'x86', # win64 - 'armv7l': 'arm', - 'armv6l': 'arm', - }[mach] - except KeyError: - return mach + # + result ={'i386': MODEL_X86, + 'i486': MODEL_X86, + 'i586': MODEL_X86, + 'i686': MODEL_X86, + 'i86pc': MODEL_X86, # Solaris/Intel + 'x86': MODEL_X86, # Apple + 'Power Macintosh': MODEL_PPC_64, + 'x86_64': MODEL_X86, + 'amd64': MODEL_X86, # freebsd + 'AMD64': MODEL_X86, # win64 + 'armv7l': MODEL_ARM, + 'armv6l': MODEL_ARM, + }[mach] + # + if result.startswith('x86'): + if sys.maxint == 2**63-1: + result = MODEL_X86_64 + else: + assert sys.maxint == 2**31-1 + from rpython.jit.backend.x86.detect_sse2 import detect_sse2 + if detect_sse2(): + result = MODEL_X86 + else: + result = MODEL_X86_NO_SSE2 + # + if result.startswith('arm'): + from rpython.jit.backend.arm.detect import detect_float + assert detect_float(), 'the JIT-compiler requires a vfp unit' + # + return result -def autodetect_main_model_and_size(): - if not is_host_build(): - return detect_main_model_and_size_from_platform() - model = autodetect_main_model() - if sys.maxint == 2**31-1: - model += '_32' - elif sys.maxint == 2**63-1: - model += '_64' - else: - raise AssertionError, "bad value for sys.maxint" - return model def autodetect(): - model = autodetect_main_model() - if sys.maxint == 2**63-1: - model += '_64' + if not is_host_build(): + return detect_model_from_c_compiler() else: - assert sys.maxint == 2**31-1 - if model == 'x86': - from rpython.jit.backend.x86.detect_sse2 import detect_sse2 - if not detect_sse2(): - model = 'x86-without-sse2' - if model.startswith('arm'): - from rpython.jit.backend.arm.detect import detect_hardfloat, detect_float - assert detect_float(), 'the JIT-compiler requires a vfp unit' - return model + return detect_model_from_host_platform() + def getcpuclassname(backend_name="auto"): if backend_name == "auto": backend_name = autodetect() - if backend_name == 'x86': + backend_name = backend_name.replace('_', '-') + if backend_name == MODEL_X86: return "rpython.jit.backend.x86.runner", "CPU" - elif backend_name == 'x86-without-sse2': + elif backend_name == MODEL_X86_NO_SSE2: return "rpython.jit.backend.x86.runner", "CPU386_NO_SSE2" - elif backend_name == 'x86_64': + elif backend_name == MODEL_X86_64: return "rpython.jit.backend.x86.runner", "CPU_X86_64" - elif backend_name == 'cli': - return "rpython.jit.backend.cli.runner", "CliCPU" - elif backend_name.startswith('arm'): + #elif backend_name == 'cli': + # return "rpython.jit.backend.cli.runner", "CliCPU" + elif backend_name == MODEL_ARM: return "rpython.jit.backend.arm.runner", "CPU_ARM" else: raise ProcessorAutodetectError, ( @@ -115,6 +112,22 @@ mod = __import__(modname, {}, {}, clsname) return getattr(mod, clsname) + +def getcpufeatures(backend_name="auto"): + """NOT_RPYTHON""" + cpucls = getcpuclass(backend_name) + return [attr[len('supports_'):] for attr in dir(cpucls) + if attr.startswith('supports_') + and getattr(cpucls, attr)] + if __name__ == '__main__': - print autodetect() - print getcpuclassname() + if len(sys.argv) > 1: + name = sys.argv[1] + x = name + else: + name = 'auto' + x = autodetect() + x = (x, getcpuclassname(name), getcpufeatures(name)) + print 'autodetect: ', x[0] + print 'getcpuclassname:', x[1] + print 'getcpufeatures: ', x[2] diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -18,7 +18,7 @@ from rpython.jit.codewriter import heaptracker, longlong from rpython.rlib import longlong2float from rpython.rlib.rarithmetic import intmask, is_valid_int -from rpython.jit.backend.detect_cpu import autodetect_main_model_and_size +from rpython.jit.backend.detect_cpu import autodetect from rpython.jit.backend.llsupport import jitframe @@ -3539,7 +3539,7 @@ looptoken) self.cpu.assembler.set_debug(True) # always on untranslated assert info.asmlen != 0 - cpuname = autodetect_main_model_and_size() + cpuname = autodetect() # XXX we have to check the precise assembler, otherwise # we don't quite know if borders are correct diff --git a/rpython/jit/backend/test/test_detect_cpu.py b/rpython/jit/backend/test/test_detect_cpu.py --- a/rpython/jit/backend/test/test_detect_cpu.py +++ b/rpython/jit/backend/test/test_detect_cpu.py @@ -28,6 +28,13 @@ assert issubclass(cpu, AbstractCPU) -def test_detect_main_model_and_size_from_platform(): - info = autodetect_main_model_and_size() - assert detect_main_model_and_size_from_platform() == info +def test_detect_model_from_c_compiler(): + info1 = detect_model_from_host_platform() + info2 = detect_model_from_c_compiler() + assert info1 == info2 + +def test_getcpufeatures(): + features = getcpufeatures() + assert isinstance(features, list) + for x in features: + assert x in ['floats', 'singlefloats', 'longlong'] diff --git a/rpython/jit/backend/tool/viewcode.py b/rpython/jit/backend/tool/viewcode.py --- a/rpython/jit/backend/tool/viewcode.py +++ b/rpython/jit/backend/tool/viewcode.py @@ -50,9 +50,12 @@ def machine_code_dump(data, originaddr, backend_name, label_list=None): objdump_backend_option = { 'x86': 'i386', + 'x86-without-sse2': 'i386', 'x86_32': 'i386', 'x86_64': 'x86-64', + 'x86-64': 'x86-64', 'i386': 'i386', + 'arm': 'arm', 'arm_32': 'arm', } cmd = find_objdump() diff --git a/rpython/jit/backend/x86/test/conftest.py b/rpython/jit/backend/x86/test/conftest.py --- a/rpython/jit/backend/x86/test/conftest.py +++ b/rpython/jit/backend/x86/test/conftest.py @@ -3,7 +3,7 @@ cpu = detect_cpu.autodetect() def pytest_runtest_setup(item): - if cpu not in ('x86', 'x86_64'): + if not cpu.startswith('x86'): py.test.skip("x86/x86_64 tests skipped: cpu is %r" % (cpu,)) if cpu == 'x86_64': if os.name == "nt": diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -1751,7 +1751,7 @@ def rewrite_op_jit_ffi_save_result(self, op): kind = op.args[0].value - assert kind in ('int', 'float') + assert kind in ('int', 'float', 'longlong', 'singlefloat') return SpaceOperation('libffi_save_result_%s' % kind, op.args[1:], None) def rewrite_op_jit_force_virtual(self, op): diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -1351,24 +1351,39 @@ def bhimpl_ll_read_timestamp(): return read_timestamp() - @arguments("cpu", "i", "i", "i") - def bhimpl_libffi_save_result_int(self, cif_description, exchange_buffer, result): - ARRAY = lltype.Ptr(rffi.CArray(lltype.Signed)) - cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) - exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP) + def _libffi_save_result(self, cif_description, exchange_buffer, result): + ARRAY = lltype.Ptr(rffi.CArray(lltype.typeOf(result))) + cast_int_to_ptr = self.cpu.cast_int_to_ptr + cif_description = cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) + exchange_buffer = cast_int_to_ptr(exchange_buffer, rffi.CCHARP) # data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result) rffi.cast(ARRAY, data_out)[0] = result + _libffi_save_result._annspecialcase_ = 'specialize:argtype(3)' - @arguments("cpu", "i", "i", "f") - def bhimpl_libffi_save_result_float(self, cif_description, exchange_buffer, result): + @arguments("self", "i", "i", "i") + def bhimpl_libffi_save_result_int(self, cif_description, + exchange_buffer, result): + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "f") + def bhimpl_libffi_save_result_float(self, cif_description, + exchange_buffer, result): result = longlong.getrealfloat(result) - ARRAY = lltype.Ptr(rffi.CArray(lltype.Float)) - cif_description = self.cast_int_to_ptr(cif_description, CIF_DESCRIPTION_P) - exchange_buffer = self.cast_int_to_ptr(exchange_buffer, rffi.CCHARP) - # - data_out = rffi.ptradd(exchange_buffer, cif_description.exchange_result) - rffi.cast(ARRAY, data_out)[0] = result + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "f") + def bhimpl_libffi_save_result_longlong(self, cif_description, + exchange_buffer, result): + # 32-bit only: 'result' is here a LongLong + assert longlong.is_longlong(lltype.typeOf(result)) + self._libffi_save_result(cif_description, exchange_buffer, result) + + @arguments("self", "i", "i", "i") + def bhimpl_libffi_save_result_singlefloat(self, cif_description, + exchange_buffer, result): + result = longlong.int2singlefloat(result) + self._libffi_save_result(cif_description, exchange_buffer, result) # ---------- diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1190,8 +1190,8 @@ return self.metainterp.execute_and_record(rop.READ_TIMESTAMP, None) @arguments("box", "box", "box") - def opimpl_libffi_save_result_int(self, box_cif_description, box_exchange_buffer, - box_result): + def _opimpl_libffi_save_result(self, box_cif_description, + box_exchange_buffer, box_result): from rpython.rtyper.lltypesystem import llmemory from rpython.rlib.jit_libffi import CIF_DESCRIPTION_P from rpython.jit.backend.llsupport.ffisupport import get_arg_descr @@ -1208,10 +1208,14 @@ assert ofs % itemsize == 0 # alignment check (result) self.metainterp.history.record(rop.SETARRAYITEM_RAW, [box_exchange_buffer, - ConstInt(ofs // itemsize), box_result], + ConstInt(ofs // itemsize), + box_result], None, descr) - opimpl_libffi_save_result_float = opimpl_libffi_save_result_int + opimpl_libffi_save_result_int = _opimpl_libffi_save_result + opimpl_libffi_save_result_float = _opimpl_libffi_save_result + opimpl_libffi_save_result_longlong = _opimpl_libffi_save_result + opimpl_libffi_save_result_singlefloat = _opimpl_libffi_save_result # ------------------------------ diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -14,7 +14,10 @@ def _get_jitcodes(testself, CPUClass, func, values, type_system, - supports_longlong=False, translationoptions={}, **kwds): + supports_floats=True, + supports_longlong=False, + supports_singlefloats=False, + translationoptions={}, **kwds): from rpython.jit.codewriter import support class FakeJitCell(object): @@ -67,9 +70,16 @@ cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()]) cw.debug = True testself.cw = cw + if supports_floats and not cpu.supports_floats: + py.test.skip("this test requires supports_floats=True") + if supports_longlong and not cpu.supports_longlong: + py.test.skip("this test requires supports_longlong=True") + if supports_singlefloats and not cpu.supports_singlefloats: + py.test.skip("this test requires supports_singlefloats=True") policy = JitPolicy() - policy.set_supports_floats(True) + policy.set_supports_floats(supports_floats) policy.set_supports_longlong(supports_longlong) + policy.set_supports_singlefloats(supports_singlefloats) graphs = cw.find_all_graphs(policy) if kwds.get("backendopt"): backend_optimizations(rtyper.annotator.translator, graphs=graphs) diff --git a/rpython/jit/metainterp/test/test_fficall.py b/rpython/jit/metainterp/test/test_fficall.py --- a/rpython/jit/metainterp/test/test_fficall.py +++ b/rpython/jit/metainterp/test/test_fficall.py @@ -5,13 +5,13 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.annlowlevel import llhelper from rpython.jit.metainterp.test.support import LLJitMixin -from rpython.jit.codewriter.longlong import is_longlong +from rpython.jit.codewriter.longlong import is_longlong, is_64_bit from rpython.rlib import jit from rpython.rlib import jit_libffi from rpython.rlib.jit_libffi import (types, CIF_DESCRIPTION, FFI_TYPE_PP, jit_ffi_call, jit_ffi_save_result) from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.rarithmetic import intmask, r_longlong +from rpython.rlib.rarithmetic import intmask, r_longlong, r_singlefloat from rpython.rlib.longlong2float import float2longlong def get_description(atypes, rtype): @@ -45,7 +45,12 @@ class FfiCallTests(object): - def _run(self, atypes, rtype, avalues, rvalue, expected_call_release_gil=1): + def _run(self, atypes, rtype, avalues, rvalue, + expected_call_release_gil=1, + supports_floats=True, + supports_longlong=True, + supports_singlefloats=True): + cif_description = get_description(atypes, rtype) def verify(*args): @@ -67,7 +72,11 @@ for avalue in unroll_avalues: TYPE = rffi.CArray(lltype.typeOf(avalue)) data = rffi.ptradd(exchange_buffer, ofs) - assert rffi.cast(lltype.Ptr(TYPE), data)[0] == avalue + got = rffi.cast(lltype.Ptr(TYPE), data)[0] + if lltype.typeOf(avalue) is lltype.SingleFloat: + got = float(got) + avalue = float(avalue) + assert got == avalue ofs += 16 if rvalue is not None: write_rvalue = rvalue @@ -96,17 +105,30 @@ data = rffi.ptradd(exbuf, ofs) res = rffi.cast(lltype.Ptr(TYPE), data)[0] lltype.free(exbuf, flavor='raw') + if lltype.typeOf(res) is lltype.SingleFloat: + res = float(res) return res + def matching_result(res, rvalue): + if rvalue is None: + return res == 654321 + if isinstance(rvalue, r_singlefloat): + rvalue = float(rvalue) + return res == rvalue + with FakeFFI(fake_call_impl_any): res = f() - assert res == rvalue or (res, rvalue) == (654321, None) - res = self.interp_operations(f, []) + assert matching_result(res, rvalue) + res = self.interp_operations(f, [], + supports_floats = supports_floats, + supports_longlong = supports_longlong, + supports_singlefloats = supports_singlefloats) if is_longlong(FUNC.RESULT): - # longlongs are passed around as floats inside the JIT, we - # need to convert it back before checking the value + # longlongs are returned as floats, but that's just + # an inconvenience of interp_operations(). Normally both + # longlong and floats are passed around as longlongs. res = float2longlong(res) - assert res == rvalue or (res, rvalue) == (654321, None) + assert matching_result(res, rvalue) self.check_operations_history(call_may_force=0, call_release_gil=expected_call_release_gil) @@ -119,14 +141,24 @@ [-123456*j for j in range(i)], -42434445) - def test_simple_call_float(self): - self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2) + def test_simple_call_float(self, **kwds): + self._run([types.double] * 2, types.double, [45.6, 78.9], -4.2, **kwds) - def test_simple_call_longlong(self): + def test_simple_call_longlong(self, **kwds): maxint32 = 2147483647 a = r_longlong(maxint32) + 1 b = r_longlong(maxint32) + 2 - self._run([types.slonglong] * 2, types.slonglong, [a, b], a) + self._run([types.slonglong] * 2, types.slonglong, [a, b], a, **kwds) + + def test_simple_call_singlefloat_args(self): + self._run([types.float] * 2, types.double, + [r_singlefloat(10.5), r_singlefloat(31.5)], + -4.5) + + def test_simple_call_singlefloat(self, **kwds): + self._run([types.float] * 2, types.float, + [r_singlefloat(10.5), r_singlefloat(31.5)], + r_singlefloat(-4.5), **kwds) def test_simple_call_longdouble(self): # longdouble is not supported, so we expect NOT to generate a call_release_gil @@ -266,3 +298,20 @@ assert res == math.sin(1.23) lltype.free(atypes, flavor='raw') + + def test_simple_call_float_unsupported(self): + self.test_simple_call_float(supports_floats=False, + expected_call_release_gil=0) + + def test_simple_call_longlong_unsupported(self): + self.test_simple_call_longlong(supports_longlong=False, + expected_call_release_gil=is_64_bit) + + def test_simple_call_singlefloat_unsupported(self): + self.test_simple_call_singlefloat(supports_singlefloats=False, + expected_call_release_gil=0) + + def test_simple_call_float_even_if_other_unsupported(self): + self.test_simple_call_float(supports_longlong=False, + supports_singlefloats=False) + # this is the default: expected_call_release_gil=1 diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py --- a/rpython/memory/gctransform/transform.py +++ b/rpython/memory/gctransform/transform.py @@ -281,11 +281,11 @@ def finish_helpers(self, backendopt=True): if self.translator is not None: self.mixlevelannotator.finish_annotate() - self.finished_helpers = True if self.translator is not None: self.mixlevelannotator.finish_rtype() if backendopt: self.mixlevelannotator.backend_optimize() + self.finished_helpers = True # Make sure that the database also sees all finalizers now. # It is likely that the finalizers need special support there newgcdependencies = self.ll_finalizers_ptrs diff --git a/rpython/rlib/jit_libffi.py b/rpython/rlib/jit_libffi.py --- a/rpython/rlib/jit_libffi.py +++ b/rpython/rlib/jit_libffi.py @@ -2,6 +2,7 @@ from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.extregistry import ExtRegistryEntry from rpython.rlib import clibffi, jit +from rpython.rlib.rarithmetic import r_longlong, r_singlefloat from rpython.rlib.nonconst import NonConstant @@ -107,12 +108,14 @@ reskind = types.getkind(cif_description.rtype) if reskind == 'v': jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer) - elif reskind == 'f' or reskind == 'L': # L is for longlongs, on 32bit - result = jit_ffi_call_impl_float(cif_description, func_addr, exchange_buffer) - jit_ffi_save_result('float', cif_description, exchange_buffer, result) elif reskind == 'i' or reskind == 'u': - result = jit_ffi_call_impl_int(cif_description, func_addr, exchange_buffer) - jit_ffi_save_result('int', cif_description, exchange_buffer, result) + _do_ffi_call_int(cif_description, func_addr, exchange_buffer) + elif reskind == 'f': + _do_ffi_call_float(cif_description, func_addr, exchange_buffer) + elif reskind == 'L': # L is for longlongs, on 32bit + _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer) + elif reskind == 'S': # SingleFloat + _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer) else: # the result kind is not supported: we disable the jit_ffi_call # optimization by calling directly jit_ffi_call_impl_any, so the JIT @@ -123,6 +126,30 @@ jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) +def _do_ffi_call_int(cif_description, func_addr, exchange_buffer): + result = jit_ffi_call_impl_int(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('int', cif_description, exchange_buffer, result) + +def _do_ffi_call_float(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support floats + result = jit_ffi_call_impl_float(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('float', cif_description, exchange_buffer, result) + +def _do_ffi_call_longlong(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support longlongs + result = jit_ffi_call_impl_longlong(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('longlong', cif_description, exchange_buffer, result) + +def _do_ffi_call_singlefloat(cif_description, func_addr, exchange_buffer): + # a separate function in case the backend doesn't support singlefloats + result = jit_ffi_call_impl_singlefloat(cif_description, func_addr, + exchange_buffer) + jit_ffi_save_result('singlefloat', cif_description, exchange_buffer,result) + + # we must return a NonConstant else we get the constant -1 as the result of # the flowgraph, and the codewriter does not produce a box for the # result. Note that when not-jitted, the result is unused, but when jitted the @@ -139,6 +166,16 @@ return NonConstant(-1.0) @jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") +def jit_ffi_call_impl_longlong(cif_description, func_addr, exchange_buffer): + jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) + return r_longlong(-1) + + at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") +def jit_ffi_call_impl_singlefloat(cif_description, func_addr, exchange_buffer): + jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) + return r_singlefloat(-1.0) + + at jit.oopspec("libffi_call(cif_description,func_addr,exchange_buffer)") def jit_ffi_call_impl_void(cif_description, func_addr, exchange_buffer): jit_ffi_call_impl_any(cif_description, func_addr, exchange_buffer) return None @@ -175,7 +212,7 @@ def compute_result_annotation(self, kind_s, *args_s): from rpython.annotator import model as annmodel assert isinstance(kind_s, annmodel.SomeString) - assert kind_s.const in ('int', 'float') + assert kind_s.const in ('int', 'float', 'longlong', 'singlefloat') def specialize_call(self, hop): hop.exception_cannot_occur() diff --git a/rpython/translator/c/gcc/test/conftest.py b/rpython/translator/c/gcc/test/conftest.py --- a/rpython/translator/c/gcc/test/conftest.py +++ b/rpython/translator/c/gcc/test/conftest.py @@ -2,5 +2,5 @@ from rpython.jit.backend import detect_cpu cpu = detect_cpu.autodetect() def pytest_runtest_setup(item): - if cpu not in ('x86', 'x86_64'): + if not cpu.startswith('x86'): py.test.skip("x86 directory skipped: cpu is %r" % (cpu,)) diff --git a/testrunner/runner.py b/testrunner/runner.py --- a/testrunner/runner.py +++ b/testrunner/runner.py @@ -329,7 +329,7 @@ self.collect_one_testdir(testdirs, reldir, [self.reltoroot(t) for t in entries if self.is_test_py_file(t)]) - return + break for p1 in entries: if p1.check(dir=1, link=0): From noreply at buildbot.pypy.org Tue May 7 10:25:51 2013 From: noreply at buildbot.pypy.org (bivab) Date: Tue, 7 May 2013 10:25:51 +0200 (CEST) Subject: [pypy-commit] buildbot default: assing new buildslaves to builders Message-ID: <20130507082551.829471C030B@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r814:d3b4e913c057 Date: 2013-05-07 10:24 +0200 http://bitbucket.org/pypy/buildbot/changeset/d3b4e913c057/ Log: assing new buildslaves to builders diff --git a/bot2/pypybuildbot/arm_master.py b/bot2/pypybuildbot/arm_master.py --- a/bot2/pypybuildbot/arm_master.py +++ b/bot2/pypybuildbot/arm_master.py @@ -111,7 +111,7 @@ BUILDLINUXARMHF_RASPBIAN, # on hhu-cross-raspbianhf, uses 1 core JITBACKENDONLYLINUXARMEL, # on hhu-imx.53 - JITBACKENDONLYLINUXARMHF, # on hhu-raspberry-pi + JITBACKENDONLYLINUXARMHF, JITBACKENDONLYLINUXARMHF_v7, # on cubieboard-bob ], branch=None, hour=0, minute=0), @@ -123,12 +123,12 @@ JITLINUXARM, # triggered by BUILDJITLINUXARM, on hhu-beagleboard ]), Triggerable("APPLVLLINUXARMHF_RASPBIAN_scheduler", [ - APPLVLLINUXARMHF_RASPBIAN, # triggered by BUILDLINUXARMHF_RASPBIAN, on hhu-raspberry-pi + APPLVLLINUXARMHF_RASPBIAN, # triggered by BUILDLINUXARMHF_RASPBIAN APPLVLLINUXARMHF_v7, # triggered by BUILDLINUXARMHF_RASPBIAN, on cubieboard-bob ]), Triggerable("JITLINUXARMHF_RASPBIAN_scheduler", [ - JITLINUXARMHF_RASPBIAN, # triggered by BUILDJITLINUXARMHF_RASPBIAN, on hhu-raspberry-pi + JITLINUXARMHF_RASPBIAN, # triggered by BUILDJITLINUXARMHF_RASPBIAN JITLINUXARMHF_v7, # triggered by BUILDJITLINUXARMHF_RASPBIAN, on cubieboard-bob ]), ] @@ -147,7 +147,7 @@ # armhf ## armv6 {"name": JITBACKENDONLYLINUXARMHF, - "slavenames": ['hhu-raspberry-pi'], + "slavenames": ['hhu-raspberry-pi', 'hhu-pypy-pi', 'hhu-pypy-pi2'], "builddir": JITBACKENDONLYLINUXARMHF, "factory": pypyJitBackendOnlyOwnTestFactoryARM, "category": 'linux-armhf', @@ -179,14 +179,14 @@ }, ## armv6 hardfloat {"name": APPLVLLINUXARMHF_RASPBIAN, - "slavenames": ["hhu-raspberry-pi"], + "slavenames": ['hhu-raspberry-pi', 'hhu-pypy-pi', 'hhu-pypy-pi2'], "builddir": APPLVLLINUXARMHF_RASPBIAN, "factory": pypyARMHF_RASPBIAN_TranslatedAppLevelTestFactory, "category": "linux-armhf", "locks": [ARMBoardLock.access('counting')], }, {"name": JITLINUXARMHF_RASPBIAN, - "slavenames": ["hhu-raspberry-pi"], + "slavenames": ['hhu-raspberry-pi', 'hhu-pypy-pi', 'hhu-pypy-pi2'], 'builddir': JITLINUXARMHF_RASPBIAN, 'factory': pypyARMHF_RASPBIAN_JITTranslatedTestFactory, 'category': 'linux-armhf', From noreply at buildbot.pypy.org Tue May 7 10:25:52 2013 From: noreply at buildbot.pypy.org (bivab) Date: Tue, 7 May 2013 10:25:52 +0200 (CEST) Subject: [pypy-commit] buildbot default: merge heads Message-ID: <20130507082552.C81F01C1293@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r815:db292526bec2 Date: 2013-05-07 10:25 +0200 http://bitbucket.org/pypy/buildbot/changeset/db292526bec2/ Log: merge heads diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -207,7 +207,7 @@ APPLVLLINUX32, # on tannit32, uses 1 core APPLVLLINUX64, # on allegro64, uses 1 core # other platforms - MACOSX32, # on minime + #MACOSX32, # on minime JITWIN32, # on aurora JITFREEBSD764, # on headless JITFREEBSD864, # on ananke From noreply at buildbot.pypy.org Tue May 7 11:28:10 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 7 May 2013 11:28:10 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added is_closure_context to BlockContextShadow to fix some of our tests Message-ID: <20130507092810.379021C1293@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r379:cd9d6bc86103 Date: 2013-05-07 10:39 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/cd9d6bc86103/ Log: added is_closure_context to BlockContextShadow to fix some of our tests diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -811,6 +811,9 @@ # A blockcontext doesn't have any temps return 0 + def is_closure_context(self): + return True + def short_str(self, argcount): return 'BlockContext of %s (%s) [%d]' % ( self.w_method().get_identifier_string(), From noreply at buildbot.pypy.org Tue May 7 11:28:11 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 7 May 2013 11:28:11 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changed print_stack to return only the string, not the padding Message-ID: <20130507092811.4D48F1C12FE@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r380:7ea3d7cff34f Date: 2013-05-07 10:48 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/7ea3d7cff34f/ Log: changed print_stack to return only the string, not the padding diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -708,11 +708,17 @@ # ______________________________________________________________________ # Debugging printout - def print_stack(self): - padding = ret_str = '' - if self.s_sender() is not None: - padding, ret_str = self.s_sender().print_stack() - return padding + ' ', '%s\n%s%s' % (ret_str, padding, self.method_str()) + def print_stack(self, method=True): + def print_padded_stack(s_context, method): + padding = ret_str = '' + if s_context.s_sender() is not None: + padding, ret_str = print_padded_stack(s_context.s_sender(), method) + if method: + desc = s_context.method_str() + else: + desc = s_context.short_str(0) + return padding + ' ', '%s\n%s%s' % (ret_str, padding, desc) + return print_padded_stack(self, method)[1] class BlockContextShadow(ContextPartShadow): From noreply at buildbot.pypy.org Tue May 7 11:28:12 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 7 May 2013 11:28:12 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: STORE_STACKP-primitive: the check for a shadow is already done when calling store, so we can skip the test at this point... Message-ID: <20130507092812.7EFD41C1578@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r381:d87e8807dd80 Date: 2013-05-07 10:51 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/d87e8807dd80/ Log: STORE_STACKP-primitive: the check for a shadow is already done when calling store, so we can skip the test at this point... diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -487,11 +487,7 @@ assert stackp >= 0 if not isinstance(w_frame, model.W_PointersObject): raise PrimitiveFailedError - if w_frame.has_shadow(): - s_frame = w_frame.as_context_get_shadow(interp.space) - s_frame.store_stackpointer(stackp) - else: - w_frame.store(interp.space, constants.CTXPART_STACKP_INDEX, stackp) + w_frame.store(interp.space, constants.CTXPART_STACKP_INDEX, interp.space.wrap_int(stackp)) return w_frame @expose_primitive(SOME_INSTANCE, unwrap_spec=[object]) From noreply at buildbot.pypy.org Tue May 7 11:28:13 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 7 May 2013 11:28:13 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: removed skipped benchmark test in bootstrapped Message-ID: <20130507092813.98BB51C1293@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r382:aad908fe6500 Date: 2013-05-07 11:27 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/aad908fe6500/ Log: removed skipped benchmark test in bootstrapped changed test-sequence to make two tests green in test_miniimage added reset of interrupt counter to perform to avoid interrupting during tests diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -155,6 +155,8 @@ self.space, s_method, w_receiver, [], None) s_frame.push(w_receiver) s_frame.push_all(list(arguments_w)) + + self.interrupt_check_counter = constants.INTERRUPT_COUNTER_SIZE try: self.loop(s_frame.w_self()) except ReturnFromTopLevel, e: diff --git a/spyvm/test/test_bootstrappedimage.py b/spyvm/test/test_bootstrappedimage.py --- a/spyvm/test/test_bootstrappedimage.py +++ b/spyvm/test/test_bootstrappedimage.py @@ -50,13 +50,3 @@ def test_all_pointers_are_valid(): tools.test_all_pointers_are_valid() tools.test_lookup_abs_in_integer() - -def test_tinyBenchmarks(): - py.test.skip("Waste of time, because it doesn't assert anything.") - # we can't find PCSystem, because Smalltalkdict is nil... - import time - t0 = time.time() - sends = perform(w(5), 'benchFib') - t1 = time.time() - t = t1 - t0 - print str(tools.space.unwrap_int(sends)/t) + " sends per second" diff --git a/spyvm/test/test_miniimage.py b/spyvm/test/test_miniimage.py --- a/spyvm/test/test_miniimage.py +++ b/spyvm/test/test_miniimage.py @@ -301,20 +301,6 @@ perform(w(10).getclass(space), "compile:classified:notifying:", w(sourcecode), w('pypy'), w(None)) assert perform(w(10), "fib").is_same_object(w(89)) -def test_primitive_perform_with_args(): - from spyvm.test.test_primitives import prim - from spyvm import primitives - w_o = space.wrap_list([1, 2, 3]) - w_methoddict = w_o.shadow_of_my_class(space)._s_superclass._s_superclass.w_methoddict() - w_methoddict.as_methoddict_get_shadow(space).sync_cache() - selectors_w = w_methoddict._shadow.methoddict.keys() - w_sel = None - for sel in selectors_w: - if sel.as_string() == 'size': - w_sel = sel - size = prim(primitives.PERFORM_WITH_ARGS, [w_o, w_sel, []]) - assert size.value == 3 - def test_create_new_symbol(): w_result = perform(w("someString"), "asSymbol") assert w_result is not None @@ -405,3 +391,18 @@ assert s_ctx.top().value == 2 interp.step(s_ctx) assert s_ctx.top().value == 3 + +def test_primitive_perform_with_args(): + # this test should be last, because importing test_primitives has some (unknown) side-effects + from spyvm.test.test_primitives import prim + from spyvm import primitives + w_o = space.wrap_list([1, 2, 3]) + w_methoddict = w_o.shadow_of_my_class(space)._s_superclass._s_superclass.w_methoddict() + w_methoddict.as_methoddict_get_shadow(space).sync_cache() + selectors_w = w_methoddict._shadow.methoddict.keys() + w_sel = None + for sel in selectors_w: + if sel.as_string() == 'size': + w_sel = sel + size = prim(primitives.PERFORM_WITH_ARGS, [w_o, w_sel, []]) + assert size.value == 3 From noreply at buildbot.pypy.org Tue May 7 11:42:31 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 7 May 2013 11:42:31 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added skip note to weak_pointers test to be green on server. the test is green locally, but not on the ci.. Message-ID: <20130507094231.87E321C0307@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r383:d41579b7c86c Date: 2013-05-07 11:42 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/d41579b7c86c/ Log: added skip note to weak_pointers test to be green on server. the test is green locally, but not on the ci.. diff --git a/spyvm/test/test_model.py b/spyvm/test/test_model.py --- a/spyvm/test/test_model.py +++ b/spyvm/test/test_model.py @@ -316,6 +316,7 @@ assert target.pixelbuffer[i] == 0xffffffff + at py.test.mark.skipif("socket.gethostname() == 'precise32'") def test_weak_pointers(): from spyvm.shadow import WEAK_POINTERS From noreply at buildbot.pypy.org Tue May 7 14:27:29 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 7 May 2013 14:27:29 +0200 (CEST) Subject: [pypy-commit] pypy default: Print the version of the host Message-ID: <20130507122729.D812E1C3007@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63895:656b4a44da7b Date: 2013-05-07 14:26 +0200 http://bitbucket.org/pypy/pypy/changeset/656b4a44da7b/ Log: Print the version of the host (if it's PyPy, it includes the hg checksum) diff --git a/rpython/translator/goal/translate.py b/rpython/translator/goal/translate.py --- a/rpython/translator/goal/translate.py +++ b/rpython/translator/goal/translate.py @@ -147,6 +147,10 @@ else: show_help(translateconfig, opt_parser, None, config) + # print the version of the host + # (if it's PyPy, it includes the hg checksum) + log.info(sys.version) + # apply the platform settings set_platform(config) From noreply at buildbot.pypy.org Tue May 7 14:28:30 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 7 May 2013 14:28:30 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the downloads Message-ID: <20130507122830.0C0421C3007@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r405:fea3e8d445d3 Date: 2013-05-07 14:28 +0200 http://bitbucket.org/pypy/pypy.org/changeset/fea3e8d445d3/ Log: update the downloads diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -50,8 +50,8 @@ as stable as the release, but they contain numerous bugfixes and performance improvements.

    Here are the binaries of the current release — PyPy 2.0 beta2 — (what's -new in PyPy 2.0 beta2?) for x86 Linux, Mac OS/X, Windows or ARM linux -(not available for 2.0 beta 2).

    +new in PyPy 2.0 beta2?) for x86 Linux, Mac OS/X, Windows. There is also +PyPy 2.0 alpha ARM for ARM.

    You can also find here the older 1.9 release.

    • Download
        @@ -85,7 +85,15 @@ installer vcredist_x86.exe.)
    -
    + +

    1.9

    • Linux binary (32bit)
    • @@ -212,6 +220,9 @@ 61c2d5873ee62823bcf35b2e7086644f pypy-2.0-beta2-linux.tar.bz2 f7ad21f79c8005b9c00c48e190ec662e pypy-2.0-beta2-osx64.tar.bz2 3b5250872a5e79034bb1a7c209f39391 pypy-2.0-beta2-win32.zip +b9c36b99296c85a590c3e480b05d5a13 pypy-2.0-alpha-arm-armel.tar.bz2 +2565ce68b4032eb306d998e722495694 pypy-2.0-alpha-arm-armhf.tar.bz2 +b39d98de75f4948bfd2d606a8263ac1f pypy-upstream_2.0~alpha+arm_armhf.deb 201d2cce2557e40c784473b471ee1b6b pypy-1.9-linux64.tar.bz2 1a08c88642434fc2e0e4256d351f48db pypy-1.9-linux.tar.bz2 aad9c4b7b827583e37fe8ae0f7cfe0ff pypy-1.9-osx64.tar.bz2 @@ -223,6 +234,9 @@ 591e661b091ed4849fdf5aab7e73393dea64016b pypy-2.0-beta2-linux.tar.bz2 ec3d80d7806b0689d9da70ca27c741b1d9cea250 pypy-2.0-beta2-osx64.tar.bz2 bb0604f32ba0e2af3c585a1af45dc887e0e95d34 pypy-2.0-beta2-win32.zip +dc09a293b85ab4f0032f6943815aaf5bbbceb645 pypy-2.0-alpha-arm-armel.tar.bz2 +0971c4b668bfd2fcd52aa35087aa995e03bd5842 pypy-2.0-alpha-arm-armhf.tar.bz2 +91910eb654ffbe0509bec2a7aeb460984acf8d82 pypy-upstream_2.0~alpha+arm_armhf.deb 51be6b7b802a5239a759e04ae9595082e17c4c70 pypy-1.9-linux64.tar.bz2 1bc5d2467039b954f9b7395b3ee1b8407ce1c057 pypy-1.9-linux.tar.bz2 825e15724419fbdb6fe215eeea044f9181883c90 pypy-1.9-osx64.tar.bz2 diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -13,8 +13,8 @@ performance improvements. Here are the binaries of the current release — **PyPy 2.0 beta2** — (`what's -new in PyPy 2.0 beta2?`_) for x86 Linux, Mac OS/X, Windows or ARM linux -(not available for 2.0 beta 2). +new in PyPy 2.0 beta2?`_) for x86 Linux, Mac OS/X, Windows. There is also +**PyPy 2.0 alpha ARM** for ARM. You can also find here the older 1.9 release. @@ -62,6 +62,17 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-beta2-win32.zip .. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582 +2.0 alpha ARM +------------- + +* `Linux binary (32bit, armel)`__ +* `Linux binary (32bit, armhf)`__ +* `Linux deb for raspbian (raspberry pi)`__ + +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-alpha-arm-armel.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-alpha-arm-armhf.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-upstream_2.0~alpha+arm_armhf.deb + 1.9 --- @@ -223,6 +234,9 @@ 61c2d5873ee62823bcf35b2e7086644f pypy-2.0-beta2-linux.tar.bz2 f7ad21f79c8005b9c00c48e190ec662e pypy-2.0-beta2-osx64.tar.bz2 3b5250872a5e79034bb1a7c209f39391 pypy-2.0-beta2-win32.zip + b9c36b99296c85a590c3e480b05d5a13 pypy-2.0-alpha-arm-armel.tar.bz2 + 2565ce68b4032eb306d998e722495694 pypy-2.0-alpha-arm-armhf.tar.bz2 + b39d98de75f4948bfd2d606a8263ac1f pypy-upstream_2.0~alpha+arm_armhf.deb 201d2cce2557e40c784473b471ee1b6b pypy-1.9-linux64.tar.bz2 1a08c88642434fc2e0e4256d351f48db pypy-1.9-linux.tar.bz2 aad9c4b7b827583e37fe8ae0f7cfe0ff pypy-1.9-osx64.tar.bz2 @@ -235,6 +249,9 @@ 591e661b091ed4849fdf5aab7e73393dea64016b pypy-2.0-beta2-linux.tar.bz2 ec3d80d7806b0689d9da70ca27c741b1d9cea250 pypy-2.0-beta2-osx64.tar.bz2 bb0604f32ba0e2af3c585a1af45dc887e0e95d34 pypy-2.0-beta2-win32.zip + dc09a293b85ab4f0032f6943815aaf5bbbceb645 pypy-2.0-alpha-arm-armel.tar.bz2 + 0971c4b668bfd2fcd52aa35087aa995e03bd5842 pypy-2.0-alpha-arm-armhf.tar.bz2 + 91910eb654ffbe0509bec2a7aeb460984acf8d82 pypy-upstream_2.0~alpha+arm_armhf.deb 51be6b7b802a5239a759e04ae9595082e17c4c70 pypy-1.9-linux64.tar.bz2 1bc5d2467039b954f9b7395b3ee1b8407ce1c057 pypy-1.9-linux.tar.bz2 825e15724419fbdb6fe215eeea044f9181883c90 pypy-1.9-osx64.tar.bz2 From noreply at buildbot.pypy.org Tue May 7 14:29:25 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 7 May 2013 14:29:25 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: kill disabled Message-ID: <20130507122925.838841C3007@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r406:49dace07a8ee Date: 2013-05-07 14:29 +0200 http://bitbucket.org/pypy/pypy.org/changeset/49dace07a8ee/ Log: kill disabled diff --git a/source/features.txt b/source/features.txt --- a/source/features.txt +++ b/source/features.txt @@ -7,8 +7,7 @@ =========================================================== **PyPy 2.0 beta2** implements **Python 2.7.3** and runs on Intel -`x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms (with ARM -being disabled until 2.0 final), with PPC being underway. +`x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms, with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python From noreply at buildbot.pypy.org Tue May 7 14:29:26 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 7 May 2013 14:29:26 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: fix this Message-ID: <20130507122926.A8C4E1C3007@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r407:d2c71262339d Date: 2013-05-07 14:29 +0200 http://bitbucket.org/pypy/pypy.org/changeset/d2c71262339d/ Log: fix this diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -47,8 +47,7 @@

      Features

      PyPy 2.0 beta2 implements Python 2.7.3 and runs on Intel -x86 (IA-32) , x86_64 and ARM platforms (with ARM -being disabled until 2.0 final), with PPC being underway. +x86 (IA-32) , x86_64 and ARM platforms, with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python From noreply at buildbot.pypy.org Tue May 7 14:33:32 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 7 May 2013 14:33:32 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Tweaks Message-ID: <20130507123332.47B161C1293@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r4970:e7a529a7ff58 Date: 2013-05-07 14:33 +0200 http://bitbucket.org/pypy/extradoc/changeset/e7a529a7ff58/ Log: Tweaks diff --git a/blog/draft/pypy-alpha-arm.rst b/blog/draft/pypy-alpha-arm.rst --- a/blog/draft/pypy-alpha-arm.rst +++ b/blog/draft/pypy-alpha-arm.rst @@ -11,7 +11,7 @@ This is the first release that supports a range of ARM devices - anything with ARMv6 (like the Raspberry Pi) or ARMv7 (like Beagleboard, Chromebook, Cubieboard, etc.) that supports VFPv3 should work. We provide builds with -support for both ARM EABI variants, hard-float and for some older operating +support for both ARM EABI variants: hard-float and some older operating systems soft-float. This release comes with a list of limitations, consider it alpha quality, @@ -62,9 +62,9 @@ * benchmark name -* PyPy speedup over CPython on ARM +* PyPy speedup over CPython on ARM (Cortex A9) -* PyPy speedup over CPython on x86 +* PyPy speedup over CPython on x86 (Xeon) * speedup on Xeon vs Cortex A9, as measured on CPython @@ -156,8 +156,8 @@ .. _`installation schemes`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy .. _`PyPy and pip`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy -We would not recommend using PyPy on ARM just quite yet, however the day -of a stable PyPy ARM release is not far off. +We would not recommend using in production PyPy on ARM just quite yet, +however the day of a stable PyPy ARM release is not far off. Cheers, fijal, bivab, arigo and the whole PyPy team From noreply at buildbot.pypy.org Tue May 7 14:34:19 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 7 May 2013 14:34:19 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: link typo Message-ID: <20130507123419.500911C1293@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r4971:6f14b045461e Date: 2013-05-07 14:33 +0200 http://bitbucket.org/pypy/extradoc/changeset/6f14b045461e/ Log: link typo diff --git a/blog/draft/pypy-alpha-arm.rst b/blog/draft/pypy-alpha-arm.rst --- a/blog/draft/pypy-alpha-arm.rst +++ b/blog/draft/pypy-alpha-arm.rst @@ -45,7 +45,7 @@ in other builds, such as gnueabi for ARMv6 or without requiring a VFP let us know in the comments or in IRC. -.. _`cross-compilation custom toolchain`: https://github.com/raspberrypi +.. _`cross-compilation toolchain`: https://github.com/raspberrypi Benchmarks ========== From noreply at buildbot.pypy.org Tue May 7 14:34:20 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 7 May 2013 14:34:20 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: merge Message-ID: <20130507123420.8B6691C1293@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r4972:06be20da4eb9 Date: 2013-05-07 14:34 +0200 http://bitbucket.org/pypy/extradoc/changeset/06be20da4eb9/ Log: merge diff --git a/blog/draft/pypy-alpha-arm.rst b/blog/draft/pypy-alpha-arm.rst --- a/blog/draft/pypy-alpha-arm.rst +++ b/blog/draft/pypy-alpha-arm.rst @@ -11,7 +11,7 @@ This is the first release that supports a range of ARM devices - anything with ARMv6 (like the Raspberry Pi) or ARMv7 (like Beagleboard, Chromebook, Cubieboard, etc.) that supports VFPv3 should work. We provide builds with -support for both ARM EABI variants, hard-float and for some older operating +support for both ARM EABI variants: hard-float and some older operating systems soft-float. This release comes with a list of limitations, consider it alpha quality, @@ -62,9 +62,9 @@ * benchmark name -* PyPy speedup over CPython on ARM +* PyPy speedup over CPython on ARM (Cortex A9) -* PyPy speedup over CPython on x86 +* PyPy speedup over CPython on x86 (Xeon) * speedup on Xeon vs Cortex A9, as measured on CPython @@ -156,8 +156,8 @@ .. _`installation schemes`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy .. _`PyPy and pip`: http://doc.pypy.org/en/latest/getting-started.html#installing-pypy -We would not recommend using PyPy on ARM just quite yet, however the day -of a stable PyPy ARM release is not far off. +We would not recommend using in production PyPy on ARM just quite yet, +however the day of a stable PyPy ARM release is not far off. Cheers, fijal, bivab, arigo and the whole PyPy team From noreply at buildbot.pypy.org Tue May 7 14:35:20 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 7 May 2013 14:35:20 +0200 (CEST) Subject: [pypy-commit] extradoc extradoc: Stuff that was left around Message-ID: <20130507123520.9FE321C1293@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r4973:0c62020c9d21 Date: 2013-05-07 14:35 +0200 http://bitbucket.org/pypy/extradoc/changeset/0c62020c9d21/ Log: Stuff that was left around diff --git a/talk/pycon2013/pypy_without_gil/message_passing.py b/talk/pycon2013/pypy_without_gil/message_passing.py --- a/talk/pycon2013/pypy_without_gil/message_passing.py +++ b/talk/pycon2013/pypy_without_gil/message_passing.py @@ -24,5 +24,4 @@ running_threads -= 1 else: num += 1 - print num diff --git a/talk/pycon2013/pypy_without_gil/transactions2.py b/talk/pycon2013/pypy_without_gil/transactions2.py --- a/talk/pycon2013/pypy_without_gil/transactions2.py +++ b/talk/pycon2013/pypy_without_gil/transactions2.py @@ -8,11 +8,12 @@ def do_stuff_for_all(lst): + #for x in lst: + # do_stuff(x) + for x in lst: - do_stuff(x) - #for x in lst: - # transaction.add(do_stuff, x) - #transaction.run() + transaction.add(do_stuff, x) + transaction.run() do_stuff_for_all(range(20)) From noreply at buildbot.pypy.org Tue May 7 20:23:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 7 May 2013 20:23:41 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Remove trailing spaces. Message-ID: <20130507182341.4585A1C12FE@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63900:9e8ee4cd15f9 Date: 2013-05-07 14:01 +0200 http://bitbucket.org/pypy/pypy/changeset/9e8ee4cd15f9/ Log: Remove trailing spaces. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -42,7 +42,7 @@ * `Release 2.0 beta 2`_: the latest official release -* `PyPy Blog`_: news and status info about PyPy +* `PyPy Blog`_: news and status info about PyPy * `Papers`_: Academic papers, talks, and related projects @@ -51,18 +51,18 @@ * `potential project ideas`_: In case you want to get your feet wet... * `more stuff`_: this is a collection of documentation that's there, but not - particularly organized + particularly organized Documentation for the PyPy Python Interpreter ============================================= -New features of PyPy's Python Interpreter and -Translation Framework: +New features of PyPy's Python Interpreter and +Translation Framework: * `Differences between PyPy and CPython`_ * `What PyPy can do for your objects`_ - transparent proxy documentation * `Continulets and greenlets`_ - documentation about stackless features - * `JIT Generation in PyPy`_ + * `JIT Generation in PyPy`_ * `JIT hooks`_ * `Sandboxing Python code`_ * `Garbage collection environment variables`_ @@ -79,14 +79,14 @@ ============================================= * `Development mailing list`_: development and conceptual - discussions. + discussions. * `Mercurial commit mailing list`_: updates to code and - documentation. + documentation. -* `Development bug/feature tracker`_: filing bugs and feature requests. +* `Development bug/feature tracker`_: filing bugs and feature requests. -* **IRC channel #pypy on freenode**: Many of the core developers are hanging out +* **IRC channel #pypy on freenode**: Many of the core developers are hanging out at #pypy on irc.freenode.net. You are welcome to join and ask questions (if they are not already developed in the FAQ_). You can find logs of the channel here_. @@ -100,7 +100,7 @@ on the `development mailing list`_. .. _Python: http://docs.python.org/index.html -.. _`more...`: architecture.html#mission-statement +.. _`more...`: architecture.html#mission-statement .. _`PyPy blog`: http://morepypy.blogspot.com/ .. _`development bug/feature tracker`: https://bugs.pypy.org .. _here: http://tismerysoft.de/pypy/irc-logs/pypy From noreply at buildbot.pypy.org Tue May 7 20:23:40 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 7 May 2013 20:23:40 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Random small fixes (mainly in RPython docs). Message-ID: <20130507182340.003181C1293@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63899:f35d5cbbd586 Date: 2013-05-07 12:48 +0200 http://bitbucket.org/pypy/pypy/changeset/f35d5cbbd586/ Log: Random small fixes (mainly in RPython docs). diff --git a/pypy/doc/getting-started-dev.rst b/pypy/doc/getting-started-dev.rst --- a/pypy/doc/getting-started-dev.rst +++ b/pypy/doc/getting-started-dev.rst @@ -205,22 +205,12 @@ separately announced and often happen around Python conferences such as EuroPython or Pycon. Upcoming events are usually announced on `the blog`_. -.. _`full Python interpreter`: getting-started-python.html .. _`the blog`: http://morepypy.blogspot.com .. _`pypy-dev mailing list`: http://python.org/mailman/listinfo/pypy-dev .. _`contact possibilities`: index.html .. _`py library`: http://pylib.org -.. _`Spidermonkey`: http://www.mozilla.org/js/spidermonkey/ - -.. _`.NET Framework SDK`: http://msdn.microsoft.com/netframework/ -.. _Mono: http://www.mono-project.com/Main_Page -.. _`CLI backend`: cli-backend.html -.. _clr: clr-module.html - -.. _`Dot Graphviz`: http://www.graphviz.org/ -.. _Pygame: http://www.pygame.org/ .. _Standard object space: objspace.html#the-standard-object-space .. _mailing lists: index.html .. _documentation: index.html#project-documentation diff --git a/rpython/doc/cli-backend.rst b/rpython/doc/cli-backend.rst --- a/rpython/doc/cli-backend.rst +++ b/rpython/doc/cli-backend.rst @@ -33,7 +33,7 @@ - the code generation part could be easier because the target language supports high level control structures such as structured loops; - + - the generated executables take advantage of compiler's optimizations. @@ -59,7 +59,7 @@ generate: - write IL code to a file, then call the ilasm assembler; - + - directly generate code on the fly by accessing the facilities exposed by the System.Reflection.Emit API. @@ -104,14 +104,14 @@ - map ootypesystem's types to CLI Common Type System's types; - + - map ootypesystem's low level operation to CLI instructions; - + - map Python exceptions to CLI exceptions; - + - write a code generator that translates a flow graph into a list of CLI instructions; - + - write a class generator that translates ootypesystem classes into CLI classes. @@ -137,7 +137,7 @@ one-to-one translation, but has the disadvantage that RPython strings will not be recognized as .NET strings, since they only would be sequences of bytes; - + - map both char, so that Python strings will be treated as strings also by .NET: in this case there could be problems with existing Python modules that use strings as sequences of byte, such as the @@ -245,19 +245,19 @@ instruction that raises System.OverflowException when the result overflows, catch that exception and throw a new one:: - .try - { + .try + { ldarg 'x_0' ldarg 'y_0' - add.ovf + add.ovf stloc 'v1' - leave __check_block_2 - } - catch [mscorlib]System.OverflowException - { - newobj instance void class OverflowError::.ctor() - throw - } + leave __check_block_2 + } + catch [mscorlib]System.OverflowException + { + newobj instance void class OverflowError::.ctor() + throw + } Translating flow graphs @@ -308,7 +308,7 @@ ... // IL - block0: + block0: .try { ... leave block3 diff --git a/rpython/doc/contents.rst b/rpython/doc/contents.rst --- a/rpython/doc/contents.rst +++ b/rpython/doc/contents.rst @@ -5,7 +5,7 @@ .. toctree:: :maxdepth: 2 - + getting-started faq rpython diff --git a/rpython/doc/faq.rst b/rpython/doc/faq.rst --- a/rpython/doc/faq.rst +++ b/rpython/doc/faq.rst @@ -29,16 +29,16 @@ Localized Type Inference of Atomic Types in Python, http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.90.3231 -.. _`PyPy's RPython`: +.. _`PyPy's RPython`: ------------------------------ What is this RPython language? ------------------------------ -RPython is a restricted subset of the Python language. It is used for +RPython is a restricted subset of the Python language. It is used for implementing dynamic language interpreters within the PyPy toolchain. The restrictions ensure that type inference (and so, ultimately, translation -to other languages) of RPython programs is possible. +to other languages) of RPython programs is possible. The property of "being RPython" always applies to a full program, not to single functions or modules (the translation toolchain does a full program analysis). @@ -64,10 +64,10 @@ Does RPython have anything to do with Zope's Restricted Python? --------------------------------------------------------------- -No. `Zope's RestrictedPython`_ aims to provide a sandboxed +No. `Zope's RestrictedPython`_ aims to provide a sandboxed execution environment for CPython. `PyPy's RPython`_ is the implementation -language for dynamic language interpreters. However, PyPy also provides -a robust `sandboxed Python Interpreter`_. +language for dynamic language interpreters. However, PyPy also provides +a robust `sandboxed Python Interpreter`_. .. _`sandboxed Python Interpreter`: sandbox.html .. _`Zope's RestrictedPython`: http://pypi.python.org/pypi/RestrictedPython diff --git a/rpython/doc/getting-started.rst b/rpython/doc/getting-started.rst --- a/rpython/doc/getting-started.rst +++ b/rpython/doc/getting-started.rst @@ -11,7 +11,7 @@ RPython is considered from live objects **after** the imports are done. This might require more explanation. You start writing RPython from ``entry_point``, a good starting point is -``rpython/translator/goal/targetnopstandalone.py``. This does not do all that +:source:`rpython/translator/goal/targetnopstandalone.py`. This does not do all that much, but is a start. Now if code analyzed (in this case ``entry_point``) calls some functions, those calls will be followed. Those followed calls have to be RPython themselves (and everything they call etc.), however not @@ -50,6 +50,7 @@ .. _`part 2`: http://morepypy.blogspot.com/2011/04/tutorial-part-2-adding-jit.html .. _`try out the translator`: + Trying out the translator ------------------------- @@ -61,13 +62,16 @@ * Pygame_ * `Dot Graphviz`_ +.. _Pygame: http://www.pygame.org/ +.. _`Dot Graphviz`: http://www.graphviz.org/ + To start the interactive translator shell do:: cd rpython python bin/translatorshell.py Test snippets of translatable code are provided in the file -``rpython/translator/test/snippet.py``, which is imported under the name +:source:`rpython/translator/test/snippet.py`, which is imported under the name ``snippet``. For example:: >>> t = Translation(snippet.is_perfect_number, [int]) @@ -117,7 +121,7 @@ from the interactive translator shells as follows:: >>> def myfunc(a, b): return a+b - ... + ... >>> t = Translation(myfunc, [int, int]) >>> t.annotate() >>> f = t.compile_cli() # or compile_jvm() @@ -143,9 +147,13 @@ To translate and run for the CLI you must have the SDK installed: Windows users need the `.NET Framework SDK`_, while Linux and Mac users -can use Mono_. To translate and run for the JVM you must have a JDK +can use Mono_. To translate and run for the JVM you must have a JDK installed (at least version 6) and ``java``/``javac`` on your path. +.. _`CLI backend`: cli-backend.html +.. _`.NET Framework SDK`: http://msdn.microsoft.com/netframework/ +.. _Mono: http://www.mono-project.com/Main_Page + A slightly larger example +++++++++++++++++++++++++ @@ -169,7 +177,7 @@ +++++++++++++++++++++++++ To translate full RPython programs, there is the script ``translate.py`` in -``rpython/translator/goal``. Examples for this are a slightly changed version of +:source:`rpython/translator/goal`. Examples for this are a slightly changed version of Pystone:: python bin/rpython translator/goal/targetrpystonedalone @@ -196,23 +204,25 @@ Sources ------- -* `rpython/translator`_ contains the code analysis and generation stuff. +* :source:`rpython/translator` contains the code analysis and generation stuff. Start reading from translator.py, from which it should be easy to follow the pieces of code involved in the various translation phases. -* `rpython/annotator`_ contains the data model for the type annotation that +* :source:`rpython/annotator` contains the data model for the type annotation that can be inferred about a graph. The graph "walker" that uses this is in - `rpython/annotator/annrpython.py`_. + :source:`rpython/annotator/annrpython.py`. -* `rpython/rtyper`_ contains the code of the RPython typer. The typer transforms +* :source:`rpython/rtyper` contains the code of the RPython typer. The typer transforms annotated flow graphs in a way that makes them very similar to C code so that they can be easy translated. The graph transformations are controlled - by the code in `rpython/rtyper/rtyper.py`_. The object model that is used can - be found in `rpython/rtyper/lltypesystem/lltype.py`_. For each RPython type + by the code in :source:`rpython/rtyper/rtyper.py`. The object model that is used can + be found in :source:`rpython/rtyper/lltypesystem/lltype.py`. For each RPython type there is a file rxxxx.py that contains the low level functions needed for this type. -* `rpython/rlib`_ contains the `RPython standard library`_, things that you can +* :source:`rpython/rlib` contains the `RPython standard library`_, things that you can use from rpython. + +.. _`full Python interpreter`: http://pypy.readthedocs.org/en/latest/getting-started-python.html .. _`RPython standard library`: rlib.html diff --git a/rpython/doc/rffi.rst b/rpython/doc/rffi.rst --- a/rpython/doc/rffi.rst +++ b/rpython/doc/rffi.rst @@ -1,6 +1,5 @@ - Foreign Function Interface for RPython -======================================= +====================================== Purpose ------- @@ -47,19 +46,19 @@ Types ------- +----- In rffi_ there are various declared types for C-structures, like CCHARP -(char*), SIZE_T (size_t) and others. refer to file for details. -Instances of non-primitive types must be alloced by hand, with call -to lltype.malloc, and freed by lltype.free both with keyword argument +(char*), SIZE_T (size_t) and others. refer to file for details. +Instances of non-primitive types must be alloced by hand, with call +to lltype.malloc, and freed by lltype.free both with keyword argument flavor='raw'. There are several helpers like string -> char* converter, refer to the source for details. .. _rffi: https://bitbucket.org/pypy/pypy/src/tip/pypy/rpython/lltypesystem/rffi.py Registering function as external ---------------------------------- +-------------------------------- Once we provided low-level implementation of an external function, would be nice to wrap call to some library function (like os.open) diff --git a/rpython/doc/rlib.rst b/rpython/doc/rlib.rst --- a/rpython/doc/rlib.rst +++ b/rpython/doc/rlib.rst @@ -1,6 +1,6 @@ -================================================= -Generally Useful RPython Modules -================================================= +================================ +Generally Useful RPython Modules +================================ .. _Python: http://www.python.org/dev/doc/maint24/ref/ref.html @@ -158,7 +158,7 @@ parsers in RPython. It is still highly experimental and only really used by the `Prolog interpreter`_ (although in slightly non-standard ways). The easiest way to specify a tokenizer/grammar is to write it down using regular expressions and -simple EBNF format. +simple EBNF format. The regular expressions are implemented using finite automatons. The parsing engine uses `packrat parsing`_, which has O(n) parsing time but is more @@ -231,7 +231,7 @@ non-significant whitespace. Grammar rules have the form:: - + name: expansion_1 | expansion_2 | ... | expansion_n; Where ``expansion_i`` is a sequence of nonterminal or token names:: @@ -244,7 +244,7 @@ are strings in quotes that are matched literally. An example to make this clearer:: - + IGNORE: " "; DECIMAL: "0|[1-9][0-9]*"; additive: multitive "+" additive | diff --git a/rpython/doc/rpython.rst b/rpython/doc/rpython.rst --- a/rpython/doc/rpython.rst +++ b/rpython/doc/rpython.rst @@ -14,7 +14,7 @@ Flow restrictions -------------------------- +----------------- **variables** @@ -63,7 +63,7 @@ Object restrictions -------------------------- +------------------- We are using @@ -104,12 +104,12 @@ - *indexing*: positive and negative indexes are allowed. Indexes are checked when requested by an IndexError exception clause. - + - *slicing*: the slice start must be within bounds. The stop doesn't need to, but it must not be smaller than the start. All negative indexes are disallowed, except for the [:-1] special case. No step. Slice deletion follows the same rules. - + - *slice assignment*: only supports ``lst[x:y] = sublist``, if ``len(sublist) == y - x``. In other words, slice assignment cannot change the total length of the list, @@ -176,7 +176,7 @@ Integer Types -------------------------- +------------- While implementing the integer type, we stumbled over the problem that integers are quite in flux in CPython right now. Starting with Python 2.4, @@ -229,7 +229,7 @@ Exception rules ---------------------- +--------------- Exceptions are by default not generated for simple cases.:: diff --git a/rpython/doc/rtyper.rst b/rpython/doc/rtyper.rst --- a/rpython/doc/rtyper.rst +++ b/rpython/doc/rtyper.rst @@ -105,7 +105,7 @@ turning representations into explicit objects. The base Repr class is defined in :source:`rpython/rtyper/rmodel.py`. Most of the -``rpython/r*.py`` files define one or a few subclasses of Repr. The method +:source:`rpython/`\ ``r*.py`` files define one or a few subclasses of Repr. The method getrepr() of the RTyper will build and cache a single Repr instance per SomeXxx() instance; moreover, two SomeXxx() instances that are equal get the same Repr instance. @@ -244,7 +244,7 @@ Structure Types +++++++++++++++ -Structure types are built as instances of +Structure types are built as instances of ``rpython.rtyper.lltypesystem.lltype.Struct``:: MyStructType = Struct('somename', ('field1', Type1), ('field2', Type2)...) @@ -276,7 +276,7 @@ Array Types +++++++++++ -An array type is built as an instance of +An array type is built as an instance of ``rpython.rtyper.lltypesystem.lltype.Array``:: MyIntArray = Array(Signed) @@ -714,7 +714,7 @@ Exception handling: ``hop.has_implicit_exception(cls)`` - Checks if hop is in the scope of a branch catching the exception + Checks if hop is in the scope of a branch catching the exception 'cls'. This is useful for high-level operations like 'getitem' that have several low-level equivalents depending on whether they should check for an IndexError or not. Calling diff --git a/rpython/doc/translation.rst b/rpython/doc/translation.rst --- a/rpython/doc/translation.rst +++ b/rpython/doc/translation.rst @@ -106,7 +106,7 @@ .. _`interactive interface`: getting-started-dev.html#try-out-the-translator .. _`flow model`: -.. _`control flow graphs`: +.. _`control flow graphs`: The Flow Model ============== @@ -200,7 +200,7 @@ A link from one basic block to another. :prevblock: the Block that this Link is an exit of. - + :target: the target Block to which this Link points to. :args: a list of Variables and Constants, of the same size as the @@ -335,7 +335,7 @@ the same ``SomeXxx`` annotation, and so have all values). User-defined Classes and Instances ------------------------------------ +---------------------------------- ``SomeInstance`` stands for an instance of the given class or any subclass of it. For each user-defined class seen by the annotator, we @@ -450,7 +450,7 @@ the "backend optimizations" and the "stackless transform". See also `D07.1 Massive Parallelism and Translation Aspects`_ for further details. -.. _`Technical report`: +.. _`Technical report`: .. _`D07.1 Massive Parallelism and Translation Aspects`: https://bitbucket.org/pypy/extradoc/raw/ee3059291497/eu-report/D07.1_Massive_Parallelism_and_Translation_Aspects-2007-02-28.pdf Backend Optimizations diff --git a/rpython/doc/windows.rst b/rpython/doc/windows.rst --- a/rpython/doc/windows.rst +++ b/rpython/doc/windows.rst @@ -13,12 +13,12 @@ Translating PyPy with Visual Studio ----------------------------------- -We routinely test the `RPython translation toolchain`_ using +We routinely test the `RPython translation toolchain`_ using Visual Studio 2008, Express Edition. Other configurations may work as well. The translation scripts will set up the appropriate environment variables -for the compiler, so you do not need to run vcvars before translation. +for the compiler, so you do not need to run vcvars before translation. They will attempt to locate the same compiler version that was used to build the Python interpreter doing the translation. Failing that, they will pick the most recent Visual Studio @@ -65,7 +65,7 @@ Abridged method (for -Ojit builds using Visual Studio 2008) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Download the versions of all the external packages -from +from https://bitbucket.org/pypy/pypy/downloads/local.zip Then expand it into the base directory (base_dir) and modify your environment to reflect this:: @@ -110,15 +110,16 @@ cd bzip2-1.0.5 nmake -f makefile.msc - + The sqlite3 database library -~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Download http://www.sqlite.org/2013/sqlite-amalgamation-3071601.zip and extract -it into a directory under the base directory. Also get +it into a directory under the base directory. Also get http://www.sqlite.org/2013/sqlite-dll-win32-x86-3071601.zip and extract the dll into the bin directory, and the sqlite3.def into the sources directory. Now build the import library so cffi can use the header and dll:: + lib /DEF:sqlite3.def" /OUT:sqlite3.lib" copy sqlite3.lib path\to\libs @@ -128,11 +129,11 @@ Download the source code of expat on sourceforge: http://sourceforge.net/projects/expat/ and extract it in the base -directory. Version 2.1.0 is known to pass tests. Then open the project +directory. Version 2.1.0 is known to pass tests. Then open the project file ``expat.dsw`` with Visual Studio; follow the instruction for converting the project files, -switch to the "Release" configuration, reconfigure the runtime for -Multi-threaded DLL (/MD) and build the solution (the ``expat`` project +switch to the "Release" configuration, reconfigure the runtime for +Multi-threaded DLL (/MD) and build the solution (the ``expat`` project is actually enough for PyPy). Then, copy the file ``win32\bin\release\libexpat.dll`` somewhere in @@ -162,24 +163,24 @@ You probably want to set the CPATH, LIBRARY_PATH, and PATH environment variables to the header files, lib or dlls, and dlls respectively of the -locally installed packages if they are not in the mingw directory heirarchy. +locally installed packages if they are not in the mingw directory heirarchy. libffi for the mingw compiler -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To enable the _rawffi (and ctypes) module, you need to compile a mingw version of libffi. Here is one way to do this, wich should allow you to try to build for win64 or win32: #. Download and unzip a `mingw32 build`_ or `mingw64 build`_, say into c:\mingw -#. If you do not use cygwin, you will need msys to provide make, +#. If you do not use cygwin, you will need msys to provide make, autoconf tools and other goodies. #. Download and unzip a `msys for mingw`_, say into c:\msys #. Edit the c:\msys\etc\fstab file to mount c:\mingw #. Download and unzip the `libffi source files`_, and extract - them in the base directory. + them in the base directory. #. Run c:\msys\msys.bat or a cygwin shell which should make you feel better since it is a shell prompt with shell tools. #. From inside the shell, cd to the libffi directory and do:: @@ -188,7 +189,7 @@ make cp .libs/libffi-5.dll -If you can't find the dll, and the libtool issued a warning about +If you can't find the dll, and the libtool issued a warning about "undefined symbols not allowed", you will need to edit the libffi Makefile in the toplevel directory. Add the flag -no-undefined to the definition of libffi_la_LDFLAGS @@ -208,6 +209,6 @@ .. _`mingw32 build`: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Automated%20Builds .. _`mingw64 build`: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds -.. _`msys for mingw`: http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29 +.. _`msys for mingw`: http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29 .. _`libffi source files`: http://sourceware.org/libffi/ .. _`RPython translation toolchain`: translation.html From noreply at buildbot.pypy.org Tue May 7 20:23:38 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 7 May 2013 20:23:38 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add blank lines in what's new documents. Message-ID: <20130507182338.854781C073E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63898:6f745095a36d Date: 2013-05-06 19:44 +0200 http://bitbucket.org/pypy/pypy/changeset/6f745095a36d/ Log: Add blank lines in what's new documents. diff --git a/pypy/doc/whatsnew-1.9.rst b/pypy/doc/whatsnew-1.9.rst --- a/pypy/doc/whatsnew-1.9.rst +++ b/pypy/doc/whatsnew-1.9.rst @@ -6,98 +6,168 @@ .. startrev: a4261375b359 .. branch: default -* Working hash function for numpy types. + +Working hash function for numpy types. .. branch: array_equal + .. branch: better-jit-hooks-2 + Improved jit hooks + .. branch: faster-heapcache + .. branch: faster-str-decode-escape + .. branch: float-bytes + Added some primitives for dealing with floats as raw bytes. + .. branch: float-bytes-2 + Added more float byte primitives. + .. branch: jit-frame-counter + Put more debug info into resops. + .. branch: kill-geninterp + Kill "geninterp", an old attempt to statically turn some fixed app-level code to interp-level. + .. branch: kqueue + Finished select.kqueue. + .. branch: kwargsdict-strategy + Special dictionary strategy for dealing with \*\*kwds. Now having a simple -proxy ``def f(*args, **kwds): return x(*args, **kwds`` should not make +proxy ``def f(*args, **kwds): return x(*args, **kwds)`` should not make any allocations at all. + .. branch: matrixmath-dot + numpypy can now handle matrix multiplication. + .. branch: merge-2.7.2 + The stdlib was updated to version 2.7.2 + .. branch: ndmin + .. branch: newindex + .. branch: non-null-threadstate + cpyext: Better support for PyEval_SaveThread and other PyTreadState_* functions. + .. branch: numppy-flatitter + flatitier for numpy + .. branch: numpy-back-to-applevel + reuse more of original numpy + .. branch: numpy-concatenate + concatenation support for numpy + .. branch: numpy-indexing-by-arrays-bool + indexing by bool arrays + .. branch: numpy-record-dtypes + record dtypes on numpy has been started + .. branch: numpy-single-jitdriver + .. branch: numpy-ufuncs2 + .. branch: numpy-ufuncs3 + various refactorings regarding numpy + .. branch: numpypy-issue1137 + .. branch: numpypy-out + The "out" argument was added to most of the numypypy functions. + .. branch: numpypy-shape-bug + .. branch: numpypy-ufuncs + .. branch: pytest + .. branch: safe-getargs-freelist + CPyext improvements. For example PyOpenSSL should now work + .. branch: set-strategies + Sets now have strategies just like dictionaries. This means a set containing only ints will be more compact (and faster) + .. branch: speedup-list-comprehension + The simplest case of list comprehension is preallocating the correct size of the list. This speeds up select benchmarks quite significantly. + .. branch: stdlib-unification + The directory "lib-python/modified-2.7" has been removed, and its content merged into "lib-python/2.7". + .. branch: step-one-xrange + The common case of a xrange iterator with no step argument specifed was somewhat optimized. The tightest loop involving it, sum(xrange(n)), is now 18% faster on average. + .. branch: string-NUL + PyPy refuses filenames with chr(0) characters. This is implemented in RPython which can enforce no-NUL correctness and propagation, similar to const-correctness in C++. + .. branch: win32-cleanup .. branch: win32-cleanup2 .. branch: win32-cleanup_2 + Many bugs were corrected for windows 32 bit. New functionality was added to -test validity of file descriptors, leading to the removal of the global +test validity of file descriptors, leading to the removal of the global _invalid_parameter_handler + .. branch: win32-kill + Add os.kill to windows even if translating python does not have os.kill + .. branch: win_ffi + Handle calling conventions for the _ffi and ctypes modules + .. branch: win64-stage1 + .. branch: zlib-mem-pressure + Memory "leaks" associated with zlib are fixed. .. branch: ffistruct + The ``ffistruct`` branch adds a very low level way to express C structures with _ffi in a very JIT-friendly way +.. "uninteresting" branches that we should just ignore for the whatsnew: -.. "uninteresting" branches that we should just ignore for the whatsnew: .. branch: exception-cannot-occur + .. branch: sanitize-finally-stack + .. branch: revive-dlltool - (preliminary work for sepcomp) + +(preliminary work for sepcomp) diff --git a/pypy/doc/whatsnew-2.0.0-beta1.rst b/pypy/doc/whatsnew-2.0.0-beta1.rst --- a/pypy/doc/whatsnew-2.0.0-beta1.rst +++ b/pypy/doc/whatsnew-2.0.0-beta1.rst @@ -5,61 +5,107 @@ .. this is the revision of the last merge from default to release-1.9.x .. startrev: 8d567513d04d +.. branch: default + Fixed the performance of gc.get_referrers() -.. branch: default .. branch: app_main-refactor + .. branch: win-ordinal + .. branch: reflex-support + Provides cppyy module (disabled by default) for access to C++ through Reflex. See doc/cppyy.rst for full details and functionality. + .. branch: nupypy-axis-arg-check + Check that axis arg is valid in _numpypy + .. branch:less-gettestobjspace + .. branch: move-apptest-support .. branch: iterator-in-rpython + .. branch: numpypy_count_nonzero + .. branch: numpy-refactor + Remove numpy lazy evaluation and simplify everything + .. branch: numpy-reintroduce-jit-drivers + .. branch: numpy-fancy-indexing + Support for array[array-of-ints] in numpy + .. branch: even-more-jit-hooks + Implement better JIT hooks + .. branch: virtual-arguments -Improve handling of **kwds greatly, making them virtual sometimes. + +Improve handling of \*\*kwds greatly, making them virtual sometimes. + .. branch: improve-rbigint + Introduce __int128 on systems where it's supported and improve the speed of rlib/rbigint.py greatly. + .. branch: translation-cleanup + Start to clean up a bit the flow object space. + .. branch: ffi-backend + Support CFFI. http://morepypy.blogspot.ch/2012/08/cffi-release-03.html + .. branch: speedup-unpackiterable + .. branch: stdlib-2.7.3 + The stdlib was updated to version 2.7.3 .. branch: numpypy-complex2 + Complex dtype support for numpy + .. branch: numpypy-problems + Improve dtypes intp, uintp, void, string and record + .. branch: numpypy.float16 + Add float16 numpy dtype + .. branch: kill-someobject + major cleanups including killing some object support + .. branch: cpyext-PyThreadState_New + implement threadstate-related functions in cpyext .. branch: unicode-strategies + add dict/list/set strategies optimized for unicode items + .. "uninteresting" branches that we should just ignore for the whatsnew: + .. branch: slightly-shorter-c + .. branch: better-enforceargs + .. branch: rpython-unicode-formatting + .. branch: jit-opaque-licm + .. branch: rpython-utf8 + Support for utf-8 encoding in RPython + .. branch: arm-backend-2 + Support ARM in the JIT. diff --git a/pypy/doc/whatsnew-2.0.rst b/pypy/doc/whatsnew-2.0.rst --- a/pypy/doc/whatsnew-2.0.rst +++ b/pypy/doc/whatsnew-2.0.rst @@ -6,9 +6,11 @@ .. startrev: 0e6161a009c6 .. branch: split-rpython + Split rpython and pypy into seperate directories .. branch: callback-jit + Callbacks from C are now better JITted .. branch: fix-jit-logs @@ -16,62 +18,87 @@ .. branch: remove-globals-in-jit .. branch: length-hint + Implement __lenght_hint__ according to PEP 424 .. branch: numpypy-longdouble + Long double support for numpypy .. branch: numpypy-disable-longdouble + Since r_longdouble support is missing, disable all longdouble and derivative dtypes using ENABLED_LONG_DOUBLE = False .. branch: numpypy-real-as-view + Convert real, imag from ufuncs to views. This involves the beginning of view() functionality .. branch: indexing-by-array + Adds indexing by scalar, adds int conversion from scalar and single element array, fixes compress, indexing by an array with a smaller shape and the indexed object. .. branch: str-dtype-improvement + Allow concatenation of str and numeric arrays .. branch: signatures + Improved RPython typing .. branch: rpython-bytearray + Rudimentary support for bytearray in RPython .. branch: refactor-call_release_gil + Fix a bug which caused cffi to return the wrong result when calling a C function which calls a Python callback which forces the frames .. branch: virtual-raw-mallocs + JIT optimizations which make cffi calls even faster, by removing the need to allocate a temporary buffer where to store the arguments. .. branch: improve-docs-2 + Improve documents and straighten out links .. branch: fast-newarray + Inline the fast path of newarray in the assembler. Disabled on ARM until we fix issues. .. branch: reflex-support + Allow dynamic loading of a (Reflex) backend that implements the C-API needed to provide reflection information + .. branches we don't care about + .. branch: autoreds + .. branch: kill-faking + .. branch: improved_ebnfparse_error + .. branch: task-decorator + .. branch: fix-e4fa0b2 + .. branch: win32-fixes + .. branch: numpy-unify-methods + .. branch: fix-version-tool + .. branch: popen2-removal + .. branch: pickle-dumps + .. branch: scalar_get_set .. branch: release-2.0-beta1 @@ -81,23 +108,29 @@ .. branch: missing-jit-operations .. branch: fix-lookinside-iff-oopspec + Fixed the interaction between two internal tools for controlling the JIT. .. branch: inline-virtualref-2 + Better optimized certain types of frame accesses in the JIT, particularly around exceptions that escape the function they were raised in. .. branch: missing-ndarray-attributes + Some missing attributes from ndarrays .. branch: cleanup-tests + Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into one directory for reduced confusion and so they all run nightly. .. branch: unquote-faster + .. branch: urlparse-unquote-faster .. branch: signal-and-thread + Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a non-main thread to enable the processing of signal handlers in that thread. @@ -106,35 +139,45 @@ .. branch: clean-up-remaining-pypy-rlib-refs .. branch: enumerate-rstr + Support enumerate() over rstr types. .. branch: cleanup-numpypy-namespace + Cleanup _numpypy and numpypy namespaces to more closely resemble numpy. .. branch: kill-flowobjspace + Random cleanups to hide FlowObjSpace from public view. .. branch: vendor-rename .. branch: jitframe-on-heap + Moves optimized JIT frames from stack to heap. As a side effect it enables stackless to work well with the JIT on PyPy. Also removes a bunch of code from the GC which fixes cannot find gc roots. .. branch: pycon2013-doc-fixes + Documentation fixes after going through the docs at PyCon 2013 sprint. .. branch: extregistry-refactor .. branch: remove-list-smm + .. branch: bridge-logging + .. branch: curses_cffi + cffi implementation of _curses .. branch: sqlite-cffi + cffi implementation of sqlite3 .. branch: release-2.0-beta2 + .. branch: unbreak-freebsd .. branch: virtualref-virtualizable From noreply at buildbot.pypy.org Tue May 7 20:23:42 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 7 May 2013 20:23:42 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Jit generation docs were moved to RPython. Message-ID: <20130507182342.7B8171C1578@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63901:b8500e8e390a Date: 2013-05-07 14:02 +0200 http://bitbucket.org/pypy/pypy/changeset/b8500e8e390a/ Log: Jit generation docs were moved to RPython. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -62,7 +62,6 @@ * `Differences between PyPy and CPython`_ * `What PyPy can do for your objects`_ - transparent proxy documentation * `Continulets and greenlets`_ - documentation about stackless features - * `JIT Generation in PyPy`_ * `JIT hooks`_ * `Sandboxing Python code`_ * `Garbage collection environment variables`_ @@ -70,7 +69,6 @@ .. _`Differences between PyPy and CPython`: cpython_differences.html .. _`What PyPy can do for your objects`: objspace-proxies.html .. _`Continulets and greenlets`: stackless.html -.. _`JIT Generation in PyPy`: jit/index.html .. _`JIT hooks`: jit-hooks.html .. _`Sandboxing Python code`: sandbox.html .. _`Garbage collection environment variables`: gc_info.html From noreply at buildbot.pypy.org Tue May 7 20:23:43 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 7 May 2013 20:23:43 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Fix some internal links. Message-ID: <20130507182343.B25A91C073E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63902:95a26751e3e3 Date: 2013-05-07 20:21 +0200 http://bitbucket.org/pypy/pypy/changeset/95a26751e3e3/ Log: Fix some internal links. diff --git a/rpython/doc/faq.rst b/rpython/doc/faq.rst --- a/rpython/doc/faq.rst +++ b/rpython/doc/faq.rst @@ -56,9 +56,7 @@ exceptions are some functions in ``os``, ``math`` and ``time`` that have native support. -To read more about the RPython limitations read the `RPython description`_. - -.. _`RPython description`: coding-guide.html#restricted-python +To read more about the RPython limitations read the :doc:`RPython description `. --------------------------------------------------------------- Does RPython have anything to do with Zope's Restricted Python? diff --git a/rpython/doc/rlib.rst b/rpython/doc/rlib.rst --- a/rpython/doc/rlib.rst +++ b/rpython/doc/rlib.rst @@ -96,9 +96,7 @@ The :source:`rpython/rlib/rarithmetic.py` module contains functionality to handle the small differences in the behaviour of arithmetic code in regular Python and RPython code. Most of -them are already described in the `coding guide`_ - -.. _`coding guide`: coding-guide.html +them are already described in the :doc:`RPython description `. rbigint diff --git a/rpython/doc/translation.rst b/rpython/doc/translation.rst --- a/rpython/doc/translation.rst +++ b/rpython/doc/translation.rst @@ -6,11 +6,9 @@ This document describes the toolchain that we have developed to analyze -and "compile" RPython_ programs (like PyPy itself) to various target +and "compile" RPython programs (like PyPy itself) to various target platforms. -.. _RPython: coding-guide.html#restricted-python - It consists of three broad sections: a slightly simplified overview, a brief introduction to each of the major components of our toolchain and then a more comprehensive section describing how the pieces fit together. @@ -21,21 +19,18 @@ Overview ======== -The job of the translation toolchain is to translate RPython_ programs into an +The job of the translation toolchain is to translate RPython programs into an efficient version of that program for one of various target platforms, generally one that is considerably lower-level than Python. It divides this task into several steps, and the purpose of this document is to introduce them. -As of the 1.2 release, RPython_ programs can be translated into the following +As of the 1.2 release, RPython programs can be translated into the following languages/platforms: C/POSIX, CLI/.NET and Java/JVM. -.. _`application-level`: coding-guide.html#application-level -.. _`interpreter-level`: coding-guide.html#interpreter-level - The choice of the target platform affects the process somewhat, but to -start with we describe the process of translating an RPython_ program into +start with we describe the process of translating an RPython program into C (which is the default and original target). .. _`initialization time`: @@ -56,7 +51,7 @@ 1. The complete program is imported, at which time arbitrary run-time initialization can be performed. Once this is done, the program must be present in memory as a form that is "static enough" in the sense of - RPython_. + :doc:`RPython `. 2. The Annotator_ performs a global analysis starting from an specified entry point to deduce type and other information about what each @@ -90,7 +85,7 @@ (although these steps are not quite as distinct as you might think from this presentation). -There is an `interactive interface`_ called :source:`rpython/bin/translatorshell.py` to the +There is an :ref:`interactive interface ` called :source:`rpython/bin/translatorshell.py` to the translation process which allows you to interactively work through these stages. From noreply at buildbot.pypy.org Tue May 7 21:49:09 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Tue, 7 May 2013 21:49:09 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Make MixedModule checkmodule() friendly Message-ID: <20130507194909.84FA51C030B@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r63903:5b941d020c95 Date: 2013-05-07 21:51 +0200 http://bitbucket.org/pypy/pypy/changeset/5b941d020c95/ Log: Make MixedModule checkmodule() friendly diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -13,6 +13,7 @@ # imported yet, and when it has been, it is mod.__dict__.items() just # after startup(). w_initialdict = None + lazy = False def __init__(self, space, w_name): """ NOT_RPYTHON """ From noreply at buildbot.pypy.org Tue May 7 23:24:47 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 7 May 2013 23:24:47 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130507212447.212901C1293@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63904:c0958cbd5630 Date: 2013-05-07 14:14 -0700 http://bitbucket.org/pypy/pypy/changeset/c0958cbd5630/ Log: merge default diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -167,7 +167,6 @@ return if '_fields_' not in self.__dict__: self._fields_ = [] - self._names = [] _set_shape(self, [], self._is_union) __setattr__ = struct_setattr diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -1,25 +1,21 @@ -import os +import sys, os from ctypes_configure import dumpcache -from rpython.jit.backend import detect_cpu def dumpcache2(basename, config): - model = detect_cpu.autodetect_main_model_and_size() - filename = '_%s_%s_.py' % (basename, model) + size = 32 if sys.maxint <= 2**32 else 64 + filename = '_%s_%s_.py' % (basename, size) dumpcache.dumpcache(__file__, filename, config) # filename = os.path.join(os.path.dirname(__file__), '_%s_cache.py' % (basename,)) g = open(filename, 'w') print >> g, '''\ -try: - from __pypy__ import cpumodel -except ImportError: - from rpython.jit.backend import detect_cpu - cpumodel = detect_cpu.autodetect_main_model_and_size() +import sys +_size = 32 if sys.maxint <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib -mod = __import__("_%s_%%s_" %% (cpumodel,), - globals(), locals(), ["*"], level=1) -globals().update(mod.__dict__)\ +_mod = __import__("_%s_%%s_" %% (_size,), + globals(), locals(), ["*"], level=1) +globals().update(_mod.__dict__)\ ''' % (basename,) g.close() diff --git a/lib_pypy/ctypes_config_cache/rebuild.py b/lib_pypy/ctypes_config_cache/rebuild.py --- a/lib_pypy/ctypes_config_cache/rebuild.py +++ b/lib_pypy/ctypes_config_cache/rebuild.py @@ -25,13 +25,12 @@ sys.path[:] = path def try_rebuild(): - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - # remove the files '_*_model_.py' + size = 32 if sys.maxint <= 2**32 else 64 + # remove the files '_*_size_.py' left = {} for p in os.listdir(_dirpath): - if p.startswith('_') and (p.endswith('_%s_.py' % model) or - p.endswith('_%s_.pyc' % model)): + if p.startswith('_') and (p.endswith('_%s_.py' % size) or + p.endswith('_%s_.pyc' % size)): os.unlink(os.path.join(_dirpath, p)) elif p.startswith('_') and (p.endswith('_.py') or p.endswith('_.pyc')): diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -87,6 +87,7 @@ '_multiprocessing': [('objspace.usemodules.rctime', True), ('objspace.usemodules.thread', True)], 'cpyext': [('objspace.usemodules.array', True)], + 'cppyy': [('objspace.usemodules.cpyext', True)], } module_suggests = { # the reason you want _rawffi is for ctypes, which diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.0.rst @@ -0,0 +1,61 @@ +============================ +PyPy 2.0 - Einstein Sandwich +============================ + +We're pleased to announce PyPy 2.0. This is a stable release that brings +a swath of bugfixes, small performance improvements and compatibility fixes. + +You can download the PyPy 2.0 release here: + + http://pypy.org/download.html + +The two biggest changes since PyPy 1.9 are: + +* stackless is now supported including greenlets, which means eventlet + and gevent should work (but read below about gevent) + +* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which + is preferred way of calling C from Python that works well on PyPy + +.. _`cffi`: http://cffi.readthedocs.org + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Windows 64 work is still stalling, we would welcome a volunteer +to handle that. ARM support is on the way and we're expecting to release +an alpha ARM version shortly. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +* Stackless including greenlets should work. For gevent, you need to check + out `pypycore`_ and use the `pypy-hacks`_ branch of gevent. + +* cffi is now a module included with PyPy. (`cffi`_ also exists for + CPython; the two versions should be fully compatible.) It is the + preferred way of calling C from Python that works on PyPy. + +* Callbacks from C are now JITted, which means XML parsing is much faster. + +* A lot of speed improvements in various language corners, most of them small, + but speeding up some particular corners a lot. + +* The JIT was refactored to emit machine code which manipulates a "frame" + that lives on the heap rather than on the stack. This is what makes + Stackless work, and it could bring another future speed-up (not done yet). + +* A lot of stability issues fixed. + +.. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ +.. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks + +Cheers, +fijal, arigo and the PyPy team 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 @@ -5,4 +5,3 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 - diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -6,8 +6,14 @@ if sys.platform.startswith('linux'): arch = 'linux' + cmd = 'wget "%s"' + tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" +if sys.platform.startswith('darwin'): + arch = 'osx' + cmd = 'curl -O "%s"' + tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" else: - print 'Cannot determine the platform, please update this scrip' + print 'Cannot determine the platform, please update this script' sys.exit(1) if sys.maxint == 2**63 - 1: @@ -23,10 +29,9 @@ tmp = py.path.local.mkdtemp() mydir = tmp.chdir() print 'Downloading pypy to', tmp -if os.system('wget "%s"' % url) != 0: +if os.system(cmd % url) != 0: sys.exit(1) print 'Extracting pypy binary' mydir.chdir() -os.system("tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" % tmp.join(filename)) - +os.system(tar % tmp.join(filename)) diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -83,6 +83,17 @@ PYC_MAGIC = get_pyc_magic(self.space) self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC) # - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + try: + from rpython.jit.backend import detect_cpu + model = detect_cpu.autodetect() + self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model) + except Exception: + if self.space.config.translation.jit: + raise + else: + pass # ok fine to ignore in this case + # + if self.space.config.translation.jit: + features = detect_cpu.getcpufeatures(model) + self.extra_interpdef('jit_backend_features', + 'space.wrap(%r)' % features) diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py --- a/pypy/module/__pypy__/test/test_special.py +++ b/pypy/module/__pypy__/test/test_special.py @@ -92,3 +92,14 @@ assert list_strategy(l) == "empty" o = 5 raises(TypeError, list_strategy, 5) + + +class AppTestJitFeatures(object): + spaceconfig = {"translation.jit": True} + + def test_jit_backend_features(self): + from __pypy__ import jit_backend_features + supported_types = jit_backend_features + assert isinstance(supported_types, list) + for x in supported_types: + assert x in ['floats', 'singlefloats', 'longlong'] 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 @@ -56,10 +56,15 @@ return rffi.cast(lltype.Unsigned, rffi.cast(TPP, target)[0]) raise NotImplementedError("bad integer size") + at specialize.arg(0) +def _read_raw_float_data_tp(TPP, target): + # in its own function: FLOAT may make the whole function jit-opaque + return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0]) + def read_raw_float_data(target, size): for TP, TPP in _prim_float_types: if size == rffi.sizeof(TP): - return rffi.cast(lltype.Float, rffi.cast(TPP, target)[0]) + return _read_raw_float_data_tp(TPP, target) raise NotImplementedError("bad float size") def read_raw_longdouble_data(target): @@ -82,10 +87,15 @@ raise NotImplementedError("bad integer size") + at specialize.arg(0, 1) +def _write_raw_float_data_tp(TP, TPP, target, source): + # in its own function: FLOAT may make the whole function jit-opaque + rffi.cast(TPP, target)[0] = rffi.cast(TP, source) + def write_raw_float_data(target, source, size): for TP, TPP in _prim_float_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, target)[0] = rffi.cast(TP, source) + _write_raw_float_data_tp(TP, TPP, target, source) return raise NotImplementedError("bad float size") @@ -267,13 +277,18 @@ # ____________________________________________________________ + at specialize.arg(0) +def _raw_memcopy_tp(TPP, source, dest): + # in its own function: LONGLONG may make the whole function jit-opaque + rffi.cast(TPP, dest)[0] = rffi.cast(TPP, source)[0] + def _raw_memcopy(source, dest, size): if jit.isconstant(size): # for the JIT: first handle the case where 'size' is known to be # a constant equal to 1, 2, 4, 8 for TP, TPP in _prim_unsigned_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, dest)[0] = rffi.cast(TPP, source)[0] + _raw_memcopy_tp(TPP, source, dest) return _raw_memcopy_opaque(source, dest, size) @@ -287,10 +302,15 @@ llmemory.cast_ptr_to_adr(dest) + zero, size * llmemory.sizeof(lltype.Char)) + at specialize.arg(0, 1) +def _raw_memclear_tp(TP, TPP, dest): + # in its own function: LONGLONG may make the whole function jit-opaque + rffi.cast(TPP, dest)[0] = rffi.cast(TP, 0) + def _raw_memclear(dest, size): # for now, only supports the cases of size = 1, 2, 4, 8 for TP, TPP in _prim_unsigned_types: if size == rffi.sizeof(TP): - rffi.cast(TPP, dest)[0] = rffi.cast(TP, 0) + _raw_memclear_tp(TP, TPP, dest) return raise NotImplementedError("bad clear size") diff --git a/pypy/module/_io/__init__.py b/pypy/module/_io/__init__.py --- a/pypy/module/_io/__init__.py +++ b/pypy/module/_io/__init__.py @@ -30,5 +30,5 @@ def shutdown(self, space): # at shutdown, flush all open streams. Ignore I/O errors. - from pypy.module._io.interp_iobase import get_autoflushher - get_autoflushher(space).flush_all(space) + from pypy.module._io.interp_iobase import get_autoflusher + get_autoflusher(space).flush_all(space) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -47,7 +47,7 @@ self.w_dict = space.newdict() self.__IOBase_closed = False self.streamholder = None # needed by AutoFlusher - get_autoflushher(space).add(self) + get_autoflusher(space).add(self) def getdict(self, space): return self.w_dict @@ -118,7 +118,7 @@ space.call_method(self, "flush") finally: self.__IOBase_closed = True - get_autoflushher(space).remove(self) + get_autoflusher(space).remove(self) def _dealloc_warn_w(self, space, w_source): """Called when the io is implicitly closed via the deconstructor""" @@ -403,5 +403,5 @@ else: streamholder.autoflush(space) -def get_autoflushher(space): +def get_autoflusher(space): return space.fromcache(AutoFlusher) diff --git a/pypy/module/_random/interp_random.py b/pypy/module/_random/interp_random.py --- a/pypy/module/_random/interp_random.py +++ b/pypy/module/_random/interp_random.py @@ -31,8 +31,8 @@ if space.isinstance_w(w_n, space.w_int): w_n = space.abs(w_n) else: - # XXX not perfectly like CPython - w_n = space.abs(space.hash(w_n)) + n = space.hash_w(w_n) + w_n = space.wrap(r_uint(n)) key = [] w_one = space.newint(1) w_two = space.newint(2) diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -42,13 +42,14 @@ rnd1.setstate((-1, ) * 624 + (0, )) def test_seed(self): - import _random + import _random, sys rnd = _random.Random() rnd.seed() different_nums = [] + mask = sys.maxint * 2 + 1 for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]: nums = [] - for o in [obj, hash(obj), -hash(obj)]: + for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]: rnd.seed(o) nums.append([rnd.random() for i in range(100)]) n1 = nums[0] diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -119,6 +119,12 @@ """) def test_array_of_floats(self): + try: + from __pypy__ import jit_backend_features + if 'singlefloats' not in jit_backend_features: + py.test.skip("test requres singlefloats support from the JIT backend") + except ImportError: + pass def main(): from array import array img = array('f', [21.5]*1000) diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -230,6 +230,17 @@ pt = POINT(y=2, x=1) assert (pt.x, pt.y) == (1, 2) + def test_subclass_initializer(self): + class POINT(Structure): + _fields_ = [("x", c_int), ("y", c_int)] + + class POSITION(POINT): + # A subclass without _fields_ + pass + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) + + def test_invalid_field_types(self): class POINT(Structure): pass @@ -533,6 +544,7 @@ raises(AttributeError, setattr, X, "_fields_", []) Y.__fields__ = [] + class TestPatologicalCases(BaseCTypesTestChecker): def test_structure_overloading_getattr(self): class X(Structure): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -223,7 +223,7 @@ def str_title__String(space, w_self): input = w_self._value builder = StringBuilder(len(input)) - prev_letter=' ' + prev_letter = ' ' for pos in range(len(input)): ch = input[pos] @@ -427,7 +427,7 @@ space.wrap("rjust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self = d * fillchar + u_self @@ -443,7 +443,7 @@ space.wrap("ljust() argument 2 must be a single character")) d = u_arg - len(u_self) - if d>0: + if d > 0: fillchar = fillchar[0] # annotator hint: it's a single character u_self += d * fillchar @@ -535,7 +535,7 @@ def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.find(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -545,7 +545,7 @@ def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) res = self.rfind(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, @@ -769,7 +769,7 @@ while 1: #no sophisticated linebreak support now, '\r' just for passing adapted CPython test if u_token[offset-1] == "\n" or u_token[offset-1] == "\r": - break; + break distance += 1 offset -= 1 if offset == 0: @@ -779,7 +779,7 @@ #print '' % (offset, distance, u_tabsize, u_token) distance = (u_tabsize-distance) % u_tabsize if distance == 0: - distance=u_tabsize + distance = u_tabsize return distance @@ -801,14 +801,14 @@ for token in split: #print "%d#%d -%s-" % (_tabindent(oldtoken,u_tabsize), u_tabsize, token) - u_expanded += " " * _tabindent(oldtoken,u_tabsize) + token + u_expanded += " " * _tabindent(oldtoken, u_tabsize) + token oldtoken = token return wrapstr(space, u_expanded) def str_splitlines__String_ANY(space, w_self, w_keepends): - u_keepends = space.int_w(w_keepends) # truth value, but type checked + u_keepends = space.int_w(w_keepends) # truth value, but type checked data = w_self._value selflen = len(data) strs_w = [] @@ -917,7 +917,6 @@ return space.wrap(ord(str[ival])) def getitem__String_Slice(space, w_str, w_slice): - w = space.wrap s = w_str._value length = len(s) start, stop, step, sl = w_slice.indices4(space, length) diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -926,6 +926,9 @@ def test_setitem_slice_performance(self): # because of a complexity bug, this used to take forever on a # translated pypy. On CPython2.6 -A, it takes around 5 seconds. + import platform + if platform.machine().startswith('arm'): + skip("consumes too much memory for most ARM machines") if self.runappdirect: count = 16*1024*1024 else: diff --git a/pypy/pytest-A.py b/pypy/pytest-A.py --- a/pypy/pytest-A.py +++ b/pypy/pytest-A.py @@ -6,6 +6,7 @@ 'interpreter/pyparser/test', 'interpreter/test', 'interpreter/test2', + 'module/test_lib_pypy', 'objspace/std/test', ], } diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py --- a/pypy/tool/jitlogparser/test/test_parser.py +++ b/pypy/tool/jitlogparser/test/test_parser.py @@ -4,7 +4,7 @@ parse_log_counts) from pypy.tool.jitlogparser.storage import LoopStorage import py, sys -from rpython.jit.backend.detect_cpu import autodetect_main_model +from rpython.jit.backend.detect_cpu import autodetect def parse(input, **kwds): return SimpleParser.parse_from_input(input, **kwds) @@ -189,7 +189,7 @@ assert chunk.bytecode_name.startswith('StrLiteralSearch') def test_parsing_assembler(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') backend_dump = "554889E5534154415541564157488DA500000000488B042590C5540148C7042590C554010000000048898570FFFFFF488B042598C5540148C7042598C554010000000048898568FFFFFF488B0425A0C5540148C70425A0C554010000000048898560FFFFFF488B0425A8C5540148C70425A8C554010000000048898558FFFFFF4C8B3C2550525B0149BB30E06C96FC7F00004D8B334983C60149BB30E06C96FC7F00004D89334981FF102700000F8D000000004983C7014C8B342580F76A024983EE014C89342580F76A024983FE000F8C00000000E9AEFFFFFF488B042588F76A024829E0483B042580EC3C01760D49BB05F30894FC7F000041FFD3554889E5534154415541564157488DA550FFFFFF4889BD70FFFFFF4889B568FFFFFF48899560FFFFFF48898D58FFFFFF4D89C7E954FFFFFF49BB00F00894FC7F000041FFD34440484C3D030300000049BB00F00894FC7F000041FFD34440484C3D070304000000" dump_start = 0x7f3b0b2e63d5 @@ -218,7 +218,7 @@ assert 'jmp' in loop.operations[-1].asm def test_parsing_arm_assembler(): - if not autodetect_main_model() == 'arm': + if not autodetect().startswith('arm'): py.test.skip('ARM only test') backend_dump = "F04F2DE9108B2DED2CD04DE20DB0A0E17CC302E3DFC040E300409CE5085084E2086000E3006084E504B084E500508CE508D04BE20000A0E10000A0E1B0A10DE30EA044E300A09AE501A08AE2B0910DE30E9044E300A089E5C0910DE30E9044E3009099E5019089E2C0A10DE30EA044E300908AE5010050E1700020E124A092E500C08AE00C90DCE5288000E3090058E10180A0030080A013297000E3090057E10170A0030070A013077088E1200059E30180A0030080A013099049E2050059E30190A0330090A023099088E1000059E30190A0130090A003099087E1000059E3700020E1010080E204200BE5D0210DE30E2044E3002092E5012082E2D0910DE30E9044E3002089E5010050E1700020E100C08AE00C90DCE5282000E3090052E10120A0030020A013297000E3090057E10170A0030070A013077082E1200059E30120A0030020A013099049E2050059E30190A0330090A023099082E1000059E30190A0130090A003099087E1000059E3700020E1010080E20D005BE10FF0A0A1700020E1D8FFFFEA68C100E301C04BE33CFF2FE105010803560000000000000068C100E301C04BE33CFF2FE105010803570000000000000068C100E301C04BE33CFF2FE105014003580000000000000068C100E301C04BE33CFF2FE1050140035900000000000000" dump_start = int(-0x4ffee930) @@ -272,7 +272,7 @@ def test_import_log(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest.log'))) @@ -281,7 +281,7 @@ assert 'jge' in loops[0].operations[3].asm def test_import_log_2(): - if not autodetect_main_model() == 'x86': + if not autodetect().startswith('x86'): py.test.skip('x86 only test') _, loops = import_log(str(py.path.local(__file__).join('..', 'logtest2.log'))) diff --git a/rpython/jit/backend/arm/test/test_fficall.py b/rpython/jit/backend/arm/test/test_fficall.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/test/test_fficall.py @@ -0,0 +1,23 @@ +import py +from rpython.jit.metainterp.test import test_fficall +from rpython.jit.backend.arm.test.support import JitARMMixin + +class TestFfiCall(JitARMMixin, test_fficall.FfiCallTests): + # for the individual tests see + # ====> ../../../metainterp/test/test_fficall.py + + def _add_libffi_types_to_ll2types_maybe(self): + # this is needed by test_guard_not_forced_fails, because it produces a + # loop which reads the value of types.* in a variable, then a guard + # fail and we switch to blackhole: the problem is that at this point + # the blackhole interp has a real integer, but it needs to convert it + # back to a lltype pointer (which is handled by ll2ctypes, deeply in + # the logic). The workaround is to teach ll2ctypes in advance which + # are the addresses of the various types.* structures. + # Try to comment this code out and run the test to see how it fails :) + from rpython.rtyper.lltypesystem import rffi, lltype, ll2ctypes + from rpython.rlib.jit_libffi import types + for key, value in types.__dict__.iteritems(): + if isinstance(value, lltype._ptr): + addr = rffi.cast(lltype.Signed, value) + ll2ctypes._int2obj[addr] = value diff --git a/rpython/jit/backend/detect_cpu.py b/rpython/jit/backend/detect_cpu.py --- a/rpython/jit/backend/detect_cpu.py +++ b/rpython/jit/backend/detect_cpu.py @@ -10,31 +10,31 @@ pass -def detect_main_model_and_size_from_platform(): +MODEL_X86 = 'x86' +MODEL_X86_NO_SSE2 = 'x86-without-sse2' +MODEL_X86_64 = 'x86-64' +MODEL_ARM = 'arm' +MODEL_PPC_64 = 'ppc-64' +# don't use '_' in the model strings; they are replaced by '-' + + +def detect_model_from_c_compiler(): # based on http://sourceforge.net/p/predef/wiki/Architectures/ mapping = { - ('x86', '64'): [ - '__amd64__', '__amd64', '__x86_64__', '__x86_64', # AMD64 - ], - ('arm', '32'): ['__arm__', '__thumb__'], - ('x86', '32'): ['i386', '__i386', '__i386__', '__i686__',], - ('ppc', '64'): ['__powerpc64__'], + MODEL_X86_64: ['__amd64__', '__amd64', '__x86_64__', '__x86_64'], + MODEL_ARM: ['__arm__', '__thumb__'], + MODEL_X86: ['i386', '__i386', '__i386__', '__i686__'], + MODEL_PPC_64: ['__powerpc64__'], } for k, v in mapping.iteritems(): for macro in v: if not getdefined(macro, ''): continue - return '_'.join(k) + return k raise ProcessorAutodetectError, "Cannot detect processor using compiler macros" -def detect_main_model_from_platform(): - return detect_main_model_and_size_from_platform()[0] - - -def autodetect_main_model(): - if not is_host_build(): - return detect_main_model_from_platform() +def detect_model_from_host_platform(): mach = None try: import platform @@ -44,67 +44,64 @@ if not mach: platform = sys.platform.lower() if platform.startswith('win'): # assume an Intel Windows - return 'x86' + return MODEL_X86 # assume we have 'uname' mach = os.popen('uname -m', 'r').read().strip() if not mach: raise ProcessorAutodetectError, "cannot run 'uname -m'" - try: - return {'i386': 'x86', - 'i486': 'x86', - 'i586': 'x86', - 'i686': 'x86', - 'i86pc': 'x86', # Solaris/Intel - 'x86': 'x86', # Apple - 'Power Macintosh': 'ppc', - 'x86_64': 'x86', - 'amd64': 'x86', # freebsd - 'AMD64': 'x86', # win64 - 'armv7l': 'arm', - 'armv6l': 'arm', - }[mach] - except KeyError: - return mach + # + result ={'i386': MODEL_X86, + 'i486': MODEL_X86, + 'i586': MODEL_X86, + 'i686': MODEL_X86, + 'i86pc': MODEL_X86, # Solaris/Intel + 'x86': MODEL_X86, # Apple + 'Power Macintosh': MODEL_PPC_64, + 'x86_64': MODEL_X86, + 'amd64': MODEL_X86, # freebsd + 'AMD64': MODEL_X86, # win64 + 'armv7l': MODEL_ARM, + 'armv6l': MODEL_ARM, + }[mach] + # + if result.startswith('x86'): + if sys.maxint == 2**63-1: + result = MODEL_X86_64 + else: + assert sys.maxint == 2**31-1 + from rpython.jit.backend.x86.detect_sse2 import detect_sse2 + if detect_sse2(): + result = MODEL_X86 + else: + result = MODEL_X86_NO_SSE2 + # + if result.startswith('arm'): + from rpython.jit.backend.arm.detect import detect_float + assert detect_float(), 'the JIT-compiler requires a vfp unit' + # + return result -def autodetect_main_model_and_size(): - if not is_host_build(): - return detect_main_model_and_size_from_platform() - model = autodetect_main_model() - if sys.maxint == 2**31-1: - model += '_32' - elif sys.maxint == 2**63-1: - model += '_64' - else: - raise AssertionError, "bad value for sys.maxint" - return model def autodetect(): - model = autodetect_main_model() - if sys.maxint == 2**63-1: - model += '_64' + if not is_host_build(): + return detect_model_from_c_compiler() else: - assert sys.maxint == 2**31-1 - if model == 'x86': - from rpython.jit.backend.x86.detect_sse2 import detect_sse2 - if not detect_sse2(): - model = 'x86-without-sse2' - if model.startswith('arm'): - from rpython.jit.backend.arm.detect import detect_hardfloat, detect_float - assert detect_float(), 'the JIT-compiler requires a vfp unit' - return model + return detect_model_from_host_platform() + def getcpuclassname(backend_name="auto"): if backend_name == "auto": backend_name = autodetect() - if backend_name == 'x86': + backend_name = backend_name.replace('_', '-') + if backend_name == MODEL_X86: return "rpython.jit.backend.x86.runner", "CPU" - elif backend_name == 'x86-without-sse2': + elif backend_name == MODEL_X86_NO_SSE2: return "rpython.jit.backend.x86.runner", "CPU386_NO_SSE2" - elif backend_name == 'x86_64': + elif backend_name == MODEL_X86_64: return "rpython.jit.backend.x86.runner", "CPU_X86_64" - elif backend_name == 'cli': - return "rpython.jit.backend.cli.runner", "CliCPU" - elif backend_name.startswith('arm'): + #elif backend_name == 'cli': + # return "rpython.jit.backend.cli.runner", "CliCPU" + elif backend_name == MODEL_ARM: return "rpython.jit.backend.arm.runner", "CPU_ARM" else: raise ProcessorAutodetectError, ( @@ -115,6 +112,22 @@ mod = __import__(modname, {}, {}, clsname) return getattr(mod, clsname) + +def getcpufeatures(backend_name="auto"): + """NOT_RPYTHON""" + cpucls = getcpuclass(backend_name) + return [attr[len('supports_'):] for attr in dir(cpucls) + if attr.startswith('supports_') + and getattr(cpucls, attr)] + if __name__ == '__main__': - print autodetect() - print getcpuclassname() + if len(sys.argv) > 1: + name = sys.argv[1] + x = name + else: + name = 'auto' + x = autodetect() + x = (x, getcpuclassname(name), getcpufeatures(name)) + print 'autodetect: ', x[0] + print 'getcpuclassname:', x[1] + print 'getcpufeatures: ', x[2] diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -18,7 +18,7 @@ from rpython.jit.codewriter import heaptracker, longlong from rpython.rlib import longlong2float from rpython.rlib.rarithmetic import intmask, is_valid_int -from rpython.jit.backend.detect_cpu import autodetect_main_model_and_size +from rpython.jit.backend.detect_cpu import autodetect from rpython.jit.backend.llsupport import jitframe @@ -3539,7 +3539,7 @@ looptoken) self.cpu.assembler.set_debug(True) # always on untranslated assert info.asmlen != 0 - cpuname = autodetect_main_model_and_size() + cpuname = autodetect() # XXX we have to check the precise assembler, otherwise # we don't quite know if borders are correct diff --git a/rpython/jit/backend/test/test_detect_cpu.py b/rpython/jit/backend/test/test_detect_cpu.py --- a/rpython/jit/backend/test/test_detect_cpu.py +++ b/rpython/jit/backend/test/test_detect_cpu.py @@ -28,6 +28,13 @@ assert issubclass(cpu, AbstractCPU) -def test_detect_main_model_and_size_from_platform(): - info = autodetect_main_model_and_size() - assert detect_main_model_and_size_from_platform() == info +def test_detect_model_from_c_compiler(): + info1 = detect_model_from_host_platform() + info2 = detect_model_from_c_compiler() + assert info1 == info2 + +def test_getcpufeatures(): + features = getcpufeatures() + assert isinstance(features, list) + for x in features: + assert x in ['floats', 'singlefloats', 'longlong'] diff --git a/rpython/jit/backend/tool/viewcode.py b/rpython/jit/backend/tool/viewcode.py --- a/rpython/jit/backend/tool/viewcode.py +++ b/rpython/jit/backend/tool/viewcode.py @@ -50,9 +50,12 @@ def machine_code_dump(data, originaddr, backend_name, label_list=None): objdump_backend_option = { 'x86': 'i386', + 'x86-without-sse2': 'i386', 'x86_32': 'i386', 'x86_64': 'x86-64', + 'x86-64': 'x86-64', 'i386': 'i386', + 'arm': 'arm', 'arm_32': 'arm', } cmd = find_objdump() diff --git a/rpython/jit/backend/x86/test/conftest.py b/rpython/jit/backend/x86/test/conftest.py --- a/rpython/jit/backend/x86/test/conftest.py +++ b/rpython/jit/backend/x86/test/conftest.py @@ -3,7 +3,7 @@ cpu = detect_cpu.autodetect() def pytest_runtest_setup(item): - if cpu not in ('x86', 'x86_64'): + if not cpu.startswith('x86'): py.test.skip("x86/x86_64 tests skipped: cpu is %r" % (cpu,)) if cpu == 'x86_64': if os.name == "nt": diff --git a/rpython/memory/gctransform/transform.py b/rpython/memory/gctransform/transform.py --- a/rpython/memory/gctransform/transform.py +++ b/rpython/memory/gctransform/transform.py @@ -281,11 +281,11 @@ def finish_helpers(self, backendopt=True): if self.translator is not None: self.mixlevelannotator.finish_annotate() - self.finished_helpers = True if self.translator is not None: self.mixlevelannotator.finish_rtype() if backendopt: self.mixlevelannotator.backend_optimize() + self.finished_helpers = True # Make sure that the database also sees all finalizers now. # It is likely that the finalizers need special support there newgcdependencies = self.ll_finalizers_ptrs diff --git a/rpython/translator/c/gcc/test/conftest.py b/rpython/translator/c/gcc/test/conftest.py --- a/rpython/translator/c/gcc/test/conftest.py +++ b/rpython/translator/c/gcc/test/conftest.py @@ -2,5 +2,5 @@ from rpython.jit.backend import detect_cpu cpu = detect_cpu.autodetect() def pytest_runtest_setup(item): - if cpu not in ('x86', 'x86_64'): + if not cpu.startswith('x86'): py.test.skip("x86 directory skipped: cpu is %r" % (cpu,)) diff --git a/rpython/translator/goal/translate.py b/rpython/translator/goal/translate.py --- a/rpython/translator/goal/translate.py +++ b/rpython/translator/goal/translate.py @@ -147,6 +147,10 @@ else: show_help(translateconfig, opt_parser, None, config) + # print the version of the host + # (if it's PyPy, it includes the hg checksum) + log.info(sys.version) + # apply the platform settings set_platform(config) diff --git a/testrunner/runner.py b/testrunner/runner.py --- a/testrunner/runner.py +++ b/testrunner/runner.py @@ -329,7 +329,7 @@ self.collect_one_testdir(testdirs, reldir, [self.reltoroot(t) for t in entries if self.is_test_py_file(t)]) - return + break for p1 in entries: if p1.check(dir=1, link=0): From noreply at buildbot.pypy.org Wed May 8 08:54:11 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 8 May 2013 08:54:11 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix copy.copy() on generator objects to make sure they get their own Message-ID: <20130508065411.2EEDA1C021A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63906:b3975062187f Date: 2013-05-08 08:53 +0200 http://bitbucket.org/pypy/pypy/changeset/b3975062187f/ Log: Fix copy.copy() on generator objects to make sure they get their own frame too, rather than sharing it with the original generator (which crashes completely). Of limited use (see comments in the test). diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -27,7 +27,7 @@ new_inst = mod.get('generator_new') w = space.wrap if self.frame: - w_frame = w(self.frame) + w_frame = self.frame._reduce_state(space) else: w_frame = space.w_None @@ -36,7 +36,20 @@ w(self.running), ] - return space.newtuple([new_inst, space.newtuple(tup)]) + return space.newtuple([new_inst, space.newtuple([]), + space.newtuple(tup)]) + + def descr__setstate__(self, space, w_args): + from rpython.rlib.objectmodel import instantiate + args_w = space.unpackiterable(w_args) + w_framestate, w_running = args_w + if space.is_w(w_framestate, space.w_None): + self.frame = None + else: + frame = instantiate(space.FrameClass) # XXX fish + frame.descr__setstate__(space, w_framestate) + GeneratorIterator.__init__(self, frame) + self.running = self.space.is_true(w_running) def descr__iter__(self): """x.__iter__() <==> iter(x)""" diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -16,10 +16,9 @@ from rpython.tool.stdlib_opcode import host_bytecode_spec # Define some opcodes used -g = globals() for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY POP_BLOCK END_FINALLY'''.split(): - g[op] = stdlib_opcode.opmap[op] + globals()[op] = stdlib_opcode.opmap[op] HAVE_ARGUMENT = stdlib_opcode.HAVE_ARGUMENT class PyFrame(eval.Frame): @@ -304,11 +303,17 @@ @jit.dont_look_inside def descr__reduce__(self, space): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('frame_new') - w = space.wrap + w_tup_state = self._reduce_state(space) + nt = space.newtuple + return nt([new_inst, nt([]), w_tup_state]) + + @jit.dont_look_inside + def _reduce_state(self, space): + from pypy.module._pickle_support import maker # helper fns + w = space.wrap nt = space.newtuple cells = self._getcells() @@ -359,8 +364,7 @@ w(self.instr_prev_plus_one), w_cells, ] - - return nt([new_inst, nt([]), nt(tup_state)]) + return nt(tup_state) @jit.dont_look_inside def descr__setstate__(self, space, w_args): diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py --- a/pypy/interpreter/test/test_zzpickle_and_slow.py +++ b/pypy/interpreter/test/test_zzpickle_and_slow.py @@ -485,3 +485,68 @@ pckl = pickle.dumps(pack.mod) result = pickle.loads(pckl) assert pack.mod is result + + +class AppTestGeneratorCloning: + + def setup_class(cls): + try: + cls.space.appexec([], """(): + def f(): yield 42 + f().__reduce__() + """) + except TypeError, e: + if 'pickle generator' not in str(e): + raise + py.test.skip("Frames can't be __reduce__()-ed") + + def test_deepcopy_generator(self): + import copy + + def f(n): + for i in range(n): + yield 42 + i + g = f(4) + g2 = copy.deepcopy(g) + res = g.next() + assert res == 42 + res = g2.next() + assert res == 42 + g3 = copy.deepcopy(g) + res = g.next() + assert res == 43 + res = g2.next() + assert res == 43 + res = g3.next() + assert res == 43 + + def test_shallowcopy_generator(self): + """Note: shallow copies of generators are often confusing. + To start with, 'for' loops have an iterator that will not + be copied, and so create tons of confusion. + """ + import copy + + def f(n): + while n > 0: + yield 42 + n + n -= 1 + g = f(2) + g2 = copy.copy(g) + res = g.next() + assert res == 44 + res = g2.next() + assert res == 44 + g3 = copy.copy(g) + res = g.next() + assert res == 43 + res = g2.next() + assert res == 43 + res = g3.next() + assert res == 43 + g4 = copy.copy(g2) + for i in range(2): + raises(StopIteration, g.next) + raises(StopIteration, g2.next) + raises(StopIteration, g3.next) + raises(StopIteration, g4.next) diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -913,6 +913,7 @@ GeneratorIterator.typedef = TypeDef("generator", __repr__ = interp2app(GeneratorIterator.descr__repr__), __reduce__ = interp2app(GeneratorIterator.descr__reduce__), + __setstate__ = interp2app(GeneratorIterator.descr__setstate__), next = interp2app(GeneratorIterator.descr_next, descrmismatch='next'), send = interp2app(GeneratorIterator.descr_send, diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -59,11 +59,8 @@ tb = instantiate(PyTraceback) return space.wrap(tb) - at unwrap_spec(running=int) -def generator_new(space, w_frame, running): - frame = space.interp_w(PyFrame, w_frame, can_be_None=True) - new_generator = GeneratorIterator(frame) - new_generator.running = running +def generator_new(space): + new_generator = instantiate(GeneratorIterator) return space.wrap(new_generator) @unwrap_spec(current=int, remaining=int, step=int) From noreply at buildbot.pypy.org Wed May 8 10:03:54 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 8 May 2013 10:03:54 +0200 (CEST) Subject: [pypy-commit] buildbot default: set maxbuilds for raspberry-pi buildslaves Message-ID: <20130508080354.EDDAC1C0307@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r816:0255e0434ee6 Date: 2013-05-08 10:03 +0200 http://bitbucket.org/pypy/buildbot/changeset/0255e0434ee6/ Log: set maxbuilds for raspberry-pi buildslaves diff --git a/bot2/pypybuildbot/master.py b/bot2/pypybuildbot/master.py --- a/bot2/pypybuildbot/master.py +++ b/bot2/pypybuildbot/master.py @@ -184,9 +184,12 @@ CPYTHON_64 = "cpython-2-benchmark-x86-64" -extra_opts= {'xerxes': {'keepalive_interval': 15}, +extra_opts = {'xerxes': {'keepalive_interval': 15}, 'aurora': {'max_builds': 1}, 'salsa': {'max_builds': 1}, + 'hhu-raspberry-pi': {'max_builds': 1}, + 'hhu-pypy-pi': {'max_builds': 1}, + 'hhu-pypy-pi2': {'max_builds': 1}, } BuildmasterConfig = { From noreply at buildbot.pypy.org Wed May 8 14:55:07 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 8 May 2013 14:55:07 +0200 (CEST) Subject: [pypy-commit] pypy default: split another function for JIT backends that don't support Message-ID: <20130508125507.0C8441C0307@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63907:5fc2df623164 Date: 2013-05-08 14:54 +0200 http://bitbucket.org/pypy/pypy/changeset/5fc2df623164/ Log: split another function for JIT backends that don't support floats/longlongs/etc. 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 @@ -235,11 +235,17 @@ eci = ExternalCompilationInfo(post_include_bits=[""" #define pypy__is_nonnull_longdouble(x) ((x) != 0.0) """]) -is_nonnull_longdouble = rffi.llexternal( +_is_nonnull_longdouble = rffi.llexternal( "pypy__is_nonnull_longdouble", [rffi.LONGDOUBLE], lltype.Bool, compilation_info=eci, _nowrapper=True, elidable_function=True, sandboxsafe=True) +# split here for JIT backends that don't support floats/longlongs/etc. +def is_nonnull_longdouble(cdata): + return _is_nonnull_longdouble(read_raw_longdouble_data(cdata)) +def is_nonnull_float(cdata, size): + return read_raw_float_data(cdata, size) != 0.0 + def object_as_bool(space, w_ob): # convert and cast a Python object to a boolean. Accept an integer # or a float object, up to a CData 'long double'. @@ -254,10 +260,9 @@ is_cdata = isinstance(w_ob, W_CData) if is_cdata and isinstance(w_ob.ctype, W_CTypePrimitiveFloat): if isinstance(w_ob.ctype, W_CTypePrimitiveLongDouble): - result = is_nonnull_longdouble( - read_raw_longdouble_data(w_ob._cdata)) + result = is_nonnull_longdouble(w_ob._cdata) else: - result = read_raw_float_data(w_ob._cdata, w_ob.ctype.size) != 0.0 + result = is_nonnull_float(w_ob._cdata, w_ob.ctype.size) keepalive_until_here(w_ob) return result # From noreply at buildbot.pypy.org Wed May 8 17:10:33 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 8 May 2013 17:10:33 +0200 (CEST) Subject: [pypy-commit] pypy default: No-op. Message-ID: <20130508151033.16C1C1C0135@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63908:31f9068a63bf Date: 2013-05-08 17:09 +0200 http://bitbucket.org/pypy/pypy/changeset/31f9068a63bf/ Log: No-op. diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -30,14 +30,14 @@ return False if getattr(func, '_gctransformer_hint_close_stack_', False): return True - return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph, - seen) + return graphanalyze.BoolGraphAnalyzer.analyze_direct_call(self, graph, + seen) def analyze_external_call(self, op, seen=None): funcobj = op.args[0].value._obj if getattr(funcobj, 'random_effects_on_gcobjs', False): return True - return graphanalyze.GraphAnalyzer.analyze_external_call(self, op, - seen) + return graphanalyze.BoolGraphAnalyzer.analyze_external_call(self, op, + seen) def analyze_simple_operation(self, op, graphinfo): if op.opname in ('malloc', 'malloc_varsize'): flags = op.args[1].value From noreply at buildbot.pypy.org Wed May 8 17:10:34 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 8 May 2013 17:10:34 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a test. It fails. That's a bad sign. Message-ID: <20130508151034.65C591C05B7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63909:e65054b55bef Date: 2013-05-08 17:09 +0200 http://bitbucket.org/pypy/pypy/changeset/e65054b55bef/ Log: Add a test. It fails. That's a bad sign. diff --git a/rpython/translator/backendopt/test/test_graphanalyze.py b/rpython/translator/backendopt/test/test_graphanalyze.py new file mode 100644 --- /dev/null +++ b/rpython/translator/backendopt/test/test_graphanalyze.py @@ -0,0 +1,51 @@ +import random +from rpython.tool.algo.unionfind import UnionFind +from rpython.translator.backendopt.graphanalyze import Dependency +from rpython.translator.backendopt.graphanalyze import DependencyTracker + + +class FakeGraphAnalyzer: + def __init__(self): + self._analyzed_calls = UnionFind(lambda graph: Dependency(self)) + + @staticmethod + def bottom_result(): + return 0 + + @staticmethod + def join_two_results(result1, result2): + return result1 | result2 + + +def test_random_graphs(): + for _ in range(100): + N = 10 + edges = [(random.randrange(N), random.randrange(N)) + for i in range(N*N//3)] + + def expected(node1): + prev = set() + seen = set([node1]) + while len(seen) > len(prev): + prev = set(seen) + for a, b in edges: + if a in seen: + seen.add(b) + return sum([1 << n for n in seen]) + + def rectrack(n, tracker): + if not tracker.enter(n): + return tracker.get_cached_result(n) + result = 1 << n + for a, b in edges: + if a == n: + result |= rectrack(b, tracker) + tracker.leave_with(result) + return result + + analyzer = FakeGraphAnalyzer() + for n in range(N): + tracker = DependencyTracker(analyzer) + method1 = rectrack(n, tracker) + method2 = expected(n) + assert method1 == method2 From noreply at buildbot.pypy.org Wed May 8 17:35:52 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 17:35:52 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: skip this test Message-ID: <20130508153552.BB1391C05B7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r63910:608abaa6c24f Date: 2013-05-08 13:55 +0200 http://bitbucket.org/pypy/pypy/changeset/608abaa6c24f/ Log: skip this test diff --git a/rpython/jit/metainterp/test/test_recursive.py b/rpython/jit/metainterp/test/test_recursive.py --- a/rpython/jit/metainterp/test/test_recursive.py +++ b/rpython/jit/metainterp/test/test_recursive.py @@ -800,6 +800,7 @@ assert res == main(0) def test_directly_call_assembler_virtualizable_reset_token(self): + py.test.skip("not applicable any more, I think") from rpython.rtyper.lltypesystem import lltype from rpython.rlib.debug import llinterpcall From noreply at buildbot.pypy.org Wed May 8 17:35:54 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 17:35:54 +0200 (CEST) Subject: [pypy-commit] pypy default: A crude hack to disable libffi Message-ID: <20130508153554.01B581C05B7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63911:70a3ebe126b7 Date: 2013-05-08 17:33 +0200 http://bitbucket.org/pypy/pypy/changeset/70a3ebe126b7/ Log: A crude hack to disable libffi diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -64,6 +64,9 @@ else: separate_module_sources = [] +def setup_after_config(config): + pass + if not _WIN32: # On some platforms, we try to link statically libffi, which is small # anyway and avoids endless troubles for installing. On other platforms @@ -72,9 +75,13 @@ if _MAC_OS: pre_include_bits = ['#define MACOSX'] - else: + else: pre_include_bits = [] + def setup_after_config(config): + if config.translation.shared: + eci.link_files = [] + def find_libffi_a(): dirlist = platform.library_dirs_for_libffi_a() for dir in dirlist: @@ -357,7 +364,7 @@ lltype.Void) c_ffi_prep_closure = external('ffi_prep_closure', [FFI_CLOSUREP, FFI_CIFP, CALLBACK_TP, rffi.VOIDP], - rffi.INT) + rffi.INT) FFI_STRUCT_P = lltype.Ptr(lltype.Struct('FFI_STRUCT', ('ffistruct', FFI_TYPE_P.TO), diff --git a/rpython/translator/goal/translate.py b/rpython/translator/goal/translate.py --- a/rpython/translator/goal/translate.py +++ b/rpython/translator/goal/translate.py @@ -183,6 +183,13 @@ # perform checks (if any) on the final config final_check_config(config) + try: + from rpython.rlib import clibffi + except ImportError: + pass # too bad + else: + clibffi.setup_after_config(config) + return targetspec_dic, translateconfig, config, args def show_help(translateconfig, opt_parser, targetspec_dic, config): From noreply at buildbot.pypy.org Wed May 8 17:35:55 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 17:35:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Finish the commit - a hack to disable libffi.a when we're shared and use Message-ID: <20130508153555.42B1E1C05B7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63912:f58273adb93e Date: 2013-05-08 17:34 +0200 http://bitbucket.org/pypy/pypy/changeset/f58273adb93e/ Log: Finish the commit - a hack to disable libffi.a when we're shared and use the .so instead (but without a warning) diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -79,6 +79,8 @@ pre_include_bits = [] def setup_after_config(config): + # a crude hack - libffi.a might be compiled without -fPIC on certain + # platforms, just disable it when we've passed --shared if config.translation.shared: eci.link_files = [] From noreply at buildbot.pypy.org Wed May 8 17:35:56 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 17:35:56 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130508153556.7EA7D1C05B7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63913:669bd7955208 Date: 2013-05-08 17:34 +0200 http://bitbucket.org/pypy/pypy/changeset/669bd7955208/ Log: merge diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -22,6 +22,13 @@ # __________ Entry point __________ + +# register the minimal equivalent of running a small piece of code. This +# should be used as sparsely as possible, just to register callbacks + +def pypy_execute_source(source): + pass + def create_entry_point(space, w_dict): w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) @@ -34,8 +41,8 @@ from rpython.jit.backend.hlinfo import highleveljitinfo highleveljitinfo.sys_executable = argv[0] - #debug("entry point starting") - #for arg in argv: + #debug("entry point starting") + #for arg in argv: # debug(" argv -> " + arg) if len(argv) > 2 and argv[1] == '--heapsize': # Undocumented option, handled at interp-level. @@ -71,6 +78,7 @@ debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 return exitcode + return entry_point def call_finish(space): @@ -219,7 +227,7 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy, pypy_hooks return PyPyJitPolicy(pypy_hooks) - + def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy rebuild = import_from_lib_pypy('ctypes_config_cache/rebuild') From noreply at buildbot.pypy.org Wed May 8 17:35:57 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 17:35:57 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130508153557.A690B1C05B7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63914:01814fcfecd2 Date: 2013-05-08 17:34 +0200 http://bitbucket.org/pypy/pypy/changeset/01814fcfecd2/ Log: merge diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -30,14 +30,14 @@ return False if getattr(func, '_gctransformer_hint_close_stack_', False): return True - return graphanalyze.GraphAnalyzer.analyze_direct_call(self, graph, - seen) + return graphanalyze.BoolGraphAnalyzer.analyze_direct_call(self, graph, + seen) def analyze_external_call(self, op, seen=None): funcobj = op.args[0].value._obj if getattr(funcobj, 'random_effects_on_gcobjs', False): return True - return graphanalyze.GraphAnalyzer.analyze_external_call(self, op, - seen) + return graphanalyze.BoolGraphAnalyzer.analyze_external_call(self, op, + seen) def analyze_simple_operation(self, op, graphinfo): if op.opname in ('malloc', 'malloc_varsize'): flags = op.args[1].value diff --git a/rpython/translator/backendopt/test/test_graphanalyze.py b/rpython/translator/backendopt/test/test_graphanalyze.py new file mode 100644 --- /dev/null +++ b/rpython/translator/backendopt/test/test_graphanalyze.py @@ -0,0 +1,51 @@ +import random +from rpython.tool.algo.unionfind import UnionFind +from rpython.translator.backendopt.graphanalyze import Dependency +from rpython.translator.backendopt.graphanalyze import DependencyTracker + + +class FakeGraphAnalyzer: + def __init__(self): + self._analyzed_calls = UnionFind(lambda graph: Dependency(self)) + + @staticmethod + def bottom_result(): + return 0 + + @staticmethod + def join_two_results(result1, result2): + return result1 | result2 + + +def test_random_graphs(): + for _ in range(100): + N = 10 + edges = [(random.randrange(N), random.randrange(N)) + for i in range(N*N//3)] + + def expected(node1): + prev = set() + seen = set([node1]) + while len(seen) > len(prev): + prev = set(seen) + for a, b in edges: + if a in seen: + seen.add(b) + return sum([1 << n for n in seen]) + + def rectrack(n, tracker): + if not tracker.enter(n): + return tracker.get_cached_result(n) + result = 1 << n + for a, b in edges: + if a == n: + result |= rectrack(b, tracker) + tracker.leave_with(result) + return result + + analyzer = FakeGraphAnalyzer() + for n in range(N): + tracker = DependencyTracker(analyzer) + method1 = rectrack(n, tracker) + method2 = expected(n) + assert method1 == method2 From noreply at buildbot.pypy.org Wed May 8 17:39:27 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 8 May 2013 17:39:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Fixes the test, but maybe makes things slower. Message-ID: <20130508153927.5ECFD1C0135@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63915:3fb0e6c27959 Date: 2013-05-08 17:38 +0200 http://bitbucket.org/pypy/pypy/changeset/3fb0e6c27959/ Log: Fixes the test, but maybe makes things slower. diff --git a/rpython/translator/backendopt/graphanalyze.py b/rpython/translator/backendopt/graphanalyze.py --- a/rpython/translator/backendopt/graphanalyze.py +++ b/rpython/translator/backendopt/graphanalyze.py @@ -207,26 +207,29 @@ self.graph_results = analyzer._analyzed_calls # the current stack of graphs being analyzed self.current_stack = [] - self.current_stack_set = set() + #self.current_stack_set = set() def enter(self, graph): if graph not in self.graph_results: self.current_stack.append(graph) - self.current_stack_set.add(graph) + #self.current_stack_set.add(graph) self.graph_results.find(graph) return True else: - if graph in self.current_stack_set: - # found a cycle; merge all graphs in that cycle - i = len(self.current_stack) - 1 - while self.current_stack[i] is not graph: - self.graph_results.union(self.current_stack[i], graph) - i -= 1 + graph = self.graph_results.find_rep(graph) + for j in range(len(self.current_stack)): + othergraph = self.graph_results.find_rep(self.current_stack[j]) + if graph is othergraph: + # found a cycle; merge all graphs in that cycle + for i in range(j, len(self.current_stack)): + self.graph_results.union(self.current_stack[i], graph) + # done + break return False def leave_with(self, result): graph = self.current_stack.pop() - self.current_stack_set.remove(graph) + #self.current_stack_set.remove(graph) dep = self.graph_results[graph] dep.merge_with_result(result) From noreply at buildbot.pypy.org Wed May 8 17:43:52 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 8 May 2013 17:43:52 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Fixes the test, but maybe makes things slower. Message-ID: <20130508154352.17E011C021A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r63916:eb5983d848f1 Date: 2013-05-08 17:38 +0200 http://bitbucket.org/pypy/pypy/changeset/eb5983d848f1/ Log: Fixes the test, but maybe makes things slower. (transplanted from 3fb0e6c27959e20cb2b71acebaea47846f24fa86) diff --git a/rpython/translator/backendopt/graphanalyze.py b/rpython/translator/backendopt/graphanalyze.py --- a/rpython/translator/backendopt/graphanalyze.py +++ b/rpython/translator/backendopt/graphanalyze.py @@ -207,26 +207,29 @@ self.graph_results = analyzer._analyzed_calls # the current stack of graphs being analyzed self.current_stack = [] - self.current_stack_set = set() + #self.current_stack_set = set() def enter(self, graph): if graph not in self.graph_results: self.current_stack.append(graph) - self.current_stack_set.add(graph) + #self.current_stack_set.add(graph) self.graph_results.find(graph) return True else: - if graph in self.current_stack_set: - # found a cycle; merge all graphs in that cycle - i = len(self.current_stack) - 1 - while self.current_stack[i] is not graph: - self.graph_results.union(self.current_stack[i], graph) - i -= 1 + graph = self.graph_results.find_rep(graph) + for j in range(len(self.current_stack)): + othergraph = self.graph_results.find_rep(self.current_stack[j]) + if graph is othergraph: + # found a cycle; merge all graphs in that cycle + for i in range(j, len(self.current_stack)): + self.graph_results.union(self.current_stack[i], graph) + # done + break return False def leave_with(self, result): graph = self.current_stack.pop() - self.current_stack_set.remove(graph) + #self.current_stack_set.remove(graph) dep = self.graph_results[graph] dep.merge_with_result(result) From noreply at buildbot.pypy.org Wed May 8 18:03:15 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 18:03:15 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a very minimal embedding API. Additionally, 'main' is an always on Message-ID: <20130508160315.E32F51C021A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63917:3bddab67a436 Date: 2013-05-08 18:01 +0200 http://bitbucket.org/pypy/pypy/changeset/3bddab67a436/ Log: Add a very minimal embedding API. Additionally, 'main' is an always on secondary entrypoint (because why not) diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -91,7 +91,7 @@ # itself needs the interp-level struct module # because 'P' is missing from the app-level one "_rawffi": [("objspace.usemodules.struct", True)], - "cpyext": [("translation.secondaryentrypoints", "cpyext"), + "cpyext": [("translation.secondaryentrypoints", "cpyext,main"), ("translation.shared", sys.platform == "win32")], } diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -23,18 +23,13 @@ # __________ Entry point __________ -# register the minimal equivalent of running a small piece of code. This -# should be used as sparsely as possible, just to register callbacks - -def pypy_execute_source(source): - pass - def create_entry_point(space, w_dict): - w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) - w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) - w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) - w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) - withjit = space.config.objspace.usemodules.pypyjit + if w_dict is not None: # for tests + w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) + w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) + w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) + w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) + withjit = space.config.objspace.usemodules.pypyjit def entry_point(argv): if withjit: @@ -79,7 +74,29 @@ return 1 return exitcode - return entry_point + # register the minimal equivalent of running a small piece of code. This + # should be used as sparsely as possible, just to register callbacks + + from rpython.rlib.entrypoint import entrypoint + from rpython.rtyper.lltypesystem import rffi + + @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') + def pypy_execute_source(ll_source): + source = rffi.charp2str(ll_source) + return _pypy_execute_source(source) + + w_globals = space.newdict() + + def _pypy_execute_source(source): + try: + space.exec_(source, w_globals, w_globals, filename='c callback') + except OperationError, e: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + + return entry_point, _pypy_execute_source # for tests def call_finish(space): space.finish() @@ -240,7 +257,7 @@ app = gateway.applevel(open(filename).read(), 'app_main.py', 'app_main') app.hidden_applevel = False w_dict = app.getwdict(space) - entry_point = create_entry_point(space, w_dict) + entry_point, _ = create_entry_point(space, w_dict) return entry_point, None, PyPyAnnotatorPolicy(single_space = space) diff --git a/pypy/interpreter/test2/test_targetpypy.py b/pypy/interpreter/test2/test_targetpypy.py --- a/pypy/interpreter/test2/test_targetpypy.py +++ b/pypy/interpreter/test2/test_targetpypy.py @@ -1,4 +1,4 @@ -from pypy.goal.targetpypystandalone import get_entry_point +from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point from pypy.config.pypyoption import get_pypy_config class TestTargetPyPy(object): @@ -6,3 +6,13 @@ config = get_pypy_config(translating=False) entry_point = get_entry_point(config)[0] entry_point(['pypy-c' , '-S', '-c', 'print 3']) + +def test_exeucte_source(space): + _, execute_source = create_entry_point(space, None) + execute_source("import sys; sys.modules['xyz'] = 3") + x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'], + space.wrap('modules')), + space.wrap('xyz'))) + assert x == 3 + execute_source("sys") + # did not crash - the same globals diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -149,7 +149,7 @@ StrOption("output", "Output file name", cmdline="--output"), StrOption("secondaryentrypoints", "Comma separated list of keys choosing secondary entrypoints", - cmdline="--entrypoints", default=""), + cmdline="--entrypoints", default="main"), BoolOption("dump_static_data_info", "Dump static data info", cmdline="--dump_static_data_info", diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -4,6 +4,8 @@ def entrypoint(key, argtypes, c_name=None, relax=False): """ Note: entrypoint should call llop.gc_stack_bottom on it's own. That's necessary for making it work with asmgcc and hence JIT + + if key == 'main' than it's included by default """ def deco(func): secondary_entrypoints.setdefault(key, []).append((func, argtypes)) From noreply at buildbot.pypy.org Wed May 8 18:03:17 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 18:03:17 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130508160317.5EF2E1C021A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63918:c5635f5e10d6 Date: 2013-05-08 18:02 +0200 http://bitbucket.org/pypy/pypy/changeset/c5635f5e10d6/ Log: merge diff --git a/rpython/translator/backendopt/graphanalyze.py b/rpython/translator/backendopt/graphanalyze.py --- a/rpython/translator/backendopt/graphanalyze.py +++ b/rpython/translator/backendopt/graphanalyze.py @@ -207,26 +207,29 @@ self.graph_results = analyzer._analyzed_calls # the current stack of graphs being analyzed self.current_stack = [] - self.current_stack_set = set() + #self.current_stack_set = set() def enter(self, graph): if graph not in self.graph_results: self.current_stack.append(graph) - self.current_stack_set.add(graph) + #self.current_stack_set.add(graph) self.graph_results.find(graph) return True else: - if graph in self.current_stack_set: - # found a cycle; merge all graphs in that cycle - i = len(self.current_stack) - 1 - while self.current_stack[i] is not graph: - self.graph_results.union(self.current_stack[i], graph) - i -= 1 + graph = self.graph_results.find_rep(graph) + for j in range(len(self.current_stack)): + othergraph = self.graph_results.find_rep(self.current_stack[j]) + if graph is othergraph: + # found a cycle; merge all graphs in that cycle + for i in range(j, len(self.current_stack)): + self.graph_results.union(self.current_stack[i], graph) + # done + break return False def leave_with(self, result): graph = self.current_stack.pop() - self.current_stack_set.remove(graph) + #self.current_stack_set.remove(graph) dep = self.graph_results[graph] dep.merge_with_result(result) From noreply at buildbot.pypy.org Wed May 8 18:10:40 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 18:10:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Shuffle stuff around so we don't have test2 any more Message-ID: <20130508161040.2EC821C0307@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63919:bf1f12fda345 Date: 2013-05-08 18:10 +0200 http://bitbucket.org/pypy/pypy/changeset/bf1f12fda345/ Log: Shuffle stuff around so we don't have test2 any more diff --git a/pypy/interpreter/test2/mymodule.py b/pypy/interpreter/test/mymodule.py rename from pypy/interpreter/test2/mymodule.py rename to pypy/interpreter/test/mymodule.py diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test/test_app_main.py rename from pypy/interpreter/test2/test_app_main.py rename to pypy/interpreter/test/test_app_main.py diff --git a/pypy/interpreter/test2/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py rename from pypy/interpreter/test2/test_targetpypy.py rename to pypy/interpreter/test/test_targetpypy.py diff --git a/pypy/interpreter/test2/__init__.py b/pypy/interpreter/test2/__init__.py deleted file mode 100644 --- a/pypy/interpreter/test2/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -#empty From noreply at buildbot.pypy.org Wed May 8 18:16:56 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 18:16:56 +0200 (CEST) Subject: [pypy-commit] pypy default: fix rpython Message-ID: <20130508161656.761F41C0307@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63920:8b833d24ae83 Date: 2013-05-08 18:15 +0200 http://bitbucket.org/pypy/pypy/changeset/8b833d24ae83/ Log: fix rpython diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -86,15 +86,20 @@ return _pypy_execute_source(source) w_globals = space.newdict() + space.setitem(w_globals, space.wrap('__builtins__'), + space.builtin_modules['__builtin__']) def _pypy_execute_source(source): try: - space.exec_(source, w_globals, w_globals, filename='c callback') + compiler = space.createcompiler() + stmt = compiler.compile(source, 'c callback', 'exec', 0) + stmt.exec_code(space, w_globals, w_globals) except OperationError, e: debug("OperationError:") debug(" operror-type: " + e.w_type.getname(space)) debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 + return 0 return entry_point, _pypy_execute_source # for tests From noreply at buildbot.pypy.org Wed May 8 18:24:28 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 18:24:28 +0200 (CEST) Subject: [pypy-commit] pypy default: oops Message-ID: <20130508162428.DDB731C021A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63921:624a417bffcf Date: 2013-05-08 18:23 +0200 http://bitbucket.org/pypy/pypy/changeset/624a417bffcf/ Log: oops diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -82,7 +82,7 @@ # a crude hack - libffi.a might be compiled without -fPIC on certain # platforms, just disable it when we've passed --shared if config.translation.shared: - eci.link_files = [] + eci.link_files = () def find_libffi_a(): dirlist = platform.library_dirs_for_libffi_a() From noreply at buildbot.pypy.org Wed May 8 19:16:11 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 19:16:11 +0200 (CEST) Subject: [pypy-commit] pypy default: automatically export all @entrypoints, not sure exactly if it works Message-ID: <20130508171611.145CC1C0307@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63922:1e3bae0b8ace Date: 2013-05-08 19:15 +0200 http://bitbucket.org/pypy/pypy/changeset/1e3bae0b8ace/ Log: automatically export all @entrypoints, not sure exactly if it works diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -7,12 +7,16 @@ if key == 'main' than it's included by default """ + from rpython.translator.cbuild import ExternalCompilationInfo + def deco(func): secondary_entrypoints.setdefault(key, []).append((func, argtypes)) if c_name is not None: func.c_name = c_name if relax: func.relax_sig_check = True + func._compilation_info = ExternalCompilationInfo( + export_symbols=[c_name or func.func_name]) return func return deco From noreply at buildbot.pypy.org Wed May 8 19:19:55 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 19:19:55 +0200 (CEST) Subject: [pypy-commit] pypy default: export also this Message-ID: <20130508171955.05FAC1C0135@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63923:6d23754a30c9 Date: 2013-05-08 19:19 +0200 http://bitbucket.org/pypy/pypy/changeset/6d23754a30c9/ Log: export also this diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -112,7 +112,7 @@ str(exename), args)) profdrv.probe(exename, args) return profdrv.after() - + class CBuilder(object): c_source_filename = None _compiled = False @@ -149,7 +149,7 @@ thread_enabled=self.config.translation.thread, sandbox=self.config.translation.sandbox) self.db = db - + # give the gc a chance to register interest in the start-up functions it # need (we call this for its side-effects of db.get()) list(db.gcpolicy.gc_startup_code()) @@ -257,7 +257,8 @@ if self.config.translation.shared: defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( - export_symbols=["pypy_main_startup"])) + export_symbols=["pypy_main_startup", + 'RPython_StartupCode'])) self.eci, cfile, extra = gen_source(db, modulename, targetdir, self.eci, defines=defines, split=self.split) @@ -622,7 +623,7 @@ if self.database.gcpolicy.need_no_typeptr(): pass # XXX gcc uses toooooons of memory??? else: - split_criteria_big = SPLIT_CRITERIA * 4 + split_criteria_big = SPLIT_CRITERIA * 4 # # All declarations From noreply at buildbot.pypy.org Wed May 8 19:24:25 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 8 May 2013 19:24:25 +0200 (CEST) Subject: [pypy-commit] pypy default: avoid the platform module at applevel Message-ID: <20130508172425.BF7BC1C0307@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63924:b191d9f8333c Date: 2013-05-08 10:23 -0700 http://bitbucket.org/pypy/pypy/changeset/b191d9f8333c/ Log: avoid the platform module at applevel diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -431,10 +431,12 @@ class AppTestW_ListObject(object): def setup_class(cls): + import platform import sys on_cpython = (cls.runappdirect and not hasattr(sys, 'pypy_translation_info')) cls.w_on_cpython = cls.space.wrap(on_cpython) + cls.w_on_arm = cls.space.wrap(platform.machine().startswith('arm')) cls.w_runappdirect = cls.space.wrap(cls.runappdirect) def test_getstrategyfromlist_w(self): @@ -948,8 +950,7 @@ def test_setitem_slice_performance(self): # because of a complexity bug, this used to take forever on a # translated pypy. On CPython2.6 -A, it takes around 5 seconds. - import platform - if platform.machine().startswith('arm'): + if self.on_arm: skip("consumes too much memory for most ARM machines") if self.runappdirect: count = 16*1024*1024 From noreply at buildbot.pypy.org Wed May 8 19:31:27 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 8 May 2013 19:31:27 +0200 (CEST) Subject: [pypy-commit] pypy default: fix import Message-ID: <20130508173127.1BC471C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r63925:712b0d30494a Date: 2013-05-08 10:30 -0700 http://bitbucket.org/pypy/pypy/changeset/712b0d30494a/ Log: fix import diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -7,7 +7,7 @@ if key == 'main' than it's included by default """ - from rpython.translator.cbuild import ExternalCompilationInfo + from rpython.translator.tool.cbuild import ExternalCompilationInfo def deco(func): secondary_entrypoints.setdefault(key, []).append((func, argtypes)) From noreply at buildbot.pypy.org Wed May 8 20:12:40 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 8 May 2013 20:12:40 +0200 (CEST) Subject: [pypy-commit] pypy py3k: 2to3 Message-ID: <20130508181240.DF1CB1C05B7@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63926:28b4dbf82ddf Date: 2013-05-08 11:11 -0700 http://bitbucket.org/pypy/pypy/changeset/28b4dbf82ddf/ Log: 2to3 diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -11,7 +11,7 @@ g = open(filename, 'w') print >> g, '''\ import sys -_size = 32 if sys.maxint <= 2**32 else 64 +_size = 32 if sys.maxsize <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib _mod = __import__("_%s_%%s_" %% (_size,), diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -46,7 +46,7 @@ rnd = _random.Random() rnd.seed() different_nums = [] - mask = sys.maxint * 2 + 1 + mask = sys.maxsize * 2 + 1 for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]: nums = [] for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]: From noreply at buildbot.pypy.org Wed May 8 20:48:10 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 20:48:10 +0200 (CEST) Subject: [pypy-commit] pypy default: dance a bit, so the RPython_StartupCode is called with correctly set stack bottom Message-ID: <20130508184810.5C23B1C0135@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63927:037ff5bf2cf9 Date: 2013-05-08 20:47 +0200 http://bitbucket.org/pypy/pypy/changeset/037ff5bf2cf9/ Log: dance a bit, so the RPython_StartupCode is called with correctly set stack bottom diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -83,6 +83,7 @@ # platforms, just disable it when we've passed --shared if config.translation.shared: eci.link_files = () + eci.libraries = ('ffi',) def find_libffi_a(): dirlist = platform.library_dirs_for_libffi_a() diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -2,7 +2,9 @@ import py import sys, os from rpython.rlib import exports +from rpython.rlib.entrypoint import entrypoint from rpython.rtyper.typesystem import getfunctionptr +from rpython.rtyper.lltypesystem import lltype, rffi from rpython.tool import runsubprocess from rpython.tool.nullpath import NullPyPathLocal from rpython.tool.udir import udir @@ -257,8 +259,7 @@ if self.config.translation.shared: defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( - export_symbols=["pypy_main_startup", - 'RPython_StartupCode'])) + export_symbols=["pypy_main_startup"])) self.eci, cfile, extra = gen_source(db, modulename, targetdir, self.eci, defines=defines, split=self.split) @@ -726,6 +727,15 @@ for line in preimplementationlines: print >> f, line +# the point of dance below is so the call to rpython_startup_code actually +# does call asm_stack_bottom + +RPython_StartupCode = rffi.llexternal([], lltype.Void) + + at entrypoint('main', [], c_name='rpython_startup_code') +def rpython_startup_code(): + return RPython_StartupCode() + def gen_startupcode(f, database): # generate the start-up code and put it into a function print >> f, 'char *RPython_StartupCode(void) {' From noreply at buildbot.pypy.org Wed May 8 20:48:11 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 20:48:11 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130508184811.AEC781C0135@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63928:6cf91c47a736 Date: 2013-05-08 20:47 +0200 http://bitbucket.org/pypy/pypy/changeset/6cf91c47a736/ Log: merge diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -431,10 +431,12 @@ class AppTestW_ListObject(object): def setup_class(cls): + import platform import sys on_cpython = (cls.runappdirect and not hasattr(sys, 'pypy_translation_info')) cls.w_on_cpython = cls.space.wrap(on_cpython) + cls.w_on_arm = cls.space.wrap(platform.machine().startswith('arm')) cls.w_runappdirect = cls.space.wrap(cls.runappdirect) def test_getstrategyfromlist_w(self): @@ -948,8 +950,7 @@ def test_setitem_slice_performance(self): # because of a complexity bug, this used to take forever on a # translated pypy. On CPython2.6 -A, it takes around 5 seconds. - import platform - if platform.machine().startswith('arm'): + if self.on_arm: skip("consumes too much memory for most ARM machines") if self.runappdirect: count = 16*1024*1024 diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -7,7 +7,7 @@ if key == 'main' than it's included by default """ - from rpython.translator.cbuild import ExternalCompilationInfo + from rpython.translator.tool.cbuild import ExternalCompilationInfo def deco(func): secondary_entrypoints.setdefault(key, []).append((func, argtypes)) From noreply at buildbot.pypy.org Wed May 8 21:21:23 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 21:21:23 +0200 (CEST) Subject: [pypy-commit] pypy default: oops Message-ID: <20130508192123.CDB641C0307@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63929:5bc8ded7660e Date: 2013-05-08 21:20 +0200 http://bitbucket.org/pypy/pypy/changeset/5bc8ded7660e/ Log: oops diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -730,7 +730,7 @@ # the point of dance below is so the call to rpython_startup_code actually # does call asm_stack_bottom -RPython_StartupCode = rffi.llexternal([], lltype.Void) +RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void) @entrypoint('main', [], c_name='rpython_startup_code') def rpython_startup_code(): From noreply at buildbot.pypy.org Wed May 8 23:55:23 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 8 May 2013 23:55:23 +0200 (CEST) Subject: [pypy-commit] pypy default: shuffle stuff around Message-ID: <20130508215523.5B2B41C12F3@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63930:0423d458c98d Date: 2013-05-08 23:54 +0200 http://bitbucket.org/pypy/pypy/changeset/0423d458c98d/ Log: shuffle stuff around diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -8,7 +8,7 @@ if key == 'main' than it's included by default """ from rpython.translator.tool.cbuild import ExternalCompilationInfo - + def deco(func): secondary_entrypoints.setdefault(key, []).append((func, argtypes)) if c_name is not None: @@ -20,3 +20,15 @@ return func return deco +# the point of dance below is so the call to rpython_startup_code actually +# does call asm_stack_bottom. It's here because there is no other good place. +# This thing is imported by any target which has any API, so it'll get +# registered + +from rpython.rtyper.lltypesystem import lltype, rffi + +RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void) + + at entrypoint('main', [], c_name='rpython_startup_code') +def rpython_startup_code(): + return RPython_StartupCode() diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -727,15 +727,6 @@ for line in preimplementationlines: print >> f, line -# the point of dance below is so the call to rpython_startup_code actually -# does call asm_stack_bottom - -RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void) - - at entrypoint('main', [], c_name='rpython_startup_code') -def rpython_startup_code(): - return RPython_StartupCode() - def gen_startupcode(f, database): # generate the start-up code and put it into a function print >> f, 'char *RPython_StartupCode(void) {' From noreply at buildbot.pypy.org Thu May 9 05:17:25 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 9 May 2013 05:17:25 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Unify formatting of glossaries (use Sphinx' glossary as reference). Message-ID: <20130509031725.A7AD21C05B7@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63932:6ad53ec0bc2a Date: 2013-05-08 14:53 +0200 http://bitbucket.org/pypy/pypy/changeset/6ad53ec0bc2a/ Log: Unify formatting of glossaries (use Sphinx' glossary as reference). diff --git a/pypy/doc/glossary.rst b/pypy/doc/glossary.rst --- a/pypy/doc/glossary.rst +++ b/pypy/doc/glossary.rst @@ -1,53 +1,52 @@ .. _glossary: -******** Glossary -******** +======== PyPy, like any large project, has developed a jargon of its own. This document gives brief definition of some of these terms and provides links to more information. -.. if you add new entries, keep the alphabetical sorting! +.. if you add new entries, keep the alphabetical sorting and formatting! .. glossary:: - application level - applevel_ code is normal Python code running on top of the PyPy or - :term:`CPython` interpreter (see :term:`interpreter level`) + application level + applevel_ code is normal Python code running on top of the PyPy or + :term:`CPython` interpreter (see :term:`interpreter level`) - CPython - The "default" implementation of Python, written in C and - distributed by the PSF_ on http://www.python.org. + CPython + The "default" implementation of Python, written in C and + distributed by the PSF_ on http://www.python.org. - interpreter level - Code running at this level is part of the implementation of the - PyPy interpreter and cannot interact normally with :term:`application - level` code; it typically provides implementation for an object - space and its builtins. + interpreter level + Code running at this level is part of the implementation of the + PyPy interpreter and cannot interact normally with :term:`application + level` code; it typically provides implementation for an object + space and its builtins. - mixed module + mixed module a module that accesses PyPy's :term:`interpreter level`. The name comes from the fact that the module's implementation can be a mixture of :term:`application level` and :term:`interpreter level` code. - object space - The `object space `__ (often abbreviated to - "objspace") creates all objects and knows how to perform operations - on the objects. You may think of an object space as being a library - offering a fixed API, a set of operations, with implementations - that a) correspond to the known semantics of Python objects, b) - extend or twist these semantics, or c) serve whole-program analysis - purposes. + object space + The `object space `__ (often abbreviated to + "objspace") creates all objects and knows how to perform operations + on the objects. You may think of an object space as being a library + offering a fixed API, a set of operations, with implementations + that a) correspond to the known semantics of Python objects, b) + extend or twist these semantics, or c) serve whole-program analysis + purposes. - stackless - Technology that enables various forms of non conventional control - flow, such as coroutines, greenlets and tasklets. Inspired by - Christian Tismer's `Stackless Python `__. + stackless + Technology that enables various forms of non conventional control + flow, such as coroutines, greenlets and tasklets. Inspired by + Christian Tismer's `Stackless Python `__. - standard interpreter - It is the `subsystem implementing the Python language`_, composed - of the bytecode interpreter and of the standard objectspace. + standard interpreter + It is the `subsystem implementing the Python language`_, composed + of the bytecode interpreter and of the standard objectspace. .. _applevel: coding-guide.html#application-level .. _PSF: http://www.python.org/psf/ diff --git a/rpython/doc/glossary.rst b/rpython/doc/glossary.rst --- a/rpython/doc/glossary.rst +++ b/rpython/doc/glossary.rst @@ -1,112 +1,114 @@ +.. _glossary: + Glossary ======== -.. if you add new entries, keep the alphabetical sorting! +.. if you add new entries, keep the alphabetical sorting and formatting! .. glossary:: - annotator - The component of the :term:`RPython toolchain` that performs a form - of :term:`type inference` on the flow graph. See the `annotator pass`_ - in the documentation. + annotator + The component of the :term:`RPython toolchain` that performs a form + of :term:`type inference` on the flow graph. See the `annotator pass`_ + in the documentation. - backend - Code generator that converts an `RPython - `__ program to a `target - language`_ using the :term:`RPython toolchain`. A backend uses either the - :term:`lltypesystem` or the :term:`ootypesystem`. + backend + Code generator that converts an `RPython + `__ program to a `target + language`_ using the :term:`RPython toolchain`. A backend uses either the + :term:`lltypesystem` or the :term:`ootypesystem`. - compile-time - In the context of the :term:`JIT`, compile time is when the JIT is - generating machine code "just in time". + compile-time + In the context of the :term:`JIT`, compile time is when the JIT is + generating machine code "just in time". - external function - Functions that we don't want to implement in Python for various - reasons (e.g. they need to make calls into the OS) and whose - implementation will be provided by the backend. + external function + Functions that we don't want to implement in Python for various + reasons (e.g. they need to make calls into the OS) and whose + implementation will be provided by the backend. - garbage collection framework - Code that makes it possible to write `PyPy's garbage collectors`_ - in Python itself. + garbage collection framework + Code that makes it possible to write `PyPy's garbage collectors`_ + in Python itself. - jit + jit `just in time compiler`_. - llinterpreter - Piece of code that is able to interpret flow graphs. This is very - useful for testing purposes, especially if you work on the :term:`RPython` - Typer. + llinterpreter + Piece of code that is able to interpret flow graphs. This is very + useful for testing purposes, especially if you work on the :term:`RPython` + Typer. - lltypesystem - A `C-like type model `__ that contains - structs and pointers. A :term:`backend` that uses this type system is also - called a low-level backend. The C backend uses this - typesystem. + lltypesystem + A `C-like type model `__ that contains + structs and pointers. A :term:`backend` that uses this type system is also + called a low-level backend. The C backend uses this + typesystem. - low-level helper - A function that the :term:`RTyper` can use a call to as part of implementing - some operation in terms of the target :term:`type system`. + low-level helper + A function that the :term:`RTyper` can use a call to as part of implementing + some operation in terms of the target :term:`type system`. - ootypesystem - An `object oriented type model `__ - containing classes and instances. A :term:`backend` that uses this type system - is also called a high-level backend. The JVM and CLI backends - all use this typesystem. + ootypesystem + An `object oriented type model `__ + containing classes and instances. A :term:`backend` that uses this type system + is also called a high-level backend. The JVM and CLI backends + all use this typesystem. - prebuilt constant - In :term:`RPython` module globals are considered constants. Moreover, - global (i.e. prebuilt) lists and dictionaries are supposed to be - immutable ("prebuilt constant" is sometimes abbreviated to "pbc"). + prebuilt constant + In :term:`RPython` module globals are considered constants. Moreover, + global (i.e. prebuilt) lists and dictionaries are supposed to be + immutable ("prebuilt constant" is sometimes abbreviated to "pbc"). - promotion - :term:`JIT` terminology. *promotion* is a way of "using" a :term:`run-time` - value at :term:`compile-time`, essentially by deferring compilation - until the run-time value is known. See if `the jit docs`_ help. + promotion + :term:`JIT` terminology. *promotion* is a way of "using" a :term:`run-time` + value at :term:`compile-time`, essentially by deferring compilation + until the run-time value is known. See if `the jit docs`_ help. - RPython - `Restricted Python`_, a limited subset of the Python_ language. - The limitations make :term:`type inference` possible. - It is also the language that the PyPy interpreter itself is written - in. + RPython + `Restricted Python`_, a limited subset of the Python_ language. + The limitations make :term:`type inference` possible. + It is also the language that the PyPy interpreter itself is written + in. - RPython toolchain - The `annotator pass`_, `The RPython Typer`_, and various - :term:`backend`\ s. + RPython toolchain + The `annotator pass`_, `The RPython Typer`_, and various + :term:`backend`\ s. - rtyper - Based on the type annotations, the `RPython Typer`_ turns the flow - graph into one that fits the model of the target platform/:term:`backend` - using either the :term:`lltypesystem` or the :term:`ootypesystem`. + rtyper + Based on the type annotations, the `RPython Typer`_ turns the flow + graph into one that fits the model of the target platform/:term:`backend` + using either the :term:`lltypesystem` or the :term:`ootypesystem`. - run-time - In the context of the :term:`JIT`, run time is when the code the JIT has - generated is executing. + run-time + In the context of the :term:`JIT`, run time is when the code the JIT has + generated is executing. - specialization - A way of controlling how a specific function is handled by the - :term:`annotator`. One specialization is to treat calls to a function - with different argument types as if they were calls to different - functions with identical source. + specialization + A way of controlling how a specific function is handled by the + :term:`annotator`. One specialization is to treat calls to a function + with different argument types as if they were calls to different + functions with identical source. - transformation - Code that modifies flowgraphs to weave in translation aspects + transformation + Code that modifies flowgraphs to weave in translation aspects - translation-time - In the context of the :term:`JIT`, translation time is when the PyPy - source is being analyzed and the JIT itself is being created. + translation-time + In the context of the :term:`JIT`, translation time is when the PyPy + source is being analyzed and the JIT itself is being created. - translator - Tool_ based on the PyPy interpreter which can translate - sufficiently static Python programs into low-level code. + translator + Tool_ based on the PyPy interpreter which can translate + sufficiently static Python programs into low-level code. - type system - The RTyper can target either the :term:`lltypesystem` or the :term:`ootypesystem`. + type system + The RTyper can target either the :term:`lltypesystem` or the :term:`ootypesystem`. - type inference - Deduces either partially or fully the type of expressions as - described in this `type inference article on Wikipedia`_. - The :term:`RPython toolchain`'s flavour of type inference is described - in the `annotator pass`_ section. + type inference + Deduces either partially or fully the type of expressions as + described in this `type inference article on Wikipedia`_. + The :term:`RPython toolchain`'s flavour of type inference is described + in the `annotator pass`_ section. .. _`just in time compiler`: jit/index.html .. _`the jit docs`: jit/index.html From noreply at buildbot.pypy.org Thu May 9 05:17:24 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 9 May 2013 05:17:24 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Split glossary. Message-ID: <20130509031724.593AB1C021A@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63931:049641859344 Date: 2013-05-08 14:42 +0200 http://bitbucket.org/pypy/pypy/changeset/049641859344/ Log: Split glossary. diff --git a/pypy/doc/glossary.rst b/pypy/doc/glossary.rst --- a/pypy/doc/glossary.rst +++ b/pypy/doc/glossary.rst @@ -12,62 +12,20 @@ .. glossary:: - annotator - The component of the :term:`RPython toolchain` that performs a form - of :term:`type inference` on the flow graph. See the `annotator pass`_ - in the documentation. - application level applevel_ code is normal Python code running on top of the PyPy or :term:`CPython` interpreter (see :term:`interpreter level`) - backend - Code generator that converts an `RPython - `__ program to a `target - language`_ using the :term:`RPython toolchain`. A backend uses either the - :term:`lltypesystem` or the :term:`ootypesystem`. - - compile-time - In the context of the :term:`JIT`, compile time is when the JIT is - generating machine code "just in time". - CPython The "default" implementation of Python, written in C and distributed by the PSF_ on http://www.python.org. - external function - Functions that we don't want to implement in Python for various - reasons (e.g. they need to make calls into the OS) and whose - implementation will be provided by the backend. - - garbage collection framework - Code that makes it possible to write `PyPy's garbage collectors`_ - in Python itself. - interpreter level Code running at this level is part of the implementation of the PyPy interpreter and cannot interact normally with :term:`application level` code; it typically provides implementation for an object space and its builtins. - jit - `just in time compiler`_. - - llinterpreter - Piece of code that is able to interpret flow graphs. This is very - useful for testing purposes, especially if you work on the :term:`RPython` - Typer. - - lltypesystem - A `C-like type model `__ that contains - structs and pointers. A :term:`backend` that uses this type system is also - called a low-level backend. The C backend uses this - typesystem. - - low-level helper - A function that the :term:`RTyper` can use a call to as part of implementing - some operation in terms of the target :term:`type system`. - mixed module a module that accesses PyPy's :term:`interpreter level`. The name comes from the fact that the module's implementation can be a mixture of @@ -82,47 +40,6 @@ extend or twist these semantics, or c) serve whole-program analysis purposes. - ootypesystem - An `object oriented type model `__ - containing classes and instances. A :term:`backend` that uses this type system - is also called a high-level backend. The JVM and CLI backends - all use this typesystem. - - prebuilt constant - In :term:`RPython` module globals are considered constants. Moreover, - global (i.e. prebuilt) lists and dictionaries are supposed to be - immutable ("prebuilt constant" is sometimes abbreviated to "pbc"). - - promotion - :term:`JIT` terminology. *promotion* is a way of "using" a :term:`run-time` - value at :term:`compile-time`, essentially by deferring compilation - until the run-time value is known. See if `the jit docs`_ help. - - RPython - `Restricted Python`_, a limited subset of the Python_ language. - The limitations make :term:`type inference` possible. - It is also the language that the PyPy interpreter itself is written - in. - - RPython toolchain - The `annotator pass`_, `The RPython Typer`_, and various - :term:`backend`\ s. - - rtyper - Based on the type annotations, the `RPython Typer`_ turns the flow - graph into one that fits the model of the target platform/:term:`backend` - using either the :term:`lltypesystem` or the :term:`ootypesystem`. - - run-time - In the context of the :term:`JIT`, run time is when the code the JIT has - generated is executing. - - specialization - A way of controlling how a specific function is handled by the - :term:`annotator`. One specialization is to treat calls to a function - with different argument types as if they were calls to different - functions with identical source. - stackless Technology that enables various forms of non conventional control flow, such as coroutines, greenlets and tasklets. Inspired by @@ -132,38 +49,6 @@ It is the `subsystem implementing the Python language`_, composed of the bytecode interpreter and of the standard objectspace. - transformation - Code that modifies flowgraphs to weave in translation aspects - - translation-time - In the context of the :term:`JIT`, translation time is when the PyPy - source is being analyzed and the JIT itself is being created. - - translator - Tool_ based on the PyPy interpreter which can translate - sufficiently static Python programs into low-level code. - - type system - The RTyper can target either the :term:`lltypesystem` or the :term:`ootypesystem`. - - type inference - Deduces either partially or fully the type of expressions as - described in this `type inference article on Wikipedia`_. - The :term:`RPython toolchain`'s flavour of type inference is described - in the `annotator pass`_ section. - .. _applevel: coding-guide.html#application-level -.. _`target language`: getting-started-dev.html#trying-out-the-translator -.. _`just in time compiler`: jit/index.html -.. _`the jit docs`: jit/index.html -.. _`type inference article on Wikipedia`: http://en.wikipedia.org/wiki/Type_inference -.. _`annotator pass`: translation.html#the-annotation-pass -.. _`The RPython Typer`: translation.html#the-rpython-typer -.. _`backends`: getting-started-dev.html#trying-out-the-translator -.. _Tool: getting-started-dev.html#trying-out-the-translator -.. _`PyPy's garbage collectors`: garbage_collection.html -.. _`Restricted Python`: coding-guide.html#restricted-python .. _PSF: http://www.python.org/psf/ -.. _Python: http://www.python.org -.. _`RPython Typer`: rtyper.html .. _`subsystem implementing the Python language`: architecture.html#standard-interpreter diff --git a/rpython/doc/glossary.rst b/rpython/doc/glossary.rst new file mode 100644 --- /dev/null +++ b/rpython/doc/glossary.rst @@ -0,0 +1,121 @@ +Glossary +======== + +.. if you add new entries, keep the alphabetical sorting! + +.. glossary:: + + annotator + The component of the :term:`RPython toolchain` that performs a form + of :term:`type inference` on the flow graph. See the `annotator pass`_ + in the documentation. + + backend + Code generator that converts an `RPython + `__ program to a `target + language`_ using the :term:`RPython toolchain`. A backend uses either the + :term:`lltypesystem` or the :term:`ootypesystem`. + + compile-time + In the context of the :term:`JIT`, compile time is when the JIT is + generating machine code "just in time". + + external function + Functions that we don't want to implement in Python for various + reasons (e.g. they need to make calls into the OS) and whose + implementation will be provided by the backend. + + garbage collection framework + Code that makes it possible to write `PyPy's garbage collectors`_ + in Python itself. + + jit + `just in time compiler`_. + + llinterpreter + Piece of code that is able to interpret flow graphs. This is very + useful for testing purposes, especially if you work on the :term:`RPython` + Typer. + + lltypesystem + A `C-like type model `__ that contains + structs and pointers. A :term:`backend` that uses this type system is also + called a low-level backend. The C backend uses this + typesystem. + + low-level helper + A function that the :term:`RTyper` can use a call to as part of implementing + some operation in terms of the target :term:`type system`. + + ootypesystem + An `object oriented type model `__ + containing classes and instances. A :term:`backend` that uses this type system + is also called a high-level backend. The JVM and CLI backends + all use this typesystem. + + prebuilt constant + In :term:`RPython` module globals are considered constants. Moreover, + global (i.e. prebuilt) lists and dictionaries are supposed to be + immutable ("prebuilt constant" is sometimes abbreviated to "pbc"). + + promotion + :term:`JIT` terminology. *promotion* is a way of "using" a :term:`run-time` + value at :term:`compile-time`, essentially by deferring compilation + until the run-time value is known. See if `the jit docs`_ help. + + RPython + `Restricted Python`_, a limited subset of the Python_ language. + The limitations make :term:`type inference` possible. + It is also the language that the PyPy interpreter itself is written + in. + + RPython toolchain + The `annotator pass`_, `The RPython Typer`_, and various + :term:`backend`\ s. + + rtyper + Based on the type annotations, the `RPython Typer`_ turns the flow + graph into one that fits the model of the target platform/:term:`backend` + using either the :term:`lltypesystem` or the :term:`ootypesystem`. + + run-time + In the context of the :term:`JIT`, run time is when the code the JIT has + generated is executing. + + specialization + A way of controlling how a specific function is handled by the + :term:`annotator`. One specialization is to treat calls to a function + with different argument types as if they were calls to different + functions with identical source. + + transformation + Code that modifies flowgraphs to weave in translation aspects + + translation-time + In the context of the :term:`JIT`, translation time is when the PyPy + source is being analyzed and the JIT itself is being created. + + translator + Tool_ based on the PyPy interpreter which can translate + sufficiently static Python programs into low-level code. + + type system + The RTyper can target either the :term:`lltypesystem` or the :term:`ootypesystem`. + + type inference + Deduces either partially or fully the type of expressions as + described in this `type inference article on Wikipedia`_. + The :term:`RPython toolchain`'s flavour of type inference is described + in the `annotator pass`_ section. + +.. _`just in time compiler`: jit/index.html +.. _`the jit docs`: jit/index.html +.. _`type inference article on Wikipedia`: http://en.wikipedia.org/wiki/Type_inference +.. _`annotator pass`: translation.html#the-annotation-pass +.. _`The RPython Typer`: translation.html#the-rpython-typer +.. _`backends`: getting-started-dev.html#trying-out-the-translator +.. _Tool: getting-started-dev.html#trying-out-the-translator +.. _`PyPy's garbage collectors`: garbage_collection.html +.. _`Restricted Python`: coding-guide.html#restricted-python +.. _Python: http://www.python.org +.. _`RPython Typer`: rtyper.html From noreply at buildbot.pypy.org Thu May 9 05:17:26 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 9 May 2013 05:17:26 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: I think the reader knows what a glossary is. ; ) Message-ID: <20130509031726.DBB8E1C021A@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63933:0632a34fd3d9 Date: 2013-05-08 14:54 +0200 http://bitbucket.org/pypy/pypy/changeset/0632a34fd3d9/ Log: I think the reader knows what a glossary is. ;) diff --git a/pypy/doc/glossary.rst b/pypy/doc/glossary.rst --- a/pypy/doc/glossary.rst +++ b/pypy/doc/glossary.rst @@ -3,10 +3,6 @@ Glossary ======== -PyPy, like any large project, has developed a jargon of its own. This -document gives brief definition of some of these terms and provides -links to more information. - .. if you add new entries, keep the alphabetical sorting and formatting! .. glossary:: From noreply at buildbot.pypy.org Thu May 9 05:17:28 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 9 May 2013 05:17:28 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Use Sphinx' cross-referencing features in glossaries (this will be expanded). Message-ID: <20130509031728.364101C021A@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63934:b9177bbb48cd Date: 2013-05-08 15:28 +0200 http://bitbucket.org/pypy/pypy/changeset/b9177bbb48cd/ Log: Use Sphinx' cross-referencing features in glossaries (this will be expanded). diff --git a/pypy/doc/architecture.rst b/pypy/doc/architecture.rst --- a/pypy/doc/architecture.rst +++ b/pypy/doc/architecture.rst @@ -171,8 +171,8 @@ .. _`document about the RPython toolchain`: translation.html .. _`garbage collector`: garbage_collection.html .. _`RPython toolchain`: translation.html -.. _`standard interpreter`: -.. _`python interpreter`: + +.. _python-interpreter: PyPy Python Interpreter ----------------------- diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -44,8 +44,8 @@ but let's stick with this somewhat canonical approach. -.. _`application-level`: -.. _`interpreter-level`: +.. _application-level: +.. _interpreter-level: Application-level and interpreter-level execution and objects ------------------------------------------------------------- diff --git a/pypy/doc/glossary.rst b/pypy/doc/glossary.rst --- a/pypy/doc/glossary.rst +++ b/pypy/doc/glossary.rst @@ -8,7 +8,7 @@ .. glossary:: application level - applevel_ code is normal Python code running on top of the PyPy or + :ref:`applevel` code is normal Python code running on top of the PyPy or :term:`CPython` interpreter (see :term:`interpreter level`) CPython @@ -27,7 +27,7 @@ :term:`application level` and :term:`interpreter level` code. object space - The `object space `__ (often abbreviated to + :doc:`objspace` (often abbreviated to "objspace") creates all objects and knows how to perform operations on the objects. You may think of an object space as being a library offering a fixed API, a set of operations, with implementations @@ -41,9 +41,7 @@ Christian Tismer's `Stackless Python `__. standard interpreter - It is the `subsystem implementing the Python language`_, composed + It is the :ref:`subsystem implementing the Python language `, composed of the bytecode interpreter and of the standard objectspace. -.. _applevel: coding-guide.html#application-level .. _PSF: http://www.python.org/psf/ -.. _`subsystem implementing the Python language`: architecture.html#standard-interpreter diff --git a/pypy/doc/objspace.rst b/pypy/doc/objspace.rst --- a/pypy/doc/objspace.rst +++ b/pypy/doc/objspace.rst @@ -1,6 +1,6 @@ -====================== -Object Spaces -====================== +================ +The Object Space +================ .. contents:: @@ -9,7 +9,7 @@ .. _`Object Space`: Introduction -================ +============ The object space creates all objects and knows how to perform operations on the objects. You may think of an object space as being a library diff --git a/rpython/doc/getting-started.rst b/rpython/doc/getting-started.rst --- a/rpython/doc/getting-started.rst +++ b/rpython/doc/getting-started.rst @@ -49,7 +49,7 @@ .. _`part 2`: http://morepypy.blogspot.com/2011/04/tutorial-part-2-adding-jit.html -.. _`try out the translator`: +.. _try-out-the-translator: Trying out the translator ------------------------- diff --git a/rpython/doc/glossary.rst b/rpython/doc/glossary.rst --- a/rpython/doc/glossary.rst +++ b/rpython/doc/glossary.rst @@ -9,13 +9,12 @@ annotator The component of the :term:`RPython toolchain` that performs a form - of :term:`type inference` on the flow graph. See the `annotator pass`_ + of :term:`type inference` on the flow graph. See :ref:`annotator` in the documentation. backend - Code generator that converts an `RPython - `__ program to a `target - language`_ using the :term:`RPython toolchain`. A backend uses either the + Code generator that converts an :doc:`rpython` program to a :ref:`target + language ` using the :term:`RPython toolchain`. A backend uses either the :term:`lltypesystem` or the :term:`ootypesystem`. compile-time @@ -28,11 +27,11 @@ implementation will be provided by the backend. garbage collection framework - Code that makes it possible to write `PyPy's garbage collectors`_ + Code that makes it possible to write :doc:`RPython's garbage collectors ` in Python itself. - jit - `just in time compiler`_. + JIT + :doc:`just in time compiler `. llinterpreter Piece of code that is able to interpret flow graphs. This is very @@ -63,20 +62,19 @@ promotion :term:`JIT` terminology. *promotion* is a way of "using" a :term:`run-time` value at :term:`compile-time`, essentially by deferring compilation - until the run-time value is known. See if `the jit docs`_ help. + until the run-time value is known. See if :doc:`the jit docs ` help. RPython - `Restricted Python`_, a limited subset of the Python_ language. + :ref:`rpython`, a limited subset of the Python_ language. The limitations make :term:`type inference` possible. It is also the language that the PyPy interpreter itself is written in. RPython toolchain - The `annotator pass`_, `The RPython Typer`_, and various - :term:`backend`\ s. + :ref:`annotator`, :doc:`rtyper`, and various :term:`backend`\ s. rtyper - Based on the type annotations, the `RPython Typer`_ turns the flow + Based on the type annotations, :doc:`rtyper` turns the flow graph into one that fits the model of the target platform/:term:`backend` using either the :term:`lltypesystem` or the :term:`ootypesystem`. @@ -98,7 +96,7 @@ source is being analyzed and the JIT itself is being created. translator - Tool_ based on the PyPy interpreter which can translate + :ref:`Tool ` based on the PyPy interpreter which can translate sufficiently static Python programs into low-level code. type system @@ -108,16 +106,7 @@ Deduces either partially or fully the type of expressions as described in this `type inference article on Wikipedia`_. The :term:`RPython toolchain`'s flavour of type inference is described - in the `annotator pass`_ section. + in :ref:`annotator` section. -.. _`just in time compiler`: jit/index.html -.. _`the jit docs`: jit/index.html -.. _`type inference article on Wikipedia`: http://en.wikipedia.org/wiki/Type_inference -.. _`annotator pass`: translation.html#the-annotation-pass -.. _`The RPython Typer`: translation.html#the-rpython-typer -.. _`backends`: getting-started-dev.html#trying-out-the-translator -.. _Tool: getting-started-dev.html#trying-out-the-translator -.. _`PyPy's garbage collectors`: garbage_collection.html -.. _`Restricted Python`: coding-guide.html#restricted-python +.. _type inference article on Wikipedia: http://en.wikipedia.org/wiki/Type_inference .. _Python: http://www.python.org -.. _`RPython Typer`: rtyper.html diff --git a/rpython/doc/translation.rst b/rpython/doc/translation.rst --- a/rpython/doc/translation.rst +++ b/rpython/doc/translation.rst @@ -267,7 +267,7 @@ .. _`document describing object spaces`: objspace.html -.. _Annotator: +.. _annotator: The Annotation Pass =================== From noreply at buildbot.pypy.org Thu May 9 05:17:29 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 9 May 2013 05:17:29 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Fix two refs. Message-ID: <20130509031729.6A2261C021A@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63935:65bf645150fe Date: 2013-05-08 16:06 +0200 http://bitbucket.org/pypy/pypy/changeset/65bf645150fe/ Log: Fix two refs. diff --git a/rpython/doc/glossary.rst b/rpython/doc/glossary.rst --- a/rpython/doc/glossary.rst +++ b/rpython/doc/glossary.rst @@ -65,7 +65,7 @@ until the run-time value is known. See if :doc:`the jit docs ` help. RPython - :ref:`rpython`, a limited subset of the Python_ language. + :doc:`rpython`, a limited subset of the Python_ language. The limitations make :term:`type inference` possible. It is also the language that the PyPy interpreter itself is written in. diff --git a/rpython/doc/translation.rst b/rpython/doc/translation.rst --- a/rpython/doc/translation.rst +++ b/rpython/doc/translation.rst @@ -85,7 +85,7 @@ (although these steps are not quite as distinct as you might think from this presentation). -There is an :ref:`interactive interface ` called :source:`rpython/bin/translatorshell.py` to the +There is an :ref:`interactive interface ` called :source:`rpython/bin/translatorshell.py` to the translation process which allows you to interactively work through these stages. From noreply at buildbot.pypy.org Thu May 9 07:30:05 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 9 May 2013 07:30:05 +0200 (CEST) Subject: [pypy-commit] pypy default: small cleanups Message-ID: <20130509053005.A492A1C05B7@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r63936:cb9096cdcb75 Date: 2013-05-08 22:29 -0700 http://bitbucket.org/pypy/pypy/changeset/cb9096cdcb75/ Log: small cleanups diff --git a/rpython/bin/translatorshell.py b/rpython/bin/translatorshell.py --- a/rpython/bin/translatorshell.py +++ b/rpython/bin/translatorshell.py @@ -1,7 +1,7 @@ -#!/usr/bin/env python +#!/usr/bin/env python -"""PyPy Translator Frontend +"""RPython Translator Frontend Glue script putting together the various pieces of the translator. Can be used for interactive testing of the translator. @@ -14,7 +14,7 @@ t.annotate() t.view() # graph + annotations under the mouse - t.rtype() # use low level operations + t.rtype() # use low level operations lib = t.compile_c() # C compilation as a library f = get_c_function(lib, func) # get the function out of the library assert f(arg) == func(arg) # sanity check (for C) @@ -51,7 +51,7 @@ import os histfile = os.path.join(os.environ["HOME"], ".pypytrhist") try: - getattr(readline, "clear_history", lambda : None)() + getattr(readline, "clear_history", lambda: None)() readline.read_history_file(histfile) except IOError: pass @@ -74,5 +74,3 @@ import os os.putenv("PYTHONINSPECT", "1") - - From noreply at buildbot.pypy.org Thu May 9 10:55:53 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 10:55:53 +0200 (CEST) Subject: [pypy-commit] pypy default: kill static linking Message-ID: <20130509085553.117921C00F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63937:a29436d16da7 Date: 2013-05-09 10:54 +0200 http://bitbucket.org/pypy/pypy/changeset/a29436d16da7/ Log: kill static linking diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -78,34 +78,8 @@ else: pre_include_bits = [] - def setup_after_config(config): - # a crude hack - libffi.a might be compiled without -fPIC on certain - # platforms, just disable it when we've passed --shared - if config.translation.shared: - eci.link_files = () - eci.libraries = ('ffi',) - - def find_libffi_a(): - dirlist = platform.library_dirs_for_libffi_a() - for dir in dirlist: - result = os.path.join(dir, 'libffi.a') - if os.path.exists(result): - return result - log.WARNING("'libffi.a' not found in %s" % (dirlist,)) - log.WARNING("trying to use the dynamic library instead...") - return None - - path_libffi_a = None - if hasattr(platform, 'library_dirs_for_libffi_a'): - path_libffi_a = find_libffi_a() - if path_libffi_a is not None: - # platforms on which we want static linking - libraries = [] - link_files = [path_libffi_a] - else: - # platforms on which we want dynamic linking - libraries = ['ffi'] - link_files = [] + libraries = ['ffi'] + link_files = [] eci = ExternalCompilationInfo( pre_include_bits = pre_include_bits, diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -7,7 +7,6 @@ import sys, os link_files = [] -testonly_libraries = [] include_dirs = [] if sys.platform == 'win32' and platform.name != 'mingw32': libraries = ['libeay32', 'ssleay32', @@ -21,27 +20,8 @@ # so that openssl/ssl.h can repair this nonsense. 'wincrypt.h'] else: - libraries = ['z'] + libraries = ['z', 'ssl', 'crypto'] includes = [] - if (sys.platform.startswith('linux') and - os.path.exists('/usr/lib/libssl.a') and - os.path.exists('/usr/lib/libcrypto.a')): - # use static linking to avoid the infinite - # amount of troubles due to symbol versions - # and 0.9.8/1.0.0 - link_files += ['/usr/lib/libssl.a', '/usr/lib/libcrypto.a'] - testonly_libraries += ['ssl', 'crypto'] - elif (sys.platform.startswith('linux') and - os.path.exists('/usr/local/ssl/lib/libssl.a') and - os.path.exists('/usr/local/ssl/lib/libcrypto.a')): - # use static linking, 2nd version - include_dirs += ['/usr/local/ssl/include'] - link_files += ['/usr/local/ssl/lib/libssl.a', - '/usr/local/ssl/lib/libcrypto.a', - '-ldl'] - testonly_libraries += ['ssl', 'crypto'] - else: - libraries += ['ssl', 'crypto'] includes += [ 'openssl/ssl.h', @@ -54,7 +34,6 @@ eci = ExternalCompilationInfo( libraries = libraries, link_files = link_files, - testonly_libraries = testonly_libraries, includes = includes, include_dirs = include_dirs, export_symbols = [], diff --git a/rpython/translator/goal/translate.py b/rpython/translator/goal/translate.py --- a/rpython/translator/goal/translate.py +++ b/rpython/translator/goal/translate.py @@ -183,13 +183,6 @@ # perform checks (if any) on the final config final_check_config(config) - try: - from rpython.rlib import clibffi - except ImportError: - pass # too bad - else: - clibffi.setup_after_config(config) - return targetspec_dic, translateconfig, config, args def show_help(translateconfig, opt_parser, targetspec_dic, config): diff --git a/rpython/translator/platform/cygwin.py b/rpython/translator/platform/cygwin.py --- a/rpython/translator/platform/cygwin.py +++ b/rpython/translator/platform/cygwin.py @@ -39,14 +39,6 @@ return self._pkg_config("libffi", "--libs-only-L", ['/usr/lib/libffi']) - def library_dirs_for_libffi_a(self): - # places where we need to look for libffi.a - # XXX obscuuure! only look for libffi.a if run with translate.py - if 'translate' in sys.modules: - return self.library_dirs_for_libffi() + ['/usr/lib'] - else: - return [] - class Cygwin(BaseCygwin): shared_only = () # it seems that on 32-bit linux, compiling with -fPIC diff --git a/rpython/translator/platform/linux.py b/rpython/translator/platform/linux.py --- a/rpython/translator/platform/linux.py +++ b/rpython/translator/platform/linux.py @@ -7,7 +7,7 @@ class BaseLinux(BasePosix): name = "linux" - + link_flags = tuple( ['-pthread',] + os.environ.get('LDFLAGS', '').split()) @@ -20,7 +20,7 @@ shared_only = ('-fPIC',) so_ext = 'so' so_prefixes = ('lib', '') - + def _args_for_shared(self, args): return ['-shared'] + args @@ -32,20 +32,6 @@ return self._pkg_config("libffi", "--libs-only-L", ['/usr/lib/libffi']) - def library_dirs_for_libffi_a(self): - # places where we need to look for libffi.a - # XXX obscuuure! only look for libffi.a if run with translate.py - if 'translate' in sys.modules: - if sys.maxint > 2**32: - host = 'x86_64' - else: - host = 'x86' - return self.library_dirs_for_libffi() + [ - '/usr/lib', - '/usr/lib/%s-linux-gnu/' % host] - else: - return [] - class Linux(BaseLinux): if platform.machine().startswith('arm'): From noreply at buildbot.pypy.org Thu May 9 10:59:14 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 9 May 2013 10:59:14 +0200 (CEST) Subject: [pypy-commit] pypy default: clean-up Message-ID: <20130509085914.38DB01C00F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63938:63cf4c942d92 Date: 2013-05-09 10:58 +0200 http://bitbucket.org/pypy/pypy/changeset/63cf4c942d92/ Log: clean-up diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -64,13 +64,8 @@ else: separate_module_sources = [] -def setup_after_config(config): - pass if not _WIN32: - # On some platforms, we try to link statically libffi, which is small - # anyway and avoids endless troubles for installing. On other platforms - # libffi.a is typically not there, so we link dynamically. includes = ['ffi.h'] if _MAC_OS: From noreply at buildbot.pypy.org Thu May 9 11:08:35 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 11:08:35 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Port killing of static linking to the release Message-ID: <20130509090835.7418A1C00F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: release-2.0.x Changeset: r63939:b9c3566aa017 Date: 2013-05-09 11:07 +0200 http://bitbucket.org/pypy/pypy/changeset/b9c3566aa017/ Log: Port killing of static linking to the release diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -65,9 +65,6 @@ separate_module_sources = [] if not _WIN32: - # On some platforms, we try to link statically libffi, which is small - # anyway and avoids endless troubles for installing. On other platforms - # libffi.a is typically not there, so we link dynamically. includes = ['ffi.h'] if _MAC_OS: @@ -75,27 +72,7 @@ else: pre_include_bits = [] - def find_libffi_a(): - dirlist = platform.library_dirs_for_libffi_a() - for dir in dirlist: - result = os.path.join(dir, 'libffi.a') - if os.path.exists(result): - return result - log.WARNING("'libffi.a' not found in %s" % (dirlist,)) - log.WARNING("trying to use the dynamic library instead...") - return None - - path_libffi_a = None - if hasattr(platform, 'library_dirs_for_libffi_a'): - path_libffi_a = find_libffi_a() - if path_libffi_a is not None: - # platforms on which we want static linking - libraries = [] - link_files = [path_libffi_a] - else: - # platforms on which we want dynamic linking - libraries = ['ffi'] - link_files = [] + libraries = ['ffi'] eci = ExternalCompilationInfo( pre_include_bits = pre_include_bits, @@ -104,7 +81,6 @@ separate_module_sources = separate_module_sources, include_dirs = platform.include_dirs_for_libffi(), library_dirs = platform.library_dirs_for_libffi(), - link_files = link_files, testonly_libraries = ['ffi'], ) elif _MINGW: diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -7,7 +7,6 @@ import sys, os link_files = [] -testonly_libraries = [] include_dirs = [] if sys.platform == 'win32' and platform.name != 'mingw32': libraries = ['libeay32', 'ssleay32', @@ -21,27 +20,8 @@ # so that openssl/ssl.h can repair this nonsense. 'wincrypt.h'] else: - libraries = ['z'] + libraries = ['z', 'ssl', 'crypto'] includes = [] - if (sys.platform.startswith('linux') and - os.path.exists('/usr/lib/libssl.a') and - os.path.exists('/usr/lib/libcrypto.a')): - # use static linking to avoid the infinite - # amount of troubles due to symbol versions - # and 0.9.8/1.0.0 - link_files += ['/usr/lib/libssl.a', '/usr/lib/libcrypto.a'] - testonly_libraries += ['ssl', 'crypto'] - elif (sys.platform.startswith('linux') and - os.path.exists('/usr/local/ssl/lib/libssl.a') and - os.path.exists('/usr/local/ssl/lib/libcrypto.a')): - # use static linking, 2nd version - include_dirs += ['/usr/local/ssl/include'] - link_files += ['/usr/local/ssl/lib/libssl.a', - '/usr/local/ssl/lib/libcrypto.a', - '-ldl'] - testonly_libraries += ['ssl', 'crypto'] - else: - libraries += ['ssl', 'crypto'] includes += [ 'openssl/ssl.h', @@ -54,7 +34,6 @@ eci = ExternalCompilationInfo( libraries = libraries, link_files = link_files, - testonly_libraries = testonly_libraries, includes = includes, include_dirs = include_dirs, export_symbols = [], From noreply at buildbot.pypy.org Thu May 9 18:50:37 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 18:50:37 +0200 (CEST) Subject: [pypy-commit] pypy default: work on the release announcement Message-ID: <20130509165037.29A121C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63940:e87dc2af9486 Date: 2013-05-09 18:49 +0200 http://bitbucket.org/pypy/pypy/changeset/e87dc2af9486/ Log: work on the release announcement diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -4,6 +4,8 @@ We're pleased to announce PyPy 2.0. This is a stable release that brings a swath of bugfixes, small performance improvements and compatibility fixes. +PyPy 2.0 is a big step for us and we hope in the future we'll be able to +provide stable releases more often. You can download the PyPy 2.0 release here: @@ -19,6 +21,10 @@ .. _`cffi`: http://cffi.readthedocs.org +If you're using PyPy for anything, it would help us immensly if you fill +the following survey: http://bit.ly/pypysurvey This is for the developers +eyes and we will not make any information public without your agreement. + What is PyPy? ============= From noreply at buildbot.pypy.org Thu May 9 18:57:33 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 18:57:33 +0200 (CEST) Subject: [pypy-commit] pypy default: typo Message-ID: <20130509165733.A7C111C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63941:187fda28863f Date: 2013-05-09 18:57 +0200 http://bitbucket.org/pypy/pypy/changeset/187fda28863f/ Log: typo diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -21,7 +21,7 @@ .. _`cffi`: http://cffi.readthedocs.org -If you're using PyPy for anything, it would help us immensly if you fill +If you're using PyPy for anything, it would help us immensely if you fill the following survey: http://bit.ly/pypysurvey This is for the developers eyes and we will not make any information public without your agreement. From noreply at buildbot.pypy.org Thu May 9 18:58:38 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 18:58:38 +0200 (CEST) Subject: [pypy-commit] pypy default: another typo Message-ID: <20130509165838.95DF21C1458@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63942:6229f69ce54d Date: 2013-05-09 18:57 +0200 http://bitbucket.org/pypy/pypy/changeset/6229f69ce54d/ Log: another typo diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -21,7 +21,7 @@ .. _`cffi`: http://cffi.readthedocs.org -If you're using PyPy for anything, it would help us immensely if you fill +If you're using PyPy for anything, it would help us immensely if you fill out the following survey: http://bit.ly/pypysurvey This is for the developers eyes and we will not make any information public without your agreement. From noreply at buildbot.pypy.org Thu May 9 19:11:17 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 19:11:17 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Added tag release-2.0.0 for changeset b9c3566aa017 Message-ID: <20130509171117.CDDED1C00F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: release-2.0.x Changeset: r63943:3d8b01ed1cc4 Date: 2013-05-09 19:10 +0200 http://bitbucket.org/pypy/pypy/changeset/3d8b01ed1cc4/ Log: Added tag release-2.0.0 for changeset b9c3566aa017 diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -3,3 +3,4 @@ d8ac7d23d3ec5f9a0fa1264972f74a010dbfd07f release-1.6 ff4af8f318821f7f5ca998613a60fca09aa137da release-1.7 07e08e9c885ca67d89bcc304e45a32346daea2fa release-2.0-beta-1 +b9c3566aa0170aaa736db0491d542c309ec7a5dc release-2.0.0 From noreply at buildbot.pypy.org Thu May 9 19:25:04 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 9 May 2013 19:25:04 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix this Message-ID: <20130509172504.F27DC1C0307@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63944:d9fbe2e2f230 Date: 2013-05-09 19:24 +0200 http://bitbucket.org/pypy/pypy/changeset/d9fbe2e2f230/ Log: Fix this diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -34,8 +34,8 @@ This release supports x86 machines running Linux 32/64, Mac OS X 64 or Windows 32. Windows 64 work is still stalling, we would welcome a volunteer -to handle that. ARM support is on the way and we're expecting to release -an alpha ARM version shortly. +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. .. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org From noreply at buildbot.pypy.org Thu May 9 19:25:56 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 19:25:56 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: work on download.txt, not regenerating sources so far Message-ID: <20130509172556.D6CE81C0307@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r408:e436ad58a098 Date: 2013-05-09 19:25 +0200 http://bitbucket.org/pypy/pypy.org/changeset/e436ad58a098/ Log: work on download.txt, not regenerating sources so far diff --git a/source/compat.txt b/source/compat.txt --- a/source/compat.txt +++ b/source/compat.txt @@ -9,8 +9,7 @@ of the commonly used Python `standard library modules`_; details below. PyPy has **alpha/beta-level** support for the `CPython C API`_, however, as of -2.0 beta2 -release this feature is not yet complete. Many libraries will require +2.0 release this feature is not yet complete. Many libraries will require a bit of effort to work, but there are known success stories. Check out PyPy blog for updates, as well as the `Compatibility Wiki`__. diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -10,15 +10,14 @@ There are `nightly binary builds`_ available. Those builds are not always as stable as the release, but they contain numerous bugfixes and - performance improvements. + performance improvements. **Note that the OS X build is slightly miscompiled + due to buildslave being old. Contributions are welcomed**. -Here are the binaries of the current release — **PyPy 2.0 beta2** — (`what's -new in PyPy 2.0 beta2?`_) for x86 Linux, Mac OS/X, Windows. There is also -**PyPy 2.0 alpha ARM** for ARM. +Here are the binaries of the current release — **PyPy 2.0** — (`what's +new in PyPy 2.0?`_) for x86 Linux, Mac OS/X, Windows. ARM support in +2.0 is alpha-level. -You can also find here the older 1.9 release. - -.. _what's new in PyPy 2.0 beta2?: http://doc.pypy.org/en/latest/release-2.0.0-beta2.html +.. _what's new in PyPy 2.0?: http://doc.pypy.org/en/latest/release-2.0.0.html .. class:: download_menu @@ -42,28 +41,52 @@ x86 CPUs that have the SSE2_ instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain `stackless`_ extensions, like `greenlets`_. -(This is the official release 2.0 beta2 and 1.9; +(This is the official release 2.0 for the most up-to-date version see below.) -2.0 beta2 ---------- +2.0 +--- + +Note that linux binaries are dynamically linked and might not be usable due +to a sad story of linux binary compatibility. We recommend either building from +source or downloading your PyPy from your release vendor. `Ubuntu`_ (`PPA`_), +`Debian`_, `Homebrew`_, +`Fedora`_, `Gentoo`_ and `Arch`_ are known to package PyPy, with various +degrees of being up-to-date. If you feel +like trying a statically linked binary (which we do not recommend using +in production due to potential future security issues), you can find +`32bit Linux`_ and `64bit Linux`_. + +.. _`Ubuntu`: http://packages.ubuntu.com/raring/pypy +.. _`PPA`: https://launchpad.net/~pypy/+archive/ppa +.. _`Debian`: http://packages.debian.org/experimental/pypy +.. _`Fedora`: http://fedoraproject.org/wiki/Features/PyPyStack +.. _`Gentoo`: http://packages.gentoo.org/package/dev-python/pypy +.. _`Homebrew`: https://github.com/mxcl/homebrew/blob/master/Library/Formula/pypy.rb +.. _`Arch`: https://wiki.archlinux.org/index.php/PyPy +.. _`32bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux.tar.bz2 +.. _`64bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux64.tar.bz2 * `Linux binary (32bit)`__ * `Linux binary (64bit) (libc 2.15)`__ -* Linux binary (64bit) (libc 2.13) (not available yet) -* Linux ARM binary (not available yet) * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) +* `Source (unix line endings)`__ +* `Source (also unix line endings, sorry)`__ -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-beta2-linux.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-beta2-linux64-libc2.15.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-beta2-osx64.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-beta2-win32.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux64.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-osx64.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-win32.zip .. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.zip -2.0 alpha ARM -------------- +2.0 for ARM alpha +----------------- + +**Note:** the following builds are alpha quality, for testing mostly * `Linux binary (32bit, armel)`__ * `Linux binary (32bit, armhf)`__ @@ -73,20 +96,6 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-alpha-arm-armhf.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-upstream_2.0~alpha+arm_armhf.deb -1.9 ---- - -* `Linux binary (32bit)`__ -* `Linux binary (64bit)`__ -* `Mac OS/X binary (64bit)`__ -* `Windows binary (32bit)`__ (you may need the `VS 2008 runtime library installer vcredist_x86.exe`_) - -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-1.9-linux.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-1.9-linux64.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-1.9-osx64.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-1.9-win32.zip -.. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582 - If your CPU is really old, it may not have SSE2. In this case, you need to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. @@ -102,10 +111,6 @@ not work for you, you might have more luck using `alternative nightly build`_, however linux binary distribution is hard. -* No JIT: A version without the JIT. Consumes a bit less memory - and may be faster on short-running scripts. (Note that a similar - effect can be obtained by running ``pypy --jit off``.) - * Sandboxing: A special safe version. Read the docs about sandboxing_. (It is also possible to translate_ a version that includes both sandboxing and the JIT compiler, although as the JIT is relatively @@ -126,7 +131,6 @@ `nightly build`_, or translate_ them yourself. .. _`nightly build`: http://buildbot.pypy.org/nightly/trunk/ -.. _`alternative nightly build`: http://baroquesoftware.com/nightlies/ Installing ------------------------------- @@ -145,17 +149,14 @@ Building from source ------------------------------- -**Warning:** the new gcc 4.8 doesn't compile the release branch of PyPy correctly. -As a workaround, run with ``CFLAGS=-fno-aggressive-loop-optimizations`` - 1. Get the source code. The following packages contain the source at the same revision as the above binaries: - * `pypy-2.0b2-src.tar.bz2`__ (sources, Unix line endings) - * `pypy-2.0b2-src.zip`__ (sources, Unix line endings too, sorry) + * `pypy-2.0-src.tar.bz2`__ (sources, Unix line endings) + * `pypy-2.0-src.zip`__ (sources, Unix line endings too, sorry) - .. __: https://bitbucket.org/pypy/pypy/get/release-2.0-beta2.tar.bz2 - .. __: https://bitbucket.org/pypy/pypy/get/release-2.0-beta2.zip + .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.tar.bz2 + .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.zip Or you can checkout the current trunk using Mercurial_ (the trunk usually works and is of course more up-to-date):: @@ -230,32 +231,20 @@ Here are the checksums for each of the downloads (md5 and sha1):: - 99f062eb516d8b6b5614f2350a65adab pypy-2.0-beta2-linux64-libc2.15.tar.bz2 - 61c2d5873ee62823bcf35b2e7086644f pypy-2.0-beta2-linux.tar.bz2 - f7ad21f79c8005b9c00c48e190ec662e pypy-2.0-beta2-osx64.tar.bz2 - 3b5250872a5e79034bb1a7c209f39391 pypy-2.0-beta2-win32.zip + f0d051c2b612b64dff496a6c0f3654fb pypy-2.0-win32.zip b9c36b99296c85a590c3e480b05d5a13 pypy-2.0-alpha-arm-armel.tar.bz2 2565ce68b4032eb306d998e722495694 pypy-2.0-alpha-arm-armhf.tar.bz2 b39d98de75f4948bfd2d606a8263ac1f pypy-upstream_2.0~alpha+arm_armhf.deb - 201d2cce2557e40c784473b471ee1b6b pypy-1.9-linux64.tar.bz2 - 1a08c88642434fc2e0e4256d351f48db pypy-1.9-linux.tar.bz2 - aad9c4b7b827583e37fe8ae0f7cfe0ff pypy-1.9-osx64.tar.bz2 - e7655066baed3c7bbbca7df617817dd5 pypy-1.9-win32.zip 2c9f0054f3b93a6473f10be35277825a pypy-1.8-sandbox-linux64.tar.bz2 009c970b5fa75754ae4c32a5d108a8d4 pypy-1.8-sandbox-linux.tar.bz2 - c6afb6dd3fcc57ba2c4144780a42412f release-2.0-beta2.tar.bz2 (source) + 4dc82e2240dd2b5be313119672988538 pypy-2.0-src.tar.bz2 + f965b50bc34c97891af77e6b743038f2 pypy-2.0-src.zip - 699fe12476a1783d6f91de59f48adc01c93c39df pypy-2.0-beta2-linux64-libc2.15.tar.bz2 - 591e661b091ed4849fdf5aab7e73393dea64016b pypy-2.0-beta2-linux.tar.bz2 - ec3d80d7806b0689d9da70ca27c741b1d9cea250 pypy-2.0-beta2-osx64.tar.bz2 - bb0604f32ba0e2af3c585a1af45dc887e0e95d34 pypy-2.0-beta2-win32.zip + cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc pypy-2.0-win32.zip dc09a293b85ab4f0032f6943815aaf5bbbceb645 pypy-2.0-alpha-arm-armel.tar.bz2 0971c4b668bfd2fcd52aa35087aa995e03bd5842 pypy-2.0-alpha-arm-armhf.tar.bz2 91910eb654ffbe0509bec2a7aeb460984acf8d82 pypy-upstream_2.0~alpha+arm_armhf.deb - 51be6b7b802a5239a759e04ae9595082e17c4c70 pypy-1.9-linux64.tar.bz2 - 1bc5d2467039b954f9b7395b3ee1b8407ce1c057 pypy-1.9-linux.tar.bz2 - 825e15724419fbdb6fe215eeea044f9181883c90 pypy-1.9-osx64.tar.bz2 - 4f060f4fab0f07bbc7de0ac8f95275eb08d726a3 pypy-1.9-win32.zip 895aaf7bba5787dd30adda5cc0e0e7fc297c0ca7 pypy-1.8-sandbox-linux64.tar.bz2 be94460bed8b2682880495435c309b6611ae2c31 pypy-1.8-sandbox-linux.tar.bz2 - 66d77a7ef98b9bff33a6ac19834c3a598bb9fa97 release-2.0-beta2.tar.bz2 (source) + d694824eeaa6169bce8d112149c9a5c7897534ed pypy-2.0-src.tar.bz2 + dc44cc9141a729ccc39b98432062bbe29c938432 pypy-2.0-src.zip diff --git a/source/features.txt b/source/features.txt --- a/source/features.txt +++ b/source/features.txt @@ -6,9 +6,9 @@ PyPy features =========================================================== -**PyPy 2.0 beta2** implements **Python 2.7.3** and runs on Intel -`x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms, with PPC being underway. -It supports all of the core language, passing the Python test suite +**PyPy 2.0** implements **Python 2.7.3** and runs on Intel +`x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms (alpha), with PPC being +underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python standard library modules. For known differences with CPython, see our diff --git a/source/index.txt b/source/index.txt --- a/source/index.txt +++ b/source/index.txt @@ -26,7 +26,7 @@ .. class:: download -`Download and try out the PyPy release 2.0 beta2!`__ +`Download and try out the PyPy release 2.0!`__ .. __: download.html From noreply at buildbot.pypy.org Thu May 9 19:29:17 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 19:29:17 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: rework this a bit Message-ID: <20130509172917.BF3E31C00F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r409:44c2ff85e805 Date: 2013-05-09 19:29 +0200 http://bitbucket.org/pypy/pypy.org/changeset/44c2ff85e805/ Log: rework this a bit diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -10,8 +10,9 @@ There are `nightly binary builds`_ available. Those builds are not always as stable as the release, but they contain numerous bugfixes and - performance improvements. **Note that the OS X build is slightly miscompiled - due to buildslave being old. Contributions are welcomed**. + performance improvements. **Note that the OS X nightly builds + (but not the release) are slightly + miscompiled due to buildslave being old. Contributions are welcomed**. Here are the binaries of the current release — **PyPy 2.0** — (`what's new in PyPy 2.0?`_) for x86 Linux, Mac OS/X, Windows. ARM support in From noreply at buildbot.pypy.org Thu May 9 19:33:03 2013 From: noreply at buildbot.pypy.org (mattip) Date: Thu, 9 May 2013 19:33:03 +0200 (CEST) Subject: [pypy-commit] pypy default: mention numpypy in release Message-ID: <20130509173303.B10411C0307@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r63945:70b2f8b1febc Date: 2013-05-09 20:29 +0300 http://bitbucket.org/pypy/pypy/changeset/70b2f8b1febc/ Log: mention numpypy in release diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -60,6 +60,10 @@ * A lot of stability issues fixed. +* Refactoring much of the numpypy array classes, which resulted in removal of + lazy expression evaluation. On the other hand, we now have more complete + dtype support and support more array attributes. + .. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ .. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks From noreply at buildbot.pypy.org Thu May 9 19:33:04 2013 From: noreply at buildbot.pypy.org (mattip) Date: Thu, 9 May 2013 19:33:04 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130509173304.EFBBE1C0307@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r63946:8472584e6074 Date: 2013-05-09 20:31 +0300 http://bitbucket.org/pypy/pypy/changeset/8472584e6074/ Log: merge heads diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -34,8 +34,8 @@ This release supports x86 machines running Linux 32/64, Mac OS X 64 or Windows 32. Windows 64 work is still stalling, we would welcome a volunteer -to handle that. ARM support is on the way and we're expecting to release -an alpha ARM version shortly. +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. .. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org From noreply at buildbot.pypy.org Thu May 9 19:33:12 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 9 May 2013 19:33:12 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Add a semicolon Message-ID: <20130509173312.D32211C0307@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r410:e26be3cf2cf6 Date: 2013-05-09 19:33 +0200 http://bitbucket.org/pypy/pypy.org/changeset/e26be3cf2cf6/ Log: Add a semicolon diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -42,7 +42,7 @@ x86 CPUs that have the SSE2_ instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain `stackless`_ extensions, like `greenlets`_. -(This is the official release 2.0 +(This is the official release 2.0; for the most up-to-date version see below.) 2.0 From noreply at buildbot.pypy.org Thu May 9 19:42:25 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 19:42:25 +0200 (CEST) Subject: [pypy-commit] pypy default: update docs Message-ID: <20130509174225.E74181C1451@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63947:13062596965a Date: 2013-05-09 19:41 +0200 http://bitbucket.org/pypy/pypy/changeset/13062596965a/ Log: update docs diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0-beta1' +release = '2.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -105,7 +105,7 @@ $ ./pypy-c Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``RPython magically makes you rich and famous (says so on the tin)'' @@ -235,7 +235,7 @@ the ``bin/pypy`` executable. To install PyPy system wide on unix-like systems, it is recommended to put the -whole hierarchy alone (e.g. in ``/opt/pypy2.0-beta1``) and put a symlink to the +whole hierarchy alone (e.g. in ``/opt/pypy2.0``) and put a symlink to the ``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -53,10 +53,10 @@ PyPy is ready to be executed as soon as you unpack the tarball or the zip file, with no need to install it in any specific location:: - $ tar xf pypy-2.0-beta1-linux.tar.bz2 - $ ./pypy-2.0-beta1/bin/pypy + $ tar xf pypy-2.0.tar.bz2 + $ ./pypy-2.0/bin/pypy Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``PyPy is an exciting technology that lets you to write fast, portable, multi-platform interpreters with less @@ -75,14 +75,14 @@ $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.0-beta1/bin/pypy distribute_setup.py + $ ./pypy-2.0/bin/pypy distribute_setup.py - $ ./pypy-2.0-beta1/bin/pypy get-pip.py + $ ./pypy-2.0/bin/pypy get-pip.py - $ ./pypy-2.0-beta1/bin/pip install pygments # for example + $ ./pypy-2.0/bin/pip install pygments # for example -3rd party libraries will be installed in ``pypy-2.0-beta1/site-packages``, and -the scripts in ``pypy-2.0-beta1/bin``. +3rd party libraries will be installed in ``pypy-2.0/site-packages``, and +the scripts in ``pypy-2.0/bin``. Installing using virtualenv --------------------------- diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0 beta 2`_: the latest official release +* `Release 2.0`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0 beta 2`: http://pypy.org/download.html +.. _`Release 2.0`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html From noreply at buildbot.pypy.org Thu May 9 19:43:14 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 19:43:14 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update the website Message-ID: <20130509174314.6722B1C1451@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r411:bcb031cb8e50 Date: 2013-05-09 19:42 +0200 http://bitbucket.org/pypy/pypy.org/changeset/bcb031cb8e50/ Log: update the website diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -51,8 +51,7 @@ already accepted in the main python in newer versions). It supports most of the commonly used Python standard library modules; details below.

      PyPy has alpha/beta-level support for the CPython C API, however, as of -2.0 beta2 -release this feature is not yet complete. Many libraries will require +2.0 release this feature is not yet complete. Many libraries will require a bit of effort to work, but there are known success stories. Check out PyPy blog for updates, as well as the Compatibility Wiki.

      C extensions need to be recompiled for PyPy in order to work. Depending on diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -48,11 +48,12 @@

      Download and install

      There are nightly binary builds available. Those builds are not always as stable as the release, but they contain numerous bugfixes and -performance improvements.

      -

      Here are the binaries of the current release — PyPy 2.0 beta2 — (what's -new in PyPy 2.0 beta2?) for x86 Linux, Mac OS/X, Windows. There is also -PyPy 2.0 alpha ARM for ARM.

      -

      You can also find here the older 1.9 release.

      +performance improvements. Note that the OS X nightly builds +(but not the release) are slightly +miscompiled due to buildslave being old. Contributions are welcomed.

      +

      Here are the binaries of the current release — PyPy 2.0 — (what's +new in PyPy 2.0?) for x86 Linux, Mac OS/X, Windows. ARM support in +2.0 is alpha-level.

      • Download
        • Default (with a JIT Compiler)
        • @@ -70,37 +71,38 @@ x86 CPUs that have the SSE2 instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain stackless extensions, like greenlets. -(This is the official release 2.0 beta2 and 1.9; +(This is the official release 2.0; for the most up-to-date version see below.)

      -
      -

      2.0 beta2

      +
      +

      2.0

      +

      Note that linux binaries are dynamically linked and might not be usable due +to a sad story of linux binary compatibility. We recommend either building from +source or downloading your PyPy from your release vendor. Ubuntu (PPA), +Debian, Homebrew, +Fedora, Gentoo and Arch are known to package PyPy, with various +degrees of being up-to-date. If you feel +like trying a statically linked binary (which we do not recommend using +in production due to potential future security issues), you can find +32bit Linux and 64bit Linux.

      -
      -

      2.0 alpha ARM

      +
      +

      2.0 for ARM alpha

      +

      Note: the following builds are alpha quality, for testing mostly

      -
      -
      -

      1.9

      -

      If your CPU is really old, it may not have SSE2. In this case, you need to translate yourself with the option --jit-backend=x86-without-sse2.

      @@ -110,11 +112,8 @@
      • The most up-to-date nightly build with a JIT, if the official release is too old for what you want to do. If the nightly build does -not work for you, you might have more luck using alternative nightly build, +not work for you, you might have more luck using `alternative nightly build`_, however linux binary distribution is hard.
      • -
      • No JIT: A version without the JIT. Consumes a bit less memory -and may be faster on short-running scripts. (Note that a similar -effect can be obtained by running pypy --jit off.)
      • Sandboxing: A special safe version. Read the docs about sandboxing. (It is also possible to translate a version that includes both sandboxing and the JIT compiler, although as the JIT is relatively @@ -142,14 +141,12 @@

      Building from source

      -

      Warning: the new gcc 4.8 doesn't compile the release branch of PyPy correctly. -As a workaround, run with CFLAGS=-fno-aggressive-loop-optimizations

      1. Get the source code. The following packages contain the source at the same revision as the above binaries:

        Or you can checkout the current trunk using Mercurial (the trunk usually works and is of course more up-to-date):

        @@ -216,36 +213,30 @@

        Checksums

        Here are the checksums for each of the downloads (md5 and sha1):

        -99f062eb516d8b6b5614f2350a65adab  pypy-2.0-beta2-linux64-libc2.15.tar.bz2
        -61c2d5873ee62823bcf35b2e7086644f  pypy-2.0-beta2-linux.tar.bz2
        -f7ad21f79c8005b9c00c48e190ec662e  pypy-2.0-beta2-osx64.tar.bz2
        -3b5250872a5e79034bb1a7c209f39391  pypy-2.0-beta2-win32.zip
        +f0d051c2b612b64dff496a6c0f3654fb  pypy-2.0-win32.zip
         b9c36b99296c85a590c3e480b05d5a13  pypy-2.0-alpha-arm-armel.tar.bz2
         2565ce68b4032eb306d998e722495694  pypy-2.0-alpha-arm-armhf.tar.bz2
         b39d98de75f4948bfd2d606a8263ac1f  pypy-upstream_2.0~alpha+arm_armhf.deb
        -201d2cce2557e40c784473b471ee1b6b  pypy-1.9-linux64.tar.bz2
        -1a08c88642434fc2e0e4256d351f48db  pypy-1.9-linux.tar.bz2
        -aad9c4b7b827583e37fe8ae0f7cfe0ff  pypy-1.9-osx64.tar.bz2
        -e7655066baed3c7bbbca7df617817dd5  pypy-1.9-win32.zip
         2c9f0054f3b93a6473f10be35277825a  pypy-1.8-sandbox-linux64.tar.bz2
         009c970b5fa75754ae4c32a5d108a8d4  pypy-1.8-sandbox-linux.tar.bz2
        -c6afb6dd3fcc57ba2c4144780a42412f  release-2.0-beta2.tar.bz2 (source)
        -699fe12476a1783d6f91de59f48adc01c93c39df  pypy-2.0-beta2-linux64-libc2.15.tar.bz2
        -591e661b091ed4849fdf5aab7e73393dea64016b  pypy-2.0-beta2-linux.tar.bz2
        -ec3d80d7806b0689d9da70ca27c741b1d9cea250  pypy-2.0-beta2-osx64.tar.bz2
        -bb0604f32ba0e2af3c585a1af45dc887e0e95d34  pypy-2.0-beta2-win32.zip
        +4dc82e2240dd2b5be313119672988538  pypy-2.0-src.tar.bz2
        +f965b50bc34c97891af77e6b743038f2  pypy-2.0-src.zip
        +cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc  pypy-2.0-win32.zip
         dc09a293b85ab4f0032f6943815aaf5bbbceb645  pypy-2.0-alpha-arm-armel.tar.bz2
         0971c4b668bfd2fcd52aa35087aa995e03bd5842  pypy-2.0-alpha-arm-armhf.tar.bz2
         91910eb654ffbe0509bec2a7aeb460984acf8d82  pypy-upstream_2.0~alpha+arm_armhf.deb
        -51be6b7b802a5239a759e04ae9595082e17c4c70  pypy-1.9-linux64.tar.bz2
        -1bc5d2467039b954f9b7395b3ee1b8407ce1c057  pypy-1.9-linux.tar.bz2
        -825e15724419fbdb6fe215eeea044f9181883c90  pypy-1.9-osx64.tar.bz2
        -4f060f4fab0f07bbc7de0ac8f95275eb08d726a3  pypy-1.9-win32.zip
         895aaf7bba5787dd30adda5cc0e0e7fc297c0ca7  pypy-1.8-sandbox-linux64.tar.bz2
         be94460bed8b2682880495435c309b6611ae2c31  pypy-1.8-sandbox-linux.tar.bz2
        -66d77a7ef98b9bff33a6ac19834c3a598bb9fa97  release-2.0-beta2.tar.bz2 (source)
        +d694824eeaa6169bce8d112149c9a5c7897534ed  pypy-2.0-src.tar.bz2
        +dc44cc9141a729ccc39b98432062bbe29c938432  pypy-2.0-src.zip
         
      +
      +

      Docutils System Messages

      +
      +

      System Message: ERROR/3 ([dynamic-text], line 105); backlink

      +Unknown target name: “alternative nightly build”.
      +
      diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -46,9 +46,9 @@

      Features

      -

      PyPy 2.0 beta2 implements Python 2.7.3 and runs on Intel -x86 (IA-32) , x86_64 and ARM platforms, with PPC being underway. -It supports all of the core language, passing the Python test suite +

      PyPy 2.0 implements Python 2.7.3 and runs on Intel +x86 (IA-32) , x86_64 and ARM platforms (alpha), with PPC being +underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python in newer versions). It supports most of the commonly used Python standard library modules. For known differences with CPython, see our diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -64,7 +64,7 @@

    • As well as other features.
    -

    Download and try out the PyPy release 2.0 beta2!

    +

    Download and try out the PyPy release 2.0!

    Want to know more? A good place to start is our detailed speed and compatibility reports!

    diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -70,7 +70,7 @@ * `Linux binary (32bit)`__ * `Linux binary (64bit) (libc 2.15)`__ -* `Mac OS/X binary (64bit)`__ +* `Mac OS/X binary (64bit)`__ (still building, the link might be broken) * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) * `Source (unix line endings)`__ From noreply at buildbot.pypy.org Thu May 9 20:37:46 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 9 May 2013 20:37:46 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: update download Message-ID: <20130509183746.A26701C1466@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r412:cfd623c140f5 Date: 2013-05-09 20:37 +0200 http://bitbucket.org/pypy/pypy.org/changeset/cfd623c140f5/ Log: update download diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -88,7 +88,7 @@
    • Linux binary (32bit)
    • Linux binary (64bit) (libc 2.15)
    • -
    • Mac OS/X binary (64bit) (still building, the link might be broken)
    • +
    • Mac OS/X binary (64bit)
    • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
    • Source (unix line endings)
    • @@ -111,9 +111,8 @@

      The other versions of PyPy are:

      • The most up-to-date nightly build with a JIT, if the official -release is too old for what you want to do. If the nightly build does -not work for you, you might have more luck using `alternative nightly build`_, -however linux binary distribution is hard.
      • +release is too old for what you want to do. There are versions for +different libc on this site too.
      • Sandboxing: A special safe version. Read the docs about sandboxing. (It is also possible to translate a version that includes both sandboxing and the JIT compiler, although as the JIT is relatively @@ -213,6 +212,9 @@

        Checksums

        Here are the checksums for each of the downloads (md5 and sha1):

        +756d738d8f35924357150fe1b6d33f86  pypy-2.0-linux64.tar.bz2
        +267c46ed8c591da19b6091aa90fa9acf  pypy-2.0-linux.tar.bz2
        +39837722da4a03ca03eda187aafa13bb  pypy-2.0-osx64.tar.bz2
         f0d051c2b612b64dff496a6c0f3654fb  pypy-2.0-win32.zip
         b9c36b99296c85a590c3e480b05d5a13  pypy-2.0-alpha-arm-armel.tar.bz2
         2565ce68b4032eb306d998e722495694  pypy-2.0-alpha-arm-armhf.tar.bz2
        @@ -221,6 +223,9 @@
         009c970b5fa75754ae4c32a5d108a8d4  pypy-1.8-sandbox-linux.tar.bz2
         4dc82e2240dd2b5be313119672988538  pypy-2.0-src.tar.bz2
         f965b50bc34c97891af77e6b743038f2  pypy-2.0-src.zip
        +88aacc21c6c552b3ff3a157a7575a9dca7e4a7c3  pypy-2.0-linux64.tar.bz2
        +b2e64ca5e38a59c3402185cca08ca5a4d507ff7e  pypy-2.0-linux.tar.bz2
        +65ecb2ba570f05691978c64469cfe3e76bfd8e01  pypy-2.0-osx64.tar.bz2
         cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc  pypy-2.0-win32.zip
         dc09a293b85ab4f0032f6943815aaf5bbbceb645  pypy-2.0-alpha-arm-armel.tar.bz2
         0971c4b668bfd2fcd52aa35087aa995e03bd5842  pypy-2.0-alpha-arm-armhf.tar.bz2
        @@ -231,12 +236,6 @@
         dc44cc9141a729ccc39b98432062bbe29c938432  pypy-2.0-src.zip
         
    -
    -

    Docutils System Messages

    -
    -

    System Message: ERROR/3 ([dynamic-text], line 105); backlink

    -Unknown target name: “alternative nightly build”.
    -
    diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -70,7 +70,7 @@ * `Linux binary (32bit)`__ * `Linux binary (64bit) (libc 2.15)`__ -* `Mac OS/X binary (64bit)`__ (still building, the link might be broken) +* `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) * `Source (unix line endings)`__ @@ -108,9 +108,8 @@ The other versions of PyPy are: * The most up-to-date `nightly build`_ with a JIT, if the official - release is too old for what you want to do. If the nightly build does - not work for you, you might have more luck using `alternative nightly build`_, - however linux binary distribution is hard. + release is too old for what you want to do. There are versions for + different libc on this site too. * Sandboxing: A special safe version. Read the docs about sandboxing_. (It is also possible to translate_ a version that includes both @@ -232,6 +231,9 @@ Here are the checksums for each of the downloads (md5 and sha1):: + 756d738d8f35924357150fe1b6d33f86 pypy-2.0-linux64.tar.bz2 + 267c46ed8c591da19b6091aa90fa9acf pypy-2.0-linux.tar.bz2 + 39837722da4a03ca03eda187aafa13bb pypy-2.0-osx64.tar.bz2 f0d051c2b612b64dff496a6c0f3654fb pypy-2.0-win32.zip b9c36b99296c85a590c3e480b05d5a13 pypy-2.0-alpha-arm-armel.tar.bz2 2565ce68b4032eb306d998e722495694 pypy-2.0-alpha-arm-armhf.tar.bz2 @@ -241,6 +243,9 @@ 4dc82e2240dd2b5be313119672988538 pypy-2.0-src.tar.bz2 f965b50bc34c97891af77e6b743038f2 pypy-2.0-src.zip + 88aacc21c6c552b3ff3a157a7575a9dca7e4a7c3 pypy-2.0-linux64.tar.bz2 + b2e64ca5e38a59c3402185cca08ca5a4d507ff7e pypy-2.0-linux.tar.bz2 + 65ecb2ba570f05691978c64469cfe3e76bfd8e01 pypy-2.0-osx64.tar.bz2 cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc pypy-2.0-win32.zip dc09a293b85ab4f0032f6943815aaf5bbbceb645 pypy-2.0-alpha-arm-armel.tar.bz2 0971c4b668bfd2fcd52aa35087aa995e03bd5842 pypy-2.0-alpha-arm-armhf.tar.bz2 From noreply at buildbot.pypy.org Thu May 9 22:12:44 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Thu, 9 May 2013 22:12:44 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Implement pickling for record dtypes Message-ID: <20130509201244.0D06C1C05B7@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r63948:bf43d52d5d8b Date: 2013-05-09 22:07 +0200 http://bitbucket.org/pypy/pypy/changeset/bf43d52d5d8b/ Log: Implement pickling for record dtypes diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -137,18 +137,22 @@ if w_fields == space.w_None: self.fields = None else: - iter = space.iter(w_fields) - while True: - try: - key = space.next(iter) - value = space.getitem(w_fields, key) - dtype = space.getitem(value, space.wrap(0)) - assert isinstance(dtype, W_Dtype) - self.fields[space.str_w(space.next(iter))] = space.int_w(space.getitem(value, space.wrap(1))), dtype - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break + ofs_and_items = [] + size = 0 + for key in space.listview(w_fields): + value = space.getitem(w_fields, key) + + dtype = space.getitem(value, space.wrap(0)) + assert isinstance(dtype, W_Dtype) + + offset = space.int_w(space.getitem(value, space.wrap(1))) + self.fields[space.str_w(key)] = offset, dtype + + ofs_and_items.append((offset, dtype.itemtype)) + size += dtype.itemtype.get_element_size() + + self.itemtype = types.RecordType(ofs_and_items, size) + self.name = "void" + str(8 * self.itemtype.get_element_size()) def descr_get_names(self, space): if self.fieldnames is None: @@ -249,11 +253,12 @@ self.native = space.str_w(space.getitem(w_data, space.wrap(1))) == byteorder_prefix - fieldnames = space.getitem(w_data, space.wrap(2)) + fieldnames = space.getitem(w_data, space.wrap(3)) self.set_names(space, fieldnames) - fields = space.getitem(w_data, space.wrap(3)) + fields = space.getitem(w_data, space.wrap(4)) self.set_fields(space, fields) + print self.itemtype class W_ComplexDtype(W_Dtype): def __init__(self, itemtype, num, kind, name, char, w_box_type, @@ -313,8 +318,7 @@ num = 20 basename = 'void' w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - raise OperationError(space.w_NotImplementedError, space.wrap( - "pure void dtype")) + return dtype_from_list(space, space.newlist([])) else: assert char == 'U' basename = 'unicode' diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -281,9 +281,13 @@ def test_pickle_record(self): from numpypy import array, dtype from cPickle import loads, dumps - skip("TODO") - a = array(([0, 0], [0, 0]), dtype=[('x', ' Author: Armin Rigo Branch: extradoc Changeset: r413:435b4bed2864 Date: 2013-05-09 22:44 +0200 http://bitbucket.org/pypy/pypy.org/changeset/435b4bed2864/ Log: Tweaks. diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -91,9 +91,11 @@
  • Mac OS/X binary (64bit)
  • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
  • -
  • Source (unix line endings)
  • -
  • Source (also unix line endings, sorry)
  • +
  • Source (tar.bz2, unix line endings)
  • +
  • Source (zip, also unix line endings, sorry)
  • +

    If your CPU is really old, it may not have SSE2. In this case, you need +to translate yourself with the option --jit-backend=x86-without-sse2.

    2.0 for ARM alpha

    @@ -103,8 +105,6 @@
  • Linux binary (32bit, armhf)
  • Linux deb for raspbian (raspberry pi)
  • -

    If your CPU is really old, it may not have SSE2. In this case, you need -to translate yourself with the option --jit-backend=x86-without-sse2.

    Other versions

    @@ -118,7 +118,8 @@ sandboxing and the JIT compiler, although as the JIT is relatively complicated, this reduces a bit the level of confidence we can put in the result.) Note that the sandboxed binary needs a full pypy checkout -to work. Consult the sandbox docs for details
      +to work. Consult the sandbox docs for details. (These are old, +PyPy 1.8.) diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -73,8 +73,8 @@ * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) -* `Source (unix line endings)`__ -* `Source (also unix line endings, sorry)`__ +* `Source (tar.bz2, unix line endings)`__ +* `Source (zip, also unix line endings, sorry)`__ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux64.tar.bz2 @@ -84,6 +84,9 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.zip +If your CPU is really old, it may not have SSE2. In this case, you need +to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. + 2.0 for ARM alpha ----------------- @@ -97,9 +100,6 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-alpha-arm-armhf.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-upstream_2.0~alpha+arm_armhf.deb -If your CPU is really old, it may not have SSE2. In this case, you need -to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. - .. _`Other versions (without a JIT)`: Other versions @@ -116,7 +116,8 @@ sandboxing and the JIT compiler, although as the JIT is relatively complicated, this reduces a bit the level of confidence we can put in the result.) **Note that the sandboxed binary needs a full pypy checkout - to work**. Consult the `sandbox docs`_ for details + to work**. Consult the `sandbox docs`_ for details. (These are old, + PyPy 1.8.) * `Linux binary (64bit)`__ From noreply at buildbot.pypy.org Thu May 9 23:48:28 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 9 May 2013 23:48:28 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Give proper distribution names in our fully-shared linux binaries. Message-ID: <20130509214828.F03D01C1466@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r414:358712681466 Date: 2013-05-09 23:48 +0200 http://bitbucket.org/pypy/pypy.org/changeset/358712681466/ Log: Give proper distribution names in our fully-shared linux binaries. diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -86,8 +86,8 @@ in production due to potential future security issues), you can find 32bit Linux and 64bit Linux.

        -
      • Linux binary (32bit)
      • -
      • Linux binary (64bit) (libc 2.15)
      • +
      • Linux binary (32bit, Debian 6.0 “squeeze”)
      • +
      • Linux binary (64bit, Ubuntu 12.04.2)
      • Mac OS/X binary (64bit)
      • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
      • diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -68,8 +68,8 @@ .. _`32bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux.tar.bz2 .. _`64bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux64.tar.bz2 -* `Linux binary (32bit)`__ -* `Linux binary (64bit) (libc 2.15)`__ +* `Linux binary (32bit, Debian 6.0 "squeeze")`__ +* `Linux binary (64bit, Ubuntu 12.04.2)`__ * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) From noreply at buildbot.pypy.org Thu May 9 23:52:44 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 9 May 2013 23:52:44 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Be precise Message-ID: <20130509215244.A7F281C146E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r415:2666b4308f34 Date: 2013-05-09 23:52 +0200 http://bitbucket.org/pypy/pypy.org/changeset/2666b4308f34/ Log: Be precise diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -87,7 +87,7 @@ 32bit Linux and 64bit Linux.

        • Linux binary (32bit, Debian 6.0 “squeeze”)
        • -
        • Linux binary (64bit, Ubuntu 12.04.2)
        • +
        • Linux binary (64bit, Ubuntu 12.04.2 LTS)
        • Mac OS/X binary (64bit)
        • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
        • diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -69,7 +69,7 @@ .. _`64bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux64.tar.bz2 * `Linux binary (32bit, Debian 6.0 "squeeze")`__ -* `Linux binary (64bit, Ubuntu 12.04.2)`__ +* `Linux binary (64bit, Ubuntu 12.04.2 LTS)`__ * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) From noreply at buildbot.pypy.org Thu May 9 23:58:19 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 9 May 2013 23:58:19 +0200 (CEST) Subject: [pypy-commit] pypy default: Update the version in trunk Message-ID: <20130509215819.EC7371C146E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63949:026f4d54f861 Date: 2013-05-09 23:57 +0200 http://bitbucket.org/pypy/pypy/changeset/026f4d54f861/ Log: Update the version in trunk diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.3" /* PyPy version as a string */ -#define PYPY_VERSION "2.0.0-beta2" +#define PYPY_VERSION "2.1.0-alpha0" /* Subversion Revision number of this file (not of the repository). * Empty since Mercurial migration. */ diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -11,7 +11,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (2, 0, 0, "beta", 2) #XXX # sync patchlevel.h +PYPY_VERSION = (2, 1, 0, "alpha", 0) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) From noreply at buildbot.pypy.org Fri May 10 00:15:59 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 10 May 2013 00:15:59 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Be more precise Message-ID: <20130509221559.38CEB1C05B7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r416:dca6e46cf805 Date: 2013-05-10 00:15 +0200 http://bitbucket.org/pypy/pypy.org/changeset/dca6e46cf805/ Log: Be more precise diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -86,8 +86,8 @@ in production due to potential future security issues), you can find 32bit Linux and 64bit Linux.

            -
          • Linux binary (32bit, Debian 6.0 “squeeze”)
          • -
          • Linux binary (64bit, Ubuntu 12.04.2 LTS)
          • +
          • Linux binary (32bit, tar.bz2 tested on Debian 6.0 “squeeze”)
          • +
          • Linux binary (64bit, tar.bz2 tested on Ubuntu 12.04.2 LTS)
          • Mac OS/X binary (64bit)
          • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
          • diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -68,8 +68,8 @@ .. _`32bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux.tar.bz2 .. _`64bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux64.tar.bz2 -* `Linux binary (32bit, Debian 6.0 "squeeze")`__ -* `Linux binary (64bit, Ubuntu 12.04.2 LTS)`__ +* `Linux binary (32bit, tar.bz2 tested on Debian 6.0 "squeeze")`__ +* `Linux binary (64bit, tar.bz2 tested on Ubuntu 12.04.2 LTS)`__ * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) From noreply at buildbot.pypy.org Fri May 10 00:17:22 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 10 May 2013 00:17:22 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Stop being sorry about Unix line endings: most tools on Windows can cope Message-ID: <20130509221722.E16171C05B7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r417:c9d4e13e4b2d Date: 2013-05-10 00:17 +0200 http://bitbucket.org/pypy/pypy.org/changeset/c9d4e13e4b2d/ Log: Stop being sorry about Unix line endings: most tools on Windows can cope diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -73,8 +73,8 @@ * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) -* `Source (tar.bz2, unix line endings)`__ -* `Source (zip, also unix line endings, sorry)`__ +* `Source (tar.bz2)`__ +* `Source (zip)`__ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux64.tar.bz2 From noreply at buildbot.pypy.org Fri May 10 00:17:37 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 10 May 2013 00:17:37 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: regen Message-ID: <20130509221737.5F0591C05B7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r418:4c8600c22830 Date: 2013-05-10 00:17 +0200 http://bitbucket.org/pypy/pypy.org/changeset/4c8600c22830/ Log: regen diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -91,8 +91,8 @@
          • Mac OS/X binary (64bit)
          • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
          • -
          • Source (tar.bz2, unix line endings)
          • -
          • Source (zip, also unix line endings, sorry)
          • +
          • Source (tar.bz2)
          • +
          • Source (zip)

          If your CPU is really old, it may not have SSE2. In this case, you need to translate yourself with the option --jit-backend=x86-without-sse2.

          From noreply at buildbot.pypy.org Fri May 10 00:20:44 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 10 May 2013 00:20:44 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Kill this outdatish paragraph Message-ID: <20130509222044.5911B1C00F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r419:4631a15c09c0 Date: 2013-05-10 00:20 +0200 http://bitbucket.org/pypy/pypy.org/changeset/4631a15c09c0/ Log: Kill this outdatish paragraph diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -125,9 +125,6 @@
      -

      These versions are not officially part of the releases, which focuses -on the JIT. You can find prebuilt binaries for them on our -nightly build, or translate them yourself.

    Installing

    diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -127,10 +127,6 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-1.8-sandbox-linux.tar.bz2 .. _`sandbox docs`: http://doc.pypy.org/en/latest/sandbox.html -These versions are not officially part of the releases, which focuses -on the JIT. You can find prebuilt binaries for them on our -`nightly build`_, or translate_ them yourself. - .. _`nightly build`: http://buildbot.pypy.org/nightly/trunk/ Installing From noreply at buildbot.pypy.org Fri May 10 00:34:17 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 10 May 2013 00:34:17 +0200 (CEST) Subject: [pypy-commit] pypy py3k-newhash: merge py3k Message-ID: <20130509223417.E0D131C1055@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k-newhash Changeset: r63950:925322f499da Date: 2013-05-09 11:55 -0700 http://bitbucket.org/pypy/pypy/changeset/925322f499da/ Log: merge py3k diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -11,7 +11,7 @@ g = open(filename, 'w') print >> g, '''\ import sys -_size = 32 if sys.maxint <= 2**32 else 64 +_size = 32 if sys.maxsize <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib _mod = __import__("_%s_%%s_" %% (_size,), diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -46,7 +46,7 @@ rnd = _random.Random() rnd.seed() different_nums = [] - mask = sys.maxint * 2 + 1 + mask = sys.maxsize * 2 + 1 for obj in ["spam and eggs", 3.14, 1+2j, 'a', tuple('abc')]: nums = [] for o in [obj, hash(obj) & mask, -(hash(obj) & mask)]: From noreply at buildbot.pypy.org Fri May 10 00:34:19 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 10 May 2013 00:34:19 +0200 (CEST) Subject: [pypy-commit] pypy py3k-newhash: modernize int's hash: it's now x modulo the new HASH_MODULUS. Message-ID: <20130509223419.3ED711C1055@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k-newhash Changeset: r63951:34a0157937d1 Date: 2013-05-09 15:32 -0700 http://bitbucket.org/pypy/pypy/changeset/34a0157937d1/ Log: modernize int's hash: it's now x modulo the new HASH_MODULUS. an exact port of CPython's impl is tricky for 64bit because it assumes HASH_BITS (61) >= rbigint's SHIFT (63), which isn't true on PyPy. so our algorithm differs and we calculate the hash via the 'wide' type like many rbigint methods diff --git a/pypy/module/sys/system.py b/pypy/module/sys/system.py --- a/pypy/module/sys/system.py +++ b/pypy/module/sys/system.py @@ -3,6 +3,7 @@ from rpython.rlib import rfloat, rbigint from rpython.rtyper.lltypesystem import rffi, lltype from pypy.objspace.std.floatobject import HASH_INF, HASH_MODULUS, HASH_NAN +from pypy.objspace.std.longobject import HASH_MODULUS from pypy.objspace.std.complexobject import HASH_IMAG diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -1,5 +1,4 @@ import operator -import sys from pypy.interpreter.error import OperationError from pypy.objspace.std import model, newformat from pypy.objspace.std.floattype import float_typedef, W_AbstractFloatObject @@ -7,7 +6,8 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.noneobject import W_NoneObject -from pypy.objspace.std.longobject import W_LongObject, newlong_from_float +from pypy.objspace.std.longobject import ( + HASH_BITS, HASH_MODULUS, W_LongObject, newlong_from_float) from rpython.rlib.rarithmetic import ( LONG_BIT, intmask, ovfcheck_float_to_int, r_uint) from rpython.rlib.rfloat import ( @@ -23,8 +23,6 @@ HASH_INF = 314159 HASH_NAN = 0 -HASH_BITS = 61 if sys.maxsize > 2 ** 31 - 1 else 31 -HASH_MODULUS = (1 << HASH_BITS) - 1 class W_FloatObject(W_AbstractFloatObject): """This is a implementation of the app-level 'float' type. diff --git a/pypy/objspace/std/longobject.py b/pypy/objspace/std/longobject.py --- a/pypy/objspace/std/longobject.py +++ b/pypy/objspace/std/longobject.py @@ -6,9 +6,12 @@ from pypy.objspace.std.multimethod import FailedToImplementArgs from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.noneobject import W_NoneObject -from rpython.rlib.rbigint import rbigint +from rpython.rlib.rarithmetic import intmask +from rpython.rlib.rbigint import SHIFT, _widen_digit, rbigint from pypy.objspace.std.longtype import long_typedef, W_AbstractLongObject +HASH_BITS = 61 if sys.maxsize > 2 ** 31 - 1 else 31 +HASH_MODULUS = 2 ** HASH_BITS - 1 class W_LongObject(W_AbstractLongObject): """This is a wrapper of rbigint.""" @@ -192,7 +195,26 @@ def hash__Long(space, w_value): - return space.wrap(w_value.num.hash()) + return space.wrap(_hash_long(space, w_value.num)) + +def _hash_long(space, v): + i = v.numdigits() - 1 + if i == -1: + return 0 + + # compute v % HASH_MODULUS + x = _widen_digit(0) + while i >= 0: + x = (x << SHIFT) + v.widedigit(i) + # efficient x % HASH_MODULUS: as HASH_MODULUS is a Mersenne + # prime + x = (x & HASH_MODULUS) + (x >> HASH_BITS) + while x >= HASH_MODULUS: + x -= HASH_MODULUS + i -= 1 + x = intmask(intmask(x) * v.sign) + return -2 if x == -1 else x + def add__Long_Long(space, w_long1, w_long2): return W_LongObject(w_long1.num.add(w_long2.num)) diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py --- a/pypy/objspace/std/test/test_floatobject.py +++ b/pypy/objspace/std/test/test_floatobject.py @@ -95,8 +95,6 @@ assert 42.0 == float(42) def test_float_hash(self): - # these are taken from standard Python, which produces - # the same but for -1. import math import sys diff --git a/pypy/objspace/std/test/test_longobject.py b/pypy/objspace/std/test/test_longobject.py --- a/pypy/objspace/std/test/test_longobject.py +++ b/pypy/objspace/std/test/test_longobject.py @@ -221,14 +221,23 @@ assert x ^ 0x555555555 == 0x5FFFFFFFF def test_hash(self): - # ints have the same hash as equal longs - for i in range(-4, 14): - assert hash(i) == hash(int(i)) - # might check too much -- it's ok to change the hashing algorithm - assert hash(123456789) == 123456789 - assert hash(1234567890123456789) in ( - -1895067127, # with 32-bit platforms - 1234567890123456789) # with 64-bit platforms + import sys + modulus = sys.hash_info.modulus + for x in (list(range(200)) + + [1234567890123456789, 18446743523953737727, + 987685321987685321987685321987685321987685321]): + y = x % modulus + assert hash(x) == hash(y) + assert hash(-x) == hash(-y) + assert hash(modulus - 1) == modulus - 1 + assert hash(modulus) == 0 + assert hash(modulus + 1) == 1 + + assert hash(-1) == -2 + value = -(modulus + 1) + assert hash(value) == -2 + assert hash(value * 2 + 1) == -2 + assert hash(value * 4 + 3) == -2 def test_math_log(self): import math From noreply at buildbot.pypy.org Fri May 10 01:20:42 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 10 May 2013 01:20:42 +0200 (CEST) Subject: [pypy-commit] pypy py3k-newhash: adjust per int's new hash Message-ID: <20130509232042.DCC1A1C05B7@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k-newhash Changeset: r63952:1fefbf049c7c Date: 2013-05-09 16:20 -0700 http://bitbucket.org/pypy/pypy/changeset/1fefbf049c7c/ Log: adjust per int's new hash diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py --- a/pypy/module/cpyext/test/test_object.py +++ b/pypy/module/cpyext/test/test_object.py @@ -168,7 +168,7 @@ def test_hash(self, space, api): assert api.PyObject_Hash(space.wrap(72)) == 72 - assert api.PyObject_Hash(space.wrap(-1)) == -1 + assert api.PyObject_Hash(space.wrap(-1)) == -2 assert (api.PyObject_Hash(space.wrap([])) == -1 and api.PyErr_Occurred() is space.w_TypeError) api.PyErr_Clear() From noreply at buildbot.pypy.org Fri May 10 03:03:39 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 10 May 2013 03:03:39 +0200 (CEST) Subject: [pypy-commit] pypy py3k-newhash: close to be merged branch Message-ID: <20130510010339.9572E1C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k-newhash Changeset: r63953:b7ea75335567 Date: 2013-05-09 18:01 -0700 http://bitbucket.org/pypy/pypy/changeset/b7ea75335567/ Log: close to be merged branch From noreply at buildbot.pypy.org Fri May 10 03:15:41 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 10 May 2013 03:15:41 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill __pypy__.get_console_cp, use py3's os.device_encoding instead Message-ID: <20130510011541.646C01C0135@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63955:ed8e8ff8f729 Date: 2013-05-09 18:14 -0700 http://bitbucket.org/pypy/pypy/changeset/ed8e8ff8f729/ Log: kill __pypy__.get_console_cp, use py3's os.device_encoding instead diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -59,8 +59,6 @@ 'newdict' : 'interp_dict.newdict', 'dictstrategy' : 'interp_dict.dictstrategy', } - if sys.platform == 'win32': - interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp' submodules = { "builders": BuildersModule, diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -88,13 +88,6 @@ except OSError, e: raise wrap_oserror(space, e) -def get_console_cp(space): - from rpython.rlib import rwin32 # Windows only - return space.newtuple([ - space.wrap('cp%d' % rwin32.GetConsoleCP()), - space.wrap('cp%d' % rwin32.GetConsoleOutputCP()), - ]) - @unwrap_spec(sizehint=int) def resizelist_hint(space, w_iterable, sizehint): if not isinstance(w_iterable, W_ListObject): From noreply at buildbot.pypy.org Fri May 10 04:16:52 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 10 May 2013 04:16:52 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix the base seek impl to accept args Message-ID: <20130510021652.324BB1C1451@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63956:55096ba173ab Date: 2013-05-09 19:16 -0700 http://bitbucket.org/pypy/pypy/changeset/55096ba173ab/ Log: fix the base seek impl to accept args diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -130,7 +130,7 @@ space.w_ValueError, space.wrap("I/O operation on closed file")) - def seek_w(self, space): + def seek_w(self, space, w_offset, w_whence=None): self._unsupportedoperation(space, "seek") def tell_w(self, space): diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -45,6 +45,13 @@ import _io e = _io.UnsupportedOperation("seek") + def test_default_implementations(self): + import _io + file = _io._IOBase() + raises(_io.UnsupportedOperation, file.seek, 0, 1) + raises(_io.UnsupportedOperation, file.fileno) + raises(_io.UnsupportedOperation, file.truncate) + def test_blockingerror(self): import _io try: From noreply at buildbot.pypy.org Fri May 10 04:37:05 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 10 May 2013 04:37:05 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix --jit help Message-ID: <20130510023705.566E31C1451@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r63957:b97729690802 Date: 2013-05-09 19:36 -0700 http://bitbucket.org/pypy/pypy/changeset/b97729690802/ Log: fix --jit help diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -163,6 +163,7 @@ raise SystemExit def _print_jit_help(): + initstdio() try: import pypyjit except ImportError: From noreply at buildbot.pypy.org Fri May 10 07:57:00 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Fri, 10 May 2013 07:57:00 +0200 (CEST) Subject: [pypy-commit] lang-js default: added requirements.txt. Message-ID: <20130510055700.48EBE1C00F4@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r375:9956fd14134e Date: 2013-05-10 00:06 -0300 http://bitbucket.org/pypy/lang-js/changeset/9956fd14134e/ Log: added requirements.txt. diff --git a/requirements.txt b/requirements.txt new file mode 100644 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,1 @@ +pytest From noreply at buildbot.pypy.org Fri May 10 07:57:01 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Fri, 10 May 2013 07:57:01 +0200 (CEST) Subject: [pypy-commit] lang-js default: added instructions about how to run tests on README.rst. Message-ID: <20130510055701.B24971C00F4@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r376:86f6f9c06efe Date: 2013-05-10 00:21 -0300 http://bitbucket.org/pypy/lang-js/changeset/86f6f9c06efe/ Log: added instructions about how to run tests on README.rst. diff --git a/README.rst b/README.rst new file mode 100644 --- /dev/null +++ b/README.rst @@ -0,0 +1,17 @@ +langjs +====== + +langjs is an implementation of javascript programming language, written in +Python using RPython. + +You will need to install some dependencies. You can do it with:: + + pip install -r requirements.txt + +And make sure you have `PyPy_` on your ``PYTHONPATH``. + +To run tests:: + + $ PYTHONPATH=. py.test + +.. _`PyPy`: https://bitbucket.org/pypy/pypy From noreply at buildbot.pypy.org Fri May 10 08:24:24 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 10 May 2013 08:24:24 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Wrongwrongwrong, our tannit32 chroot is Ubuntu 10.04. Message-ID: <20130510062424.5D67A1C02F7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r420:b1ffdfd4d690 Date: 2013-05-10 08:24 +0200 http://bitbucket.org/pypy/pypy.org/changeset/b1ffdfd4d690/ Log: Wrongwrongwrong, our tannit32 chroot is Ubuntu 10.04. diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -86,7 +86,7 @@ in production due to potential future security issues), you can find 32bit Linux and 64bit Linux.

    2.0

    -

    Note that linux binaries are dynamically linked and might not be usable due -to a sad story of linux binary compatibility. We recommend either building from +

    Note that Linux binaries are dynamically linked, as is usual, and thus might +not be usable due to the sad story of linux binary compatibility. This means +that Linux binaries are only usable on the distributions written next to +them unless you're ready to hack your system by adding symlinks to the +libraries it tries to open. In general, we recommend either building from source or downloading your PyPy from your release vendor. Ubuntu (PPA), Debian, Homebrew, Fedora, Gentoo and Arch are known to package PyPy, with various degrees of being up-to-date. If you feel -like trying a statically linked binary (which we do not recommend using +like trying a more statically linked binary (which we do not recommend using in production due to potential future security issues), you can find 32bit Linux and 64bit Linux.

    2.0 for ARM alpha

    diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -71,8 +71,8 @@ .. _`32bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux.tar.bz2 .. _`64bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux64.tar.bz2 -* `Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS)`__ -* `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ +* `Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS)`__ (see ``[1]`` below) +* `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ (see ``[1]`` below * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) @@ -90,6 +90,13 @@ If your CPU is really old, it may not have SSE2. In this case, you need to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. +``[1]:`` stating it again: the Linux binaries are provided for the +distributions listed here. **If your distribution is not exactly this +one, it won't work,** likely, or you need to hack a lot --- or you need +to translate_ your own version from source --- or you need to wait until +your distribution adds a package, see above --- or you can try the +statically linked versions listed above. + 2.0 for ARM alpha ----------------- From noreply at buildbot.pypy.org Sat May 11 07:59:49 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 07:59:49 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Include the error message Message-ID: <20130511055949.42B451C13BF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r424:8f6bc76bb578 Date: 2013-05-11 07:59 +0200 http://bitbucket.org/pypy/pypy.org/changeset/8f6bc76bb578/ Log: Include the error message diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -101,10 +101,11 @@ to translate yourself with the option --jit-backend=x86-without-sse2.

    [1]: stating it again: the Linux binaries are provided for the distributions listed here. If your distribution is not exactly this -one, it won't work, likely, or you need to hack a lot – or you need -to translate your own version from source – or you need to wait until -your distribution adds a package, see above – or you can try the -statically linked versions listed above.

    +one, it won't work, likely: pypy: error while loading shared +libraries: …. You need to hack a lot – or you need to translate +your own version from source – or you need to wait until your +distribution adds a package, see above – or you can try the statically +linked versions listed above.

    2.0 for ARM alpha

    diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -92,10 +92,11 @@ ``[1]:`` stating it again: the Linux binaries are provided for the distributions listed here. **If your distribution is not exactly this -one, it won't work,** likely, or you need to hack a lot --- or you need -to translate_ your own version from source --- or you need to wait until -your distribution adds a package, see above --- or you can try the -statically linked versions listed above. +one, it won't work,** likely: ``pypy: error while loading shared +libraries: ...``. You need to hack a lot --- or you need to translate_ +your own version from source --- or you need to wait until your +distribution adds a package, see above --- or you can try the statically +linked versions listed above. 2.0 for ARM alpha ----------------- From noreply at buildbot.pypy.org Sat May 11 10:40:43 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 10:40:43 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: typo Message-ID: <20130511084043.84D751C029E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r425:6884f0fee3d1 Date: 2013-05-11 10:40 +0200 http://bitbucket.org/pypy/pypy.org/changeset/6884f0fee3d1/ Log: typo diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -90,7 +90,7 @@ 32bit Linux and 64bit Linux.

    • Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS) (see [1] below)
    • -
    • Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS) (see [1] below
    • +
    • Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS) (see [1] below)
    • Mac OS/X binary (64bit)
    • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
    • diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -72,7 +72,7 @@ .. _`64bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux64.tar.bz2 * `Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS)`__ (see ``[1]`` below) -* `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ (see ``[1]`` below +* `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ (see ``[1]`` below) * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) From noreply at buildbot.pypy.org Sat May 11 13:44:31 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 13:44:31 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix: don't use setslice here, because _digits might occasionally be longer Message-ID: <20130511114431.0BCB11C029E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63974:c40de2de60b7 Date: 2013-05-11 12:34 +0200 http://bitbucket.org/pypy/pypy/changeset/c40de2de60b7/ Log: Fix: don't use setslice here, because _digits might occasionally be longer than numdigits() says. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -1314,7 +1314,8 @@ assert t1.sign >= 0 assert 2*shift + t1.numdigits() <= ret.numdigits() - ret._digits[2*shift : 2*shift + t1.numdigits()] = t1._digits + for i in range(t1.numdigits()): + ret._digits[2*shift + i] = t1._digits[i] # Zero-out the digits higher than the ah*bh copy. */ ## ignored, assuming that we initialize to zero @@ -1327,7 +1328,8 @@ t2 = al.mul(bl) assert t2.sign >= 0 assert t2.numdigits() <= 2*shift # no overlap with high digits - ret._digits[:t2.numdigits()] = t2._digits + for i in range(t2.numdigits()): + ret._digits[i] = t2._digits[i] # Zero out remaining digits. ## ignored, assuming that we initialize to zero From noreply at buildbot.pypy.org Sat May 11 13:44:32 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 13:44:32 +0200 (CEST) Subject: [pypy-commit] pypy default: Arrays of struct need a getlength() too. Message-ID: <20130511114432.3E2C81C029E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63975:5c4cc250d96c Date: 2013-05-11 12:36 +0200 http://bitbucket.org/pypy/pypy/changeset/5c4cc250d96c/ Log: Arrays of struct need a getlength() too. diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1005,6 +1005,19 @@ """ self.optimize_loop(ops, expected) + def test_virtual_array_of_struct_len(self): + ops = """ + [] + p0 = new_array(2, descr=complexarraydescr) + i0 = arraylen_gc(p0) + finish(i0) + """ + expected = """ + [] + finish(2) + """ + self.optimize_loop(ops, expected) + def test_nonvirtual_1(self): ops = """ [i] diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -332,6 +332,9 @@ self.arraydescr = arraydescr self._items = [{} for _ in xrange(size)] + def getlength(self): + return len(self._items) + def getinteriorfield(self, index, ofs, default): return self._items[index].get(ofs, default) From noreply at buildbot.pypy.org Sat May 11 13:44:34 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 13:44:34 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130511114434.B7B9C1C029E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63976:1b2ce85a6d2a Date: 2013-05-11 13:47 +0200 http://bitbucket.org/pypy/pypy/changeset/1b2ce85a6d2a/ Log: merge heads 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 @@ -122,10 +122,10 @@ compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: - cflags = os.environ["CFLAGS"] - compiler.compiler.append(cflags) - compiler.compiler_so.append(cflags) - compiler.linker_so.append(cflags) + cflags = os.environ["CFLAGS"].split() + compiler.compiler.extend(cflags) + compiler.compiler_so.extend(cflags) + compiler.linker_so.extend(cflags) from sysconfig_cpython import ( diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0-beta1' +release = '2.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -105,7 +105,7 @@ $ ./pypy-c Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``RPython magically makes you rich and famous (says so on the tin)'' @@ -235,7 +235,7 @@ the ``bin/pypy`` executable. To install PyPy system wide on unix-like systems, it is recommended to put the -whole hierarchy alone (e.g. in ``/opt/pypy2.0-beta1``) and put a symlink to the +whole hierarchy alone (e.g. in ``/opt/pypy2.0``) and put a symlink to the ``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -53,10 +53,10 @@ PyPy is ready to be executed as soon as you unpack the tarball or the zip file, with no need to install it in any specific location:: - $ tar xf pypy-2.0-beta1-linux.tar.bz2 - $ ./pypy-2.0-beta1/bin/pypy + $ tar xf pypy-2.0.tar.bz2 + $ ./pypy-2.0/bin/pypy Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``PyPy is an exciting technology that lets you to write fast, portable, multi-platform interpreters with less @@ -75,14 +75,14 @@ $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.0-beta1/bin/pypy distribute_setup.py + $ ./pypy-2.0/bin/pypy distribute_setup.py - $ ./pypy-2.0-beta1/bin/pypy get-pip.py + $ ./pypy-2.0/bin/pypy get-pip.py - $ ./pypy-2.0-beta1/bin/pip install pygments # for example + $ ./pypy-2.0/bin/pip install pygments # for example -3rd party libraries will be installed in ``pypy-2.0-beta1/site-packages``, and -the scripts in ``pypy-2.0-beta1/bin``. +3rd party libraries will be installed in ``pypy-2.0/site-packages``, and +the scripts in ``pypy-2.0/bin``. Installing using virtualenv --------------------------- diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0 beta 2`_: the latest official release +* `Release 2.0`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0 beta 2`: http://pypy.org/download.html +.. _`Release 2.0`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -4,6 +4,8 @@ We're pleased to announce PyPy 2.0. This is a stable release that brings a swath of bugfixes, small performance improvements and compatibility fixes. +PyPy 2.0 is a big step for us and we hope in the future we'll be able to +provide stable releases more often. You can download the PyPy 2.0 release here: @@ -19,6 +21,10 @@ .. _`cffi`: http://cffi.readthedocs.org +If you're using PyPy for anything, it would help us immensely if you fill out +the following survey: http://bit.ly/pypysurvey This is for the developers +eyes and we will not make any information public without your agreement. + What is PyPy? ============= @@ -28,8 +34,8 @@ This release supports x86 machines running Linux 32/64, Mac OS X 64 or Windows 32. Windows 64 work is still stalling, we would welcome a volunteer -to handle that. ARM support is on the way and we're expecting to release -an alpha ARM version shortly. +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. .. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org @@ -54,6 +60,10 @@ * A lot of stability issues fixed. +* Refactoring much of the numpypy array classes, which resulted in removal of + lazy expression evaluation. On the other hand, we now have more complete + dtype support and support more array attributes. + .. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ .. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks 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 @@ -5,3 +5,5 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 +.. branch: numpy-pickle +Pickling of numpy arrays and dtypes (including record dtypes) diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -13,6 +13,7 @@ # imported yet, and when it has been, it is mod.__dict__.items() just # after startup(). w_initialdict = None + lazy = False def __init__(self, space, w_name): """ NOT_RPYTHON """ 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 @@ -461,7 +461,7 @@ p = os.path.abspath(p) monkeypatch.chdir(os.path.dirname(app_main)) child = self.spawn(['-i', - '-m', 'test2.mymodule', + '-m', 'test.mymodule', 'extra']) child.expect('mymodule running') child.expect('Name: __main__') @@ -472,9 +472,9 @@ child.expect(re.escape(repr("foobar"))) child.expect('>>> ') child.sendline('import sys') - child.sendline('"test2" in sys.modules') + child.sendline('"test" in sys.modules') child.expect('True') - child.sendline('"test2.mymodule" in sys.modules') + child.sendline('"test.mymodule" in sys.modules') child.expect('False') child.sendline('sys.path[0]') child.expect("''") @@ -566,7 +566,7 @@ child.expect('hello') monkeypatch.chdir(os.path.dirname(app_main)) - child = self.spawn(['-mtest2.mymodule']) + child = self.spawn(['-mtest.mymodule']) child.expect('mymodule running') def test_ps1_only_if_interactive(self): @@ -671,7 +671,7 @@ p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') p = os.path.abspath(p) monkeypatch.chdir(os.path.dirname(app_main)) - data = self.run('-m test2.mymodule extra') + data = self.run('-m test.mymodule extra') assert 'mymodule running' in data assert 'Name: __main__' in data # ignoring case for windows. abspath behaves different from autopath diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.3" /* PyPy version as a string */ -#define PYPY_VERSION "2.0.0-beta2" +#define PYPY_VERSION "2.1.0-alpha0" /* Subversion Revision number of this file (not of the repository). * Empty since Mercurial migration. */ diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -12,6 +12,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + '_reconstruct' : 'interp_numarray._reconstruct', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -55,6 +55,9 @@ def get_size(self): return self.size // self.dtype.itemtype.get_element_size() + def get_storage_size(self): + return self.size + def reshape(self, space, orig_array, new_shape): # Since we got to here, prod(new_shape) == self.size new_strides = None @@ -328,13 +331,14 @@ class ConcreteArray(ConcreteArrayNotOwning): - def __init__(self, shape, dtype, order, strides, backstrides): - # we allocate the actual storage later because we need to compute - # self.size first + def __init__(self, shape, dtype, order, strides, backstrides, storage=lltype.nullptr(RAW_STORAGE)): null_storage = lltype.nullptr(RAW_STORAGE) ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides, null_storage) - self.storage = dtype.itemtype.malloc(self.size) + if storage == lltype.nullptr(RAW_STORAGE): + self.storage = dtype.itemtype.malloc(self.size) + else: + self.storage = storage def __del__(self): free_raw_storage(self.storage, track_allocation=False) diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -35,12 +35,17 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(shape, storage, dtype, order='C'): + def from_shape_and_storage(shape, storage, dtype, order='C', owning=False): from pypy.module.micronumpy.arrayimpl import concrete assert shape strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, - backstrides, storage) + if owning: + # Will free storage when GCd + impl = concrete.ConcreteArray(shape, dtype, order, strides, + backstrides, storage=storage) + else: + impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, + backstrides, storage) return W_NDimArray(impl) @staticmethod diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -133,11 +133,46 @@ space.wrap(offset)])) return w_d + def set_fields(self, space, w_fields): + if w_fields == space.w_None: + self.fields = None + else: + ofs_and_items = [] + size = 0 + for key in space.listview(w_fields): + value = space.getitem(w_fields, key) + + dtype = space.getitem(value, space.wrap(0)) + assert isinstance(dtype, W_Dtype) + + offset = space.int_w(space.getitem(value, space.wrap(1))) + self.fields[space.str_w(key)] = offset, dtype + + ofs_and_items.append((offset, dtype.itemtype)) + size += dtype.itemtype.get_element_size() + + self.itemtype = types.RecordType(ofs_and_items, size) + self.name = "void" + str(8 * self.itemtype.get_element_size()) + def descr_get_names(self, space): if self.fieldnames is None: return space.w_None return space.newtuple([space.wrap(name) for name in self.fieldnames]) + def set_names(self, space, w_names): + if w_names == space.w_None: + self.fieldnames = None + else: + self.fieldnames = [] + iter = space.iter(w_names) + while True: + try: + self.fieldnames.append(space.str_w(space.next(iter))) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + @unwrap_spec(item=str) def descr_getitem(self, space, item): if self.fields is None: @@ -180,6 +215,51 @@ def get_size(self): return self.itemtype.get_element_size() + def descr_reduce(self, space): + w_class = space.type(self) + + kind = self.kind + elemsize = self.itemtype.get_element_size() + builder_args = space.newtuple([space.wrap("%s%d" % (kind, elemsize)), space.wrap(0), space.wrap(1)]) + + version = space.wrap(3) + order = space.wrap(byteorder_prefix if self.native else nonnative_byteorder_prefix) + names = self.descr_get_names(space) + values = self.descr_get_fields(space) + if self.fields: + #TODO: Implement this when subarrays are implemented + subdescr = space.w_None + #TODO: Change this when alignment is implemented : + size = 0 + for key in self.fields: + dtype = self.fields[key][1] + assert isinstance(dtype, W_Dtype) + size += dtype.get_size() + w_size = space.wrap(size) + alignment = space.wrap(1) + else: + subdescr = space.w_None + w_size = space.wrap(-1) + alignment = space.wrap(-1) + flags = space.wrap(0) + + data = space.newtuple([version, order, subdescr, names, values, w_size, alignment, flags]) + + return space.newtuple([w_class, builder_args, data]) + + def descr_setstate(self, space, w_data): + if space.int_w(space.getitem(w_data, space.wrap(0))) != 3: + raise OperationError(space.w_NotImplementedError, space.wrap("Pickling protocol version not supported")) + + self.native = space.str_w(space.getitem(w_data, space.wrap(1))) == byteorder_prefix + + fieldnames = space.getitem(w_data, space.wrap(3)) + self.set_names(space, fieldnames) + + fields = space.getitem(w_data, space.wrap(4)) + self.set_fields(space, fields) + print self.itemtype + class W_ComplexDtype(W_Dtype): def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], @@ -238,8 +318,7 @@ num = 20 basename = 'void' w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - raise OperationError(space.w_NotImplementedError, space.wrap( - "pure void dtype")) + return dtype_from_list(space, space.newlist([])) else: assert char == 'U' basename = 'unicode' @@ -252,9 +331,10 @@ def dtype_from_spec(space, name): raise OperationError(space.w_NotImplementedError, space.wrap( - "dtype from spec")) + "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): + # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) if space.is_none(w_dtype): @@ -297,6 +377,9 @@ __ne__ = interp2app(W_Dtype.descr_ne), __getitem__ = interp2app(W_Dtype.descr_getitem), + __reduce__ = interp2app(W_Dtype.descr_reduce), + __setstate__ = interp2app(W_Dtype.descr_setstate), + num = interp_attrproperty("num", cls=W_Dtype), kind = interp_attrproperty("kind", cls=W_Dtype), char = interp_attrproperty("char", cls=W_Dtype), diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -781,6 +781,42 @@ return space.float(self.descr_getitem(space, space.wrap(0))) raise OperationError(space.w_TypeError, space.wrap("only length-1 arrays can be converted to Python scalars")) + def descr_reduce(self, space): + from rpython.rtyper.lltypesystem import rffi + from rpython.rlib.rstring import StringBuilder + from pypy.interpreter.mixedmodule import MixedModule + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + reconstruct = multiarray.get("_reconstruct") + + parameters = space.newtuple([space.gettypefor(W_NDimArray), space.newtuple([space.wrap(0)]), space.wrap("b")]) + + builder = StringBuilder() + builder.append_charpsize(self.implementation.get_storage(), self.implementation.get_storage_size()) + + state = space.newtuple([ + space.wrap(1), # version + self.descr_get_shape(space), + self.get_dtype(), + space.wrap(False), # is_fortran + space.wrap(builder.build()), + ]) + + return space.newtuple([reconstruct, parameters, state]) + + def descr_setstate(self, space, w_state): + from rpython.rtyper.lltypesystem import rffi + + shape = space.getitem(w_state, space.wrap(1)) + dtype = space.getitem(w_state, space.wrap(2)) + assert isinstance(dtype, interp_dtype.W_Dtype) + isfortran = space.getitem(w_state, space.wrap(3)) + storage = space.getitem(w_state, space.wrap(4)) + + self.implementation = W_NDimArray.from_shape_and_storage([space.int_w(i) for i in space.listview(shape)], rffi.str2charp(space.str_w(storage), track_allocation=False), dtype, owning=True).implementation @unwrap_spec(offset=int) @@ -814,6 +850,7 @@ W_NDimArray.typedef = TypeDef( "ndarray", + __module__ = "numpypy", __new__ = interp2app(descr_new_array), __len__ = interp2app(W_NDimArray.descr_len), @@ -932,6 +969,8 @@ __pypy_data__ = GetSetProperty(W_NDimArray.fget___pypy_data__, W_NDimArray.fset___pypy_data__, W_NDimArray.fdel___pypy_data__), + __reduce__ = interp2app(W_NDimArray.descr_reduce), + __setstate__ = interp2app(W_NDimArray.descr_setstate), ) @unwrap_spec(ndmin=int, copy=bool, subok=bool) @@ -1008,6 +1047,9 @@ arr.fill(one) return space.wrap(arr) +def _reconstruct(space, w_subtype, w_shape, w_dtype): + return descr_new_array(space, w_subtype, w_shape, w_dtype) + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -73,8 +73,8 @@ # Coerce to floats, some of these will eventually be float16, or # whatever our smallest float type is. - assert find_unaryop_result_dtype(space, bool_dtype, promote_to_float=True) is float16_dtype - assert find_unaryop_result_dtype(space, int8_dtype, promote_to_float=True) is float16_dtype + assert find_unaryop_result_dtype(space, bool_dtype, promote_to_float=True) is float16_dtype + assert find_unaryop_result_dtype(space, int8_dtype, promote_to_float=True) is float16_dtype assert find_unaryop_result_dtype(space, uint8_dtype, promote_to_float=True) is float16_dtype assert find_unaryop_result_dtype(space, int16_dtype, promote_to_float=True) is float32_dtype assert find_unaryop_result_dtype(space, uint16_dtype, promote_to_float=True) is float32_dtype diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -14,8 +14,9 @@ from rpython.rtyper.lltypesystem import rffi ptr_size = rffi.sizeof(rffi.CCHARP) cls.w_ptr_size = cls.space.wrap(ptr_size) - + class AppTestDtypes(BaseAppTestDtypes): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_dtype(self): from numpypy import dtype @@ -149,7 +150,7 @@ def test_bool_binop_types(self): from numpypy import array, dtype types = [ - '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd', + '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd', 'e' ] a = array([True], '?') @@ -270,6 +271,23 @@ ]: assert hash(tp(value)) == hash(value) + def test_pickle(self): + from numpypy import array, dtype + from cPickle import loads, dumps + a = array([1,2,3]) + assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + assert loads(dumps(a.dtype)) == a.dtype + + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): @@ -340,7 +358,7 @@ import numpypy as numpy assert numpy.int8.mro() == [numpy.int8, numpy.signedinteger, - numpy.integer, numpy.number, + numpy.integer, numpy.number, numpy.generic, object] a = numpy.array([1, 2, 3], numpy.int8) @@ -363,8 +381,8 @@ def test_uint8(self): import numpypy as numpy - assert numpy.uint8.mro() == [numpy.uint8, numpy.unsignedinteger, - numpy.integer, numpy.number, + assert numpy.uint8.mro() == [numpy.uint8, numpy.unsignedinteger, + numpy.integer, numpy.number, numpy.generic, object] a = numpy.array([1, 2, 3], numpy.uint8) @@ -435,8 +453,8 @@ import numpypy as numpy assert numpy.int_ is numpy.dtype(int).type - assert numpy.int_.mro() == [numpy.int_, numpy.signedinteger, - numpy.integer, numpy.number, + assert numpy.int_.mro() == [numpy.int_, numpy.signedinteger, + numpy.integer, numpy.number, numpy.generic, int, object] def test_int64(self): @@ -444,12 +462,12 @@ import numpypy as numpy if sys.maxint == 2 ** 63 -1: - assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, - numpy.integer, numpy.number, + assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, + numpy.integer, numpy.number, numpy.generic, int, object] else: - assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, - numpy.integer, numpy.number, + assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, + numpy.integer, numpy.number, numpy.generic, object] assert numpy.dtype(numpy.int64).type is numpy.int64 @@ -465,8 +483,8 @@ import sys import numpypy as numpy - assert numpy.uint64.mro() == [numpy.uint64, numpy.unsignedinteger, - numpy.integer, numpy.number, + assert numpy.uint64.mro() == [numpy.uint64, numpy.unsignedinteger, + numpy.integer, numpy.number, numpy.generic, object] assert numpy.dtype(numpy.uint64).type is numpy.uint64 @@ -481,8 +499,8 @@ def test_float16(self): import numpypy as numpy - assert numpy.float16.mro() == [numpy.float16, numpy.floating, - numpy.inexact, numpy.number, + assert numpy.float16.mro() == [numpy.float16, numpy.floating, + numpy.inexact, numpy.number, numpy.generic, object] assert numpy.float16(12) == numpy.float64(12) @@ -493,8 +511,8 @@ def test_float32(self): import numpypy as numpy - assert numpy.float32.mro() == [numpy.float32, numpy.floating, - numpy.inexact, numpy.number, + assert numpy.float32.mro() == [numpy.float32, numpy.floating, + numpy.inexact, numpy.number, numpy.generic, object] assert numpy.float32(12) == numpy.float64(12) @@ -504,8 +522,8 @@ def test_float64(self): import numpypy as numpy - assert numpy.float64.mro() == [numpy.float64, numpy.floating, - numpy.inexact, numpy.number, + assert numpy.float64.mro() == [numpy.float64, numpy.floating, + numpy.inexact, numpy.number, numpy.generic, float, object] a = numpy.array([1, 2, 3], numpy.float64) @@ -856,7 +874,7 @@ # it can be float96 or float128 if numpy.longfloat != numpy.float64: assert numpy.longfloat.mro()[1:] == [numpy.floating, - numpy.inexact, numpy.number, + numpy.inexact, numpy.number, numpy.generic, object] a = numpy.array([1, 2, 3], numpy.longdouble) assert type(a[1]) is numpy.longdouble @@ -898,3 +916,4 @@ a = array([1, 2, 3], dtype=self.non_native_prefix + 'G') # clongdouble assert a[0] == 1 assert (a + a)[1] == 4 + diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -214,6 +214,7 @@ assert get(1, 1) == 3 class AppTestNumArray(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def w_CustomIndexObject(self, index): class CustomIndexObject(object): def __init__(self, index): @@ -1786,6 +1787,17 @@ assert raises(TypeError, "int(array([1, 2]))") assert int(array([1.5])) == 1 + def test__reduce__(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + a = array([1, 2], dtype="int64") + data = a.__reduce__() + + assert data[2][4] == '\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00' + + pickled_data = dumps(a) + assert (loads(pickled_data) == a).all() class AppTestMultiDim(BaseNumpyAppTest): def test_init(self): @@ -2534,6 +2546,8 @@ class AppTestRecordDtype(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) + def test_zeros(self): from numpypy import zeros, integer a = zeros(2, dtype=[('x', int), ('y', float)]) @@ -2666,6 +2680,25 @@ assert s.replace('\n', '') == \ "array(['abc', 'defg', 'ab'], dtype='|S4')" + def test_pickle(self): + from numpypy import dtype, array + from cPickle import loads, dumps + + d = dtype([('x', str), ('y', 'int32')]) + a = array([('a', 2), ('cde', 1)], dtype=d) + + a = loads(dumps(a)) + d = a.dtype + + assert str(d.fields['x'][0]) == '|S0' + assert d.fields['x'][1] == 0 + assert str(d.fields['y'][0]) == 'int32' + assert d.fields['y'][1] == 0 + assert d.name == 'void32' + + assert a[0]['y'] == 2 + assert a[1]['y'] == 1 + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -11,7 +11,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (2, 0, 0, "beta", 2) #XXX # sync patchlevel.h +PYPY_VERSION = (2, 1, 0, "alpha", 0) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -446,7 +446,7 @@ TYPES += ['__int128_t'] except CompilationError: pass - + _TYPES_ARE_UNSIGNED = set(['size_t', 'uintptr_t']) # plus "unsigned *" if os.name != 'nt': TYPES.append('mode_t') @@ -693,10 +693,13 @@ builder_class = UnicodeBuilder # str -> char* - def str2charp(s): + def str2charp(s, track_allocation=True): """ str -> char* """ - array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw') + if track_allocation: + array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=True) + else: + array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=False) i = len(s) array[i] = lastchar i -= 1 @@ -704,10 +707,13 @@ array[i] = s[i] i -= 1 return array - str2charp._annenforceargs_ = [strtype] + str2charp._annenforceargs_ = [strtype, bool] - def free_charp(cp): - lltype.free(cp, flavor='raw') + def free_charp(cp, track_allocation=True): + if track_allocation: + lltype.free(cp, flavor='raw', track_allocation=True) + else: + lltype.free(cp, flavor='raw', track_allocation=False) # char* -> str # doesn't free char* From noreply at buildbot.pypy.org Sat May 11 13:45:06 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 13:45:06 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Fix: don't use setslice here, because _digits might occasionally be longer Message-ID: <20130511114506.7FFD11C029E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r63977:451209179cef Date: 2013-05-11 12:34 +0200 http://bitbucket.org/pypy/pypy/changeset/451209179cef/ Log: Fix: don't use setslice here, because _digits might occasionally be longer than numdigits() says. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -1314,7 +1314,8 @@ assert t1.sign >= 0 assert 2*shift + t1.numdigits() <= ret.numdigits() - ret._digits[2*shift : 2*shift + t1.numdigits()] = t1._digits + for i in range(t1.numdigits()): + ret._digits[2*shift + i] = t1._digits[i] # Zero-out the digits higher than the ah*bh copy. */ ## ignored, assuming that we initialize to zero @@ -1327,7 +1328,8 @@ t2 = al.mul(bl) assert t2.sign >= 0 assert t2.numdigits() <= 2*shift # no overlap with high digits - ret._digits[:t2.numdigits()] = t2._digits + for i in range(t2.numdigits()): + ret._digits[i] = t2._digits[i] # Zero out remaining digits. ## ignored, assuming that we initialize to zero From noreply at buildbot.pypy.org Sat May 11 13:45:07 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 13:45:07 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Arrays of struct need a getlength() too. Message-ID: <20130511114507.D695F1C029E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r63978:2934efd0c5c8 Date: 2013-05-11 12:36 +0200 http://bitbucket.org/pypy/pypy/changeset/2934efd0c5c8/ Log: Arrays of struct need a getlength() too. diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1005,6 +1005,19 @@ """ self.optimize_loop(ops, expected) + def test_virtual_array_of_struct_len(self): + ops = """ + [] + p0 = new_array(2, descr=complexarraydescr) + i0 = arraylen_gc(p0) + finish(i0) + """ + expected = """ + [] + finish(2) + """ + self.optimize_loop(ops, expected) + def test_nonvirtual_1(self): ops = """ [i] diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -332,6 +332,9 @@ self.arraydescr = arraydescr self._items = [{} for _ in xrange(size)] + def getlength(self): + return len(self._items) + def getinteriorfield(self, index, ofs, default): return self._items[index].get(ofs, default) From noreply at buildbot.pypy.org Sat May 11 14:29:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 11 May 2013 14:29:41 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add information for Ronan. Message-ID: <20130511122941.202E51C1106@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63979:c8a71c794e74 Date: 2013-05-11 14:28 +0200 http://bitbucket.org/pypy/pypy/changeset/c8a71c794e74/ Log: Add information for Ronan. diff --git a/pypy/doc/objspace.rst b/pypy/doc/objspace.rst --- a/pypy/doc/objspace.rst +++ b/pypy/doc/objspace.rst @@ -27,7 +27,7 @@ if-statements (or rather, to be pedantic, to implement the conditional-branching bytecodes into which if-statements get compiled). -We have many working object spaces which can be plugged into +We have some working object spaces which can be plugged into the bytecode interpreter: - The *Standard Object Space* is a complete implementation @@ -44,11 +44,6 @@ when an operation is performed on them), security-checking objects, distributed objects living on several machines, etc. -- the *Flow Object Space* transforms a Python program into a - flow-graph representation, by recording all operations that the bytecode - interpreter would like to perform when it is shown the given Python - program. This technique is explained :doc:`in another document `. - The present document gives a description of the above object spaces. The sources of PyPy contain the various object spaces in the directory :source:`pypy/objspace/`. @@ -481,81 +476,6 @@ ``6L.__radd__(5)`` being called, as in CPython. -.. _flow-object-space: - -The Flow Object Space ---------------------- - -Introduction -~~~~~~~~~~~~ - -The task of the FlowObjSpace (the source is at :source:`pypy/objspace/flow/`) is to generate a control-flow graph from a -function. This graph will also contain a trace of the individual operations, so -that it is actually just an alternate representation for the function. - -The FlowObjSpace is an object space, which means that it exports the standard -object space interface and it is driven by the bytecode interpreter. - -The basic idea is that if the bytecode interpreter is given a function, e.g.:: - - def f(n): - return 3*n+2 - -it will do whatever bytecode dispatching and stack-shuffling needed, during -which it issues a sequence of calls to the object space. The FlowObjSpace -merely records these calls (corresponding to "operations") in a structure called -a basic block. To track which value goes where, the FlowObjSpace invents -placeholder "wrapped objects" and give them to the interpreter, so that they -appear in some next operation. This technique is an example of `Abstract -Interpretation`_. - -.. _Abstract Interpretation: http://en.wikipedia.org/wiki/Abstract_interpretation - -For example, if the placeholder ``v1`` is given as the argument to the above -function, the bytecode interpreter will call ``v2 = space.mul(space.wrap(3), -v1)`` and then ``v3 = space.add(v2, space.wrap(2))`` and return ``v3`` as the -result. During these calls the FlowObjSpace will record a basic block:: - - Block(v1): # input argument - v2 = mul(Constant(3), v1) - v3 = add(v2, Constant(2)) - - -The Flow model -~~~~~~~~~~~~~~ - -The data structures built up by the flow object space are described in the -:ref:`translation document `. - - -How the FlowObjSpace works -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The FlowObjSpace works by recording all operations issued by the bytecode -interpreter into basic blocks. A basic block ends in one of two cases: when -the bytecode interpreters calls ``is_true()``, or when a joinpoint is reached. - -* A joinpoint occurs when the next operation is about to be recorded into the - current block, but there is already another block that records an operation - for the same bytecode position. This means that the bytecode interpreter - has closed a loop and is interpreting already-seen code again. In this - situation, we interrupt the bytecode interpreter and we make a link from the - end of the current block back to the previous block, thus closing the loop - in the flow graph as well. (Note that this occurs only when an operation is - about to be recorded, which allows some amount of constant-folding.) - -* If the bytecode interpreter calls ``is_true()``, the FlowObjSpace doesn't - generally know if the answer should be True or False, so it puts a - conditional jump and generates two successor blocks for the current basic - block. There is some trickery involved so that the bytecode interpreter is - fooled into thinking that ``is_true()`` first returns False (and the - subsequent operations are recorded in the first successor block), and later - the *same* call to ``is_true()`` also returns True (and the subsequent - operations go this time to the other successor block). - -(This section to be extended...) - - Object Space proxies -------------------- diff --git a/rpython/doc/ronan.rst b/rpython/doc/ronan.rst new file mode 100644 --- /dev/null +++ b/rpython/doc/ronan.rst @@ -0,0 +1,245 @@ +.. + @Ronan: This is the old documentation for the flow object space and flow model. + Please integrate (and edit when needed) this into the new section in the document rpython/doc/translation.rst (section "Building Flow Graphs"). + + +.. _flow-object-space: + +The Flow Object Space +--------------------- + +Introduction +~~~~~~~~~~~~ + +The task of the FlowObjSpace (the source is at :source:`pypy/objspace/flow/`) is to generate a control-flow graph from a +function. This graph will also contain a trace of the individual operations, so +that it is actually just an alternate representation for the function. + +The FlowObjSpace is an object space, which means that it exports the standard +object space interface and it is driven by the bytecode interpreter. + +The basic idea is that if the bytecode interpreter is given a function, e.g.:: + + def f(n): + return 3*n+2 + +it will do whatever bytecode dispatching and stack-shuffling needed, during +which it issues a sequence of calls to the object space. The FlowObjSpace +merely records these calls (corresponding to "operations") in a structure called +a basic block. To track which value goes where, the FlowObjSpace invents +placeholder "wrapped objects" and give them to the interpreter, so that they +appear in some next operation. This technique is an example of `Abstract +Interpretation`_. + +.. _Abstract Interpretation: http://en.wikipedia.org/wiki/Abstract_interpretation + +For example, if the placeholder ``v1`` is given as the argument to the above +function, the bytecode interpreter will call ``v2 = space.mul(space.wrap(3), +v1)`` and then ``v3 = space.add(v2, space.wrap(2))`` and return ``v3`` as the +result. During these calls the FlowObjSpace will record a basic block:: + + Block(v1): # input argument + v2 = mul(Constant(3), v1) + v3 = add(v2, Constant(2)) + + +The Flow model +~~~~~~~~~~~~~~ + +The data structures built up by the flow object space are described in the +:ref:`translation document `. + + +How the FlowObjSpace works +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The FlowObjSpace works by recording all operations issued by the bytecode +interpreter into basic blocks. A basic block ends in one of two cases: when +the bytecode interpreters calls ``is_true()``, or when a joinpoint is reached. + +* A joinpoint occurs when the next operation is about to be recorded into the + current block, but there is already another block that records an operation + for the same bytecode position. This means that the bytecode interpreter + has closed a loop and is interpreting already-seen code again. In this + situation, we interrupt the bytecode interpreter and we make a link from the + end of the current block back to the previous block, thus closing the loop + in the flow graph as well. (Note that this occurs only when an operation is + about to be recorded, which allows some amount of constant-folding.) + +* If the bytecode interpreter calls ``is_true()``, the FlowObjSpace doesn't + generally know if the answer should be True or False, so it puts a + conditional jump and generates two successor blocks for the current basic + block. There is some trickery involved so that the bytecode interpreter is + fooled into thinking that ``is_true()`` first returns False (and the + subsequent operations are recorded in the first successor block), and later + the *same* call to ``is_true()`` also returns True (and the subsequent + operations go this time to the other successor block). + +(This section to be extended...) + + + +.. _flow-model: + +The Flow Model +-------------- + +The :ref:`Flow Object Space ` is described in the `document +describing object spaces`_. Here we describe the data structures produced by it, +which are the basic data structures of the translation +process. + +All these types are defined in :source:`rpython/flowspace/model.py` (which is a rather +important module in the PyPy source base, to reinforce the point). + +The flow graph of a function is represented by the class ``FunctionGraph``. +It contains a reference to a collection of ``Block``\ s connected by ``Link``\ s. + +A ``Block`` contains a list of ``SpaceOperation``\ s. Each ``SpaceOperation`` +has an ``opname`` and a list of ``args`` and ``result``, which are either +``Variable``\ s or ``Constant``\ s. + +We have an extremely useful PyGame viewer, which allows you to visually +inspect the graphs at various stages of the translation process (very +useful to try to work out why things are breaking). It looks like this: + + .. image:: _static/bpnn_update.png + +It is recommended to play with ``python bin/translatorshell.py`` on a few +examples to get an idea of the structure of flow graphs. The following describes +the types and their attributes in some detail: + + +``FunctionGraph`` + A container for one graph (corresponding to one function). + + :startblock: the first block. It is where the control goes when the + function is called. The input arguments of the startblock + are the function's arguments. If the function takes a + ``*args`` argument, the ``args`` tuple is given as the last + input argument of the startblock. + + :returnblock: the (unique) block that performs a function return. It is + empty, not actually containing any ``return`` operation; the + return is implicit. The returned value is the unique input + variable of the returnblock. + + :exceptblock: the (unique) block that raises an exception out of the + function. The two input variables are the exception class + and the exception value, respectively. (No other block will + actually link to the exceptblock if the function does not + explicitly raise exceptions.) + + +``Block`` + A basic block, containing a list of operations and ending in jumps to other + basic blocks. All the values that are "live" during the execution of the + block are stored in Variables. Each basic block uses its own distinct + Variables. + + :inputargs: list of fresh, distinct Variables that represent all the + values that can enter this block from any of the previous + blocks. + + :operations: list of SpaceOperations. + :exitswitch: see below + + :exits: list of Links representing possible jumps from the end of this + basic block to the beginning of other basic blocks. + + Each Block ends in one of the following ways: + + * unconditional jump: exitswitch is None, exits contains a single Link. + + * conditional jump: exitswitch is one of the Variables that appear in the + Block, and exits contains one or more Links (usually 2). Each Link's + exitcase gives a concrete value. This is the equivalent of a "switch": + the control follows the Link whose exitcase matches the run-time value of + the exitswitch Variable. It is a run-time error if the Variable doesn't + match any exitcase. + + * exception catching: exitswitch is ``Constant(last_exception)``. The first + Link has exitcase set to None and represents the non-exceptional path. + The next Links have exitcase set to a subclass of Exception, and are taken + when the *last* operation of the basic block raises a matching exception. + (Thus the basic block must not be empty, and only the last operation is + protected by the handler.) + + * return or except: the returnblock and the exceptblock have operations set + to an empty tuple, exitswitch to None, and exits empty. + + +``Link`` + A link from one basic block to another. + + :prevblock: the Block that this Link is an exit of. + + :target: the target Block to which this Link points to. + + :args: a list of Variables and Constants, of the same size as the + target Block's inputargs, which gives all the values passed + into the next block. (Note that each Variable used in the + prevblock may appear zero, one or more times in the ``args`` + list.) + + :exitcase: see above. + + :last_exception: None or a Variable; see below. + + :last_exc_value: None or a Variable; see below. + + Note that ``args`` uses Variables from the prevblock, which are matched to + the target block's ``inputargs`` by position, as in a tuple assignment or + function call would do. + + If the link is an exception-catching one, the ``last_exception`` and + ``last_exc_value`` are set to two fresh Variables that are considered to be + created when the link is entered; at run-time, they will hold the exception + class and value, respectively. These two new variables can only be used in + the same link's ``args`` list, to be passed to the next block (as usual, + they may actually not appear at all, or appear several times in ``args``). + + +``SpaceOperation`` + A recorded (or otherwise generated) basic operation. + + :opname: the name of the operation. The Flow Space produces only operations + from the list in ``pypy.interpreter.baseobjspace``, but later the + names can be changed arbitrarily. + + :args: list of arguments. Each one is a Constant or a Variable seen + previously in the basic block. + + :result: a *new* Variable into which the result is to be stored. + + Note that operations usually cannot implicitly raise exceptions at run-time; + so for example, code generators can assume that a ``getitem`` operation on a + list is safe and can be performed without bound checking. The exceptions to + this rule are: (1) if the operation is the last in the block, which ends + with ``exitswitch == Constant(last_exception)``, then the implicit + exceptions must be checked for, generated, and caught appropriately; (2) + calls to other functions, as per ``simple_call`` or ``call_args``, can + always raise whatever the called function can raise --- and such exceptions + must be passed through to the parent unless they are caught as above. + + +``Variable`` + A placeholder for a run-time value. There is mostly debugging stuff here. + + :name: it is good style to use the Variable object itself instead of its + ``name`` attribute to reference a value, although the ``name`` is + guaranteed unique. + + +``Constant`` + A constant value used as argument to a SpaceOperation, or as value to pass + across a Link to initialize an input Variable in the target Block. + + :value: the concrete value represented by this Constant. + :key: a hashable object representing the value. + + A Constant can occasionally store a mutable Python object. It represents a + static, pre-initialized, read-only version of that object. The flow graph + should not attempt to actually mutate such Constants. + +.. _document describing object spaces: objspace.html diff --git a/rpython/doc/translation.rst b/rpython/doc/translation.rst --- a/rpython/doc/translation.rst +++ b/rpython/doc/translation.rst @@ -101,170 +101,12 @@ .. _abstract interpretation: http://en.wikipedia.org/wiki/Abstract_interpretation -.. _flow-model: +.. _flow-graphs: -The Flow Model --------------- +Building Flow Graphs +-------------------- -The :ref:`Flow Object Space ` is described in the `document -describing object spaces`_. Here we describe the data structures produced by it, -which are the basic data structures of the translation -process. - -All these types are defined in :source:`rpython/flowspace/model.py` (which is a rather -important module in the PyPy source base, to reinforce the point). - -The flow graph of a function is represented by the class ``FunctionGraph``. -It contains a reference to a collection of ``Block``\ s connected by ``Link``\ s. - -A ``Block`` contains a list of ``SpaceOperation``\ s. Each ``SpaceOperation`` -has an ``opname`` and a list of ``args`` and ``result``, which are either -``Variable``\ s or ``Constant``\ s. - -We have an extremely useful PyGame viewer, which allows you to visually -inspect the graphs at various stages of the translation process (very -useful to try to work out why things are breaking). It looks like this: - - .. image:: _static/bpnn_update.png - -It is recommended to play with ``python bin/translatorshell.py`` on a few -examples to get an idea of the structure of flow graphs. The following describes -the types and their attributes in some detail: - - -``FunctionGraph`` - A container for one graph (corresponding to one function). - - :startblock: the first block. It is where the control goes when the - function is called. The input arguments of the startblock - are the function's arguments. If the function takes a - ``*args`` argument, the ``args`` tuple is given as the last - input argument of the startblock. - - :returnblock: the (unique) block that performs a function return. It is - empty, not actually containing any ``return`` operation; the - return is implicit. The returned value is the unique input - variable of the returnblock. - - :exceptblock: the (unique) block that raises an exception out of the - function. The two input variables are the exception class - and the exception value, respectively. (No other block will - actually link to the exceptblock if the function does not - explicitly raise exceptions.) - - -``Block`` - A basic block, containing a list of operations and ending in jumps to other - basic blocks. All the values that are "live" during the execution of the - block are stored in Variables. Each basic block uses its own distinct - Variables. - - :inputargs: list of fresh, distinct Variables that represent all the - values that can enter this block from any of the previous - blocks. - - :operations: list of SpaceOperations. - :exitswitch: see below - - :exits: list of Links representing possible jumps from the end of this - basic block to the beginning of other basic blocks. - - Each Block ends in one of the following ways: - - * unconditional jump: exitswitch is None, exits contains a single Link. - - * conditional jump: exitswitch is one of the Variables that appear in the - Block, and exits contains one or more Links (usually 2). Each Link's - exitcase gives a concrete value. This is the equivalent of a "switch": - the control follows the Link whose exitcase matches the run-time value of - the exitswitch Variable. It is a run-time error if the Variable doesn't - match any exitcase. - - * exception catching: exitswitch is ``Constant(last_exception)``. The first - Link has exitcase set to None and represents the non-exceptional path. - The next Links have exitcase set to a subclass of Exception, and are taken - when the *last* operation of the basic block raises a matching exception. - (Thus the basic block must not be empty, and only the last operation is - protected by the handler.) - - * return or except: the returnblock and the exceptblock have operations set - to an empty tuple, exitswitch to None, and exits empty. - - -``Link`` - A link from one basic block to another. - - :prevblock: the Block that this Link is an exit of. - - :target: the target Block to which this Link points to. - - :args: a list of Variables and Constants, of the same size as the - target Block's inputargs, which gives all the values passed - into the next block. (Note that each Variable used in the - prevblock may appear zero, one or more times in the ``args`` - list.) - - :exitcase: see above. - - :last_exception: None or a Variable; see below. - - :last_exc_value: None or a Variable; see below. - - Note that ``args`` uses Variables from the prevblock, which are matched to - the target block's ``inputargs`` by position, as in a tuple assignment or - function call would do. - - If the link is an exception-catching one, the ``last_exception`` and - ``last_exc_value`` are set to two fresh Variables that are considered to be - created when the link is entered; at run-time, they will hold the exception - class and value, respectively. These two new variables can only be used in - the same link's ``args`` list, to be passed to the next block (as usual, - they may actually not appear at all, or appear several times in ``args``). - - -``SpaceOperation`` - A recorded (or otherwise generated) basic operation. - - :opname: the name of the operation. The Flow Space produces only operations - from the list in ``pypy.interpreter.baseobjspace``, but later the - names can be changed arbitrarily. - - :args: list of arguments. Each one is a Constant or a Variable seen - previously in the basic block. - - :result: a *new* Variable into which the result is to be stored. - - Note that operations usually cannot implicitly raise exceptions at run-time; - so for example, code generators can assume that a ``getitem`` operation on a - list is safe and can be performed without bound checking. The exceptions to - this rule are: (1) if the operation is the last in the block, which ends - with ``exitswitch == Constant(last_exception)``, then the implicit - exceptions must be checked for, generated, and caught appropriately; (2) - calls to other functions, as per ``simple_call`` or ``call_args``, can - always raise whatever the called function can raise --- and such exceptions - must be passed through to the parent unless they are caught as above. - - -``Variable`` - A placeholder for a run-time value. There is mostly debugging stuff here. - - :name: it is good style to use the Variable object itself instead of its - ``name`` attribute to reference a value, although the ``name`` is - guaranteed unique. - - -``Constant`` - A constant value used as argument to a SpaceOperation, or as value to pass - across a Link to initialize an input Variable in the target Block. - - :value: the concrete value represented by this Constant. - :key: a hashable object representing the value. - - A Constant can occasionally store a mutable Python object. It represents a - static, pre-initialized, read-only version of that object. The flow graph - should not attempt to actually mutate such Constants. - -.. _document describing object spaces: objspace.html +.. @Ronan: here .. _annotator: From noreply at buildbot.pypy.org Sat May 11 14:59:55 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 11 May 2013 14:59:55 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Forgot to add rpython/doc/dir-reference.rst. Message-ID: <20130511125955.5A6EE1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63980:7734b9319c5a Date: 2013-05-11 14:30 +0200 http://bitbucket.org/pypy/pypy/changeset/7734b9319c5a/ Log: Forgot to add rpython/doc/dir-reference.rst. diff --git a/rpython/doc/dir-reference.rst b/rpython/doc/dir-reference.rst new file mode 100644 --- /dev/null +++ b/rpython/doc/dir-reference.rst @@ -0,0 +1,52 @@ +RPython directory cross-reference +================================= + +Here is a fully referenced alphabetical two-level deep +directory overview of RPython: + +======================================== ============================================ +Directory explanation/links +======================================== ============================================ +:source:`rpython/annotator/` :ref:`type inferencing code ` for + :doc:`RPython ` programs + +:source:`rpython/config/` handles the numerous options for RPython + +:source:`rpython/flowspace/` the :ref:`FlowObjSpace_ ` implementing + `abstract interpretation`_ + +:source:`rpython/rlib/` a :doc:`"standard library" ` for :doc:`RPython ` + programs + +:source:`rpython/rtyper/` the :ref:`RPython Typer ` + +:source:`rpython/rtyper/lltypesystem/` the :ref:`low-level type system ` for + C-like backends + +:source:`rpython/rtyper/ootypesystem/` the :ref:`object-oriented type system ` + for OO backends + +:source:`rpython/memory/` the :doc:`garbage collector ` construction + framework + +:source:`rpython/translator/` :doc:`translation ` backends and support code + +:source:`rpython/translator/backendopt/` general optimizations that run before a + backend generates code + +:source:`rpython/translator/c/` the :ref:`GenC backend `, producing C code + from an RPython program (generally via the :doc:`rtyper `) + +:source:`rpython/translator/cli/` the :doc:`CLI backend ` for `.NET`_ + (Microsoft CLR or Mono_) + +:source:`rpython/translator/jvm/` the Java backend + +:source:`rpython/translator/tool/` helper tools for translation + +:source:`dotviewer/` :ref:`graph viewer ` +======================================== ============================================ + +.. _abstract interpretation: http://en.wikipedia.org/wiki/Abstract_interpretation +.. _.NET: http://www.microsoft.com/net/ +.. _Mono: http://www.mono-project.com/ From noreply at buildbot.pypy.org Sat May 11 14:59:56 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 11 May 2013 14:59:56 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add TODO. Message-ID: <20130511125956.A6A281C11B7@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r63981:d09af1ce5877 Date: 2013-05-11 14:58 +0200 http://bitbucket.org/pypy/pypy/changeset/d09af1ce5877/ Log: Add TODO. diff --git a/TODO-docs b/TODO-docs new file mode 100644 --- /dev/null +++ b/TODO-docs @@ -0,0 +1,29 @@ +Documentation TODO +================== + +General +------- + +* make inter-documentation links work +* work on configuration/options documentation +* structure documentation and add appropriate toctrees +* integrate numerous getting started documents into something more useful + (eg. "Installing PyPy", "Building PyPy from source", "Playing with the + RPython Toolchain", "Write your own interpreter in RPython") +* remove documentation for removed features +* architecture documents don't really show the separation between PyPy and RPython +* where should the documentation about coding style etc. be put? +* update / remove dead links + + +RPython +------- + +* remove duplication between translation.rst and rtyper.rst. +* rename / move rpython.rst? + + +PyPy +---- + +* divide user documentation, developer documentation, and academical stuff From noreply at buildbot.pypy.org Sat May 11 15:34:57 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 11 May 2013 15:34:57 +0200 (CEST) Subject: [pypy-commit] pypy default: shuffle stuff around a lot. also a test and a fix for exported symbols Message-ID: <20130511133457.997DD1C11B7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63982:83621509a0d4 Date: 2013-05-11 15:33 +0200 http://bitbucket.org/pypy/pypy/changeset/83621509a0d4/ Log: shuffle stuff around a lot. also a test and a fix for exported symbols diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -554,8 +554,6 @@ from pypy.module.cpyext.pyobject import Reference # we hope that malloc removal removes the newtuple() that is # inserted exactly here by the varargs specializer - rffi.stackcounter.stacks_counter += 1 - llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py retval = fatal_value boxed_args = () try: @@ -624,7 +622,6 @@ else: print str(e) pypy_debug_catch_fatal_exception() - rffi.stackcounter.stacks_counter -= 1 return retval callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -1,5 +1,10 @@ secondary_entrypoints = {} +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.lltypesystem.lloperation import llop +from rpython.rlib.objectmodel import we_are_translated + +pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) def entrypoint(key, argtypes, c_name=None, relax=False): """ Note: entrypoint should call llop.gc_stack_bottom on it's own. @@ -10,14 +15,35 @@ from rpython.translator.tool.cbuild import ExternalCompilationInfo def deco(func): - secondary_entrypoints.setdefault(key, []).append((func, argtypes)) + def wrapper(*args): + # the tuple has to be killed, but it's fine because this is + # called from C + rffi.stackcounter.stacks_counter += 1 + llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py + # this should not raise + try: + res = func(*args) + except Exception, e: + if not we_are_translated(): + import traceback + traceback.print_exc() + else: + print str(e) + pypy_debug_catch_fatal_exception() + llop.debug_fatalerror(lltype.Void) + assert 0 # dead code + rffi.stackcounter.stacks_counter -= 1 + return res + + secondary_entrypoints.setdefault(key, []).append((wrapper, argtypes)) + wrapper.func_name = func.func_name if c_name is not None: - func.c_name = c_name + wrapper.c_name = c_name if relax: - func.relax_sig_check = True - func._compilation_info = ExternalCompilationInfo( + wrapper.relax_sig_check = True + wrapper._compilation_info = ExternalCompilationInfo( export_symbols=[c_name or func.func_name]) - return func + return wrapper return deco # the point of dance below is so the call to rpython_startup_code actually @@ -25,8 +51,6 @@ # This thing is imported by any target which has any API, so it'll get # registered -from rpython.rtyper.lltypesystem import lltype, rffi - RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void) @entrypoint('main', [], c_name='rpython_startup_code') diff --git a/rpython/rtyper/lltypesystem/lltype.py b/rpython/rtyper/lltypesystem/lltype.py --- a/rpython/rtyper/lltypesystem/lltype.py +++ b/rpython/rtyper/lltypesystem/lltype.py @@ -317,7 +317,7 @@ def _names_without_voids(self): names_without_voids = [name for name in self._names if self._flds[name] is not Void] return names_without_voids - + def _str_fields_without_voids(self): return ', '.join(['%s: %s' % (name, self._flds[name]) for name in self._names_without_voids(False)]) @@ -425,7 +425,7 @@ _gckind = 'raw' __name__ = 'array' _anonym_struct = False - + def __init__(self, *fields, **kwds): if len(fields) == 1 and isinstance(fields[0], LowLevelType): self.OF = fields[0] @@ -669,7 +669,7 @@ def normalized(self): return build_number(None, normalizedinttype(self._type)) - + _numbertypes = {int: Number("Signed", int, intmask)} _numbertypes[r_int] = _numbertypes[int] @@ -766,7 +766,7 @@ adtmeths=TO._adtmeths) else: R = GcStruct("Interior", ('ptr', self), ('index', Signed), - hints={'interior_ptr_type':True}) + hints={'interior_ptr_type':True}) return R class InteriorPtr(LowLevelType): @@ -911,7 +911,7 @@ return dwn OUTSIDE = getattr(OUTSIDE, first) return -1 - + def castable(PTRTYPE, CURTYPE): if CURTYPE.TO._gckind != PTRTYPE.TO._gckind: raise TypeError("cast_pointer() cannot change the gc status: %s to %s" @@ -1120,7 +1120,7 @@ # _setobj, _getobj and _obj0 are really _internal_ implementations details of _ptr, # use _obj if necessary instead ! - def _setobj(self, pointing_to, solid=False): + def _setobj(self, pointing_to, solid=False): if pointing_to is None: obj0 = None elif (solid or self._T._gckind != 'raw' or @@ -1131,7 +1131,7 @@ obj0 = weakref.ref(pointing_to) self._set_solid(solid) self._set_obj0(obj0) - + def _getobj(self, check=True): obj = self._obj0 if obj is not None: @@ -1307,7 +1307,7 @@ return result class _ptr(_abstract_ptr): - __slots__ = ('_TYPE', + __slots__ = ('_TYPE', '_weak', '_solid', '_obj0', '__weakref__') @@ -1462,9 +1462,9 @@ assert T._gckind == 'raw' val = _interior_ptr(T, self._parent, self._offsets + [offset]) return val - - - + + + assert not '__dict__' in dir(_interior_ptr) class _container(object): @@ -1581,7 +1581,7 @@ __slots__ = flds cache[tag] = _struct1 return _struct1 - + #for pickling support: def _get_empty_instance_of_struct_variety(flds): cls = _struct_variety(flds) @@ -1644,7 +1644,7 @@ return r # for FixedSizeArray kind of structs: - + def getlength(self): assert isinstance(self._TYPE, FixedSizeArray) return self._TYPE.length @@ -1891,6 +1891,8 @@ attrs.setdefault('_name', '?') attrs.setdefault('_callable', None) self.__dict__.update(attrs) + if '_callable' in attrs: + self.__dict__['compilation_info'] = getattr(attrs['_callable'], '_compilation_info', None) def __repr__(self): return '<%s>' % (self,) @@ -1959,7 +1961,7 @@ # if we are an opaque containing a normal Struct/GcStruct, # unwrap it if hasattr(self, 'container'): - # an integer, cast to a ptr, cast to an opaque + # an integer, cast to a ptr, cast to an opaque if type(self.container) is int: return self.container if getattr(self.container, '_carry_around_for_tests', False): @@ -2082,7 +2084,7 @@ if not isinstance(GCSTRUCT, RttiStruct): raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT if GCSTRUCT._runtime_type_info is None: - raise ValueError, ("no attached runtime type info for GcStruct %s" % + raise ValueError, ("no attached runtime type info for GcStruct %s" % GCSTRUCT._name) return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info) diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py --- a/rpython/translator/c/node.py +++ b/rpython/translator/c/node.py @@ -492,7 +492,7 @@ class ContainerNode(Node): if USESLOTS: # keep the number of slots down! - __slots__ = """db obj + __slots__ = """db obj typename implementationtypename name _funccodegen_owner 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 @@ -1,10 +1,13 @@ import py import sys, os, re +from rpython.config.translationoption import get_combined_translation_config 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.entrypoint import entrypoint, secondary_entrypoints +from rpython.rtyper.lltypesystem import lltype from rpython.translator.translator import TranslationContext from rpython.translator.backendopt import all from rpython.translator.c.genc import CStandaloneBuilder, ExternalCompilationInfo @@ -18,9 +21,16 @@ config = None def compile(self, entry_point, debug=True, shared=False, - stackcheck=False): + stackcheck=False, entrypoints=None): t = TranslationContext(self.config) - t.buildannotator().build_types(entry_point, [s_list_of_strings]) + ann = t.buildannotator() + ann.build_types(entry_point, [s_list_of_strings]) + if secondary_entrypoints is not None: + anns = {} + for func, annotation in secondary_entrypoints['test']: + anns[func] = annotation + for item in entrypoints: + ann.build_types(item, anns[item]) t.buildrtyper().specialize() if stackcheck: @@ -29,7 +39,8 @@ t.config.translation.shared = shared - cbuilder = CStandaloneBuilder(t, entry_point, t.config) + cbuilder = CStandaloneBuilder(t, entry_point, t.config, + secondary_entrypoints=[(i, None) for i in entrypoints]) if debug: cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) else: @@ -89,7 +100,7 @@ llop.instrument_count(lltype.Void, 'test', 1) llop.instrument_count(lltype.Void, 'test', 1) llop.instrument_count(lltype.Void, 'test', 2) - llop.instrument_count(lltype.Void, 'test', 1) + llop.instrument_count(lltype.Void, 'test', 1) return 0 t = TranslationContext(self.config) t.config.translation.instrument = True @@ -277,7 +288,7 @@ def test_debug_print_start_stop(self): from rpython.rtyper.lltypesystem import rffi - + def entry_point(argv): x = "got:" debug_start ("mycat") @@ -409,7 +420,6 @@ assert 'bok' in data # # finally, check compiling with logging disabled - from rpython.config.translationoption import get_combined_translation_config config = get_combined_translation_config(translating=True) config.translation.log = False self.config = config @@ -823,7 +833,6 @@ py.test.skip("TestMaemo: tests skipped for now") from rpython.translator.platform.maemo import check_scratchbox check_scratchbox() - from rpython.config.translationoption import get_combined_translation_config config = get_combined_translation_config(translating=True) config.translation.platform = 'maemo' cls.config = config @@ -1164,3 +1173,26 @@ and result.count('c') == result.count('p') == 5 and result.count('a') == 1 and result.count('d') == 6) + + +class TestShared(StandaloneTests): + + def test_entrypoint(self): + import ctypes + + config = get_combined_translation_config(translating=True) + self.config = config + + @entrypoint('test', [lltype.Signed], relax=True, c_name='foo') + def f(a): + return a + 3 + + def entry_point(argv): + return 0 + + t, cbuilder = self.compile(entry_point, shared=True, + entrypoints=[f]) + libname = cbuilder.executable_name.join('..', 'lib' + + cbuilder.modulename + '.so') + lib = ctypes.CDLL(str(libname)) + assert lib.foo(13) == 16 From noreply at buildbot.pypy.org Sat May 11 15:34:59 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 11 May 2013 15:34:59 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130511133459.0EEEE1C11B7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63983:e13cd035c6ce Date: 2013-05-11 15:34 +0200 http://bitbucket.org/pypy/pypy/changeset/e13cd035c6ce/ Log: merge 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 @@ -5,3 +5,5 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 +.. branch: numpy-pickle +Pickling of numpy arrays and dtypes (including record dtypes) diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -13,6 +13,7 @@ # imported yet, and when it has been, it is mod.__dict__.items() just # after startup(). w_initialdict = None + lazy = False def __init__(self, space, w_name): """ NOT_RPYTHON """ diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -12,6 +12,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + '_reconstruct' : 'interp_numarray._reconstruct', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -55,6 +55,9 @@ def get_size(self): return self.size // self.dtype.itemtype.get_element_size() + def get_storage_size(self): + return self.size + def reshape(self, space, orig_array, new_shape): # Since we got to here, prod(new_shape) == self.size new_strides = None @@ -328,13 +331,14 @@ class ConcreteArray(ConcreteArrayNotOwning): - def __init__(self, shape, dtype, order, strides, backstrides): - # we allocate the actual storage later because we need to compute - # self.size first + def __init__(self, shape, dtype, order, strides, backstrides, storage=lltype.nullptr(RAW_STORAGE)): null_storage = lltype.nullptr(RAW_STORAGE) ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides, null_storage) - self.storage = dtype.itemtype.malloc(self.size) + if storage == lltype.nullptr(RAW_STORAGE): + self.storage = dtype.itemtype.malloc(self.size) + else: + self.storage = storage def __del__(self): free_raw_storage(self.storage, track_allocation=False) diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -35,12 +35,17 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(shape, storage, dtype, order='C'): + def from_shape_and_storage(shape, storage, dtype, order='C', owning=False): from pypy.module.micronumpy.arrayimpl import concrete assert shape strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, - backstrides, storage) + if owning: + # Will free storage when GCd + impl = concrete.ConcreteArray(shape, dtype, order, strides, + backstrides, storage=storage) + else: + impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, + backstrides, storage) return W_NDimArray(impl) @staticmethod diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -133,11 +133,46 @@ space.wrap(offset)])) return w_d + def set_fields(self, space, w_fields): + if w_fields == space.w_None: + self.fields = None + else: + ofs_and_items = [] + size = 0 + for key in space.listview(w_fields): + value = space.getitem(w_fields, key) + + dtype = space.getitem(value, space.wrap(0)) + assert isinstance(dtype, W_Dtype) + + offset = space.int_w(space.getitem(value, space.wrap(1))) + self.fields[space.str_w(key)] = offset, dtype + + ofs_and_items.append((offset, dtype.itemtype)) + size += dtype.itemtype.get_element_size() + + self.itemtype = types.RecordType(ofs_and_items, size) + self.name = "void" + str(8 * self.itemtype.get_element_size()) + def descr_get_names(self, space): if self.fieldnames is None: return space.w_None return space.newtuple([space.wrap(name) for name in self.fieldnames]) + def set_names(self, space, w_names): + if w_names == space.w_None: + self.fieldnames = None + else: + self.fieldnames = [] + iter = space.iter(w_names) + while True: + try: + self.fieldnames.append(space.str_w(space.next(iter))) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + @unwrap_spec(item=str) def descr_getitem(self, space, item): if self.fields is None: @@ -180,6 +215,51 @@ def get_size(self): return self.itemtype.get_element_size() + def descr_reduce(self, space): + w_class = space.type(self) + + kind = self.kind + elemsize = self.itemtype.get_element_size() + builder_args = space.newtuple([space.wrap("%s%d" % (kind, elemsize)), space.wrap(0), space.wrap(1)]) + + version = space.wrap(3) + order = space.wrap(byteorder_prefix if self.native else nonnative_byteorder_prefix) + names = self.descr_get_names(space) + values = self.descr_get_fields(space) + if self.fields: + #TODO: Implement this when subarrays are implemented + subdescr = space.w_None + #TODO: Change this when alignment is implemented : + size = 0 + for key in self.fields: + dtype = self.fields[key][1] + assert isinstance(dtype, W_Dtype) + size += dtype.get_size() + w_size = space.wrap(size) + alignment = space.wrap(1) + else: + subdescr = space.w_None + w_size = space.wrap(-1) + alignment = space.wrap(-1) + flags = space.wrap(0) + + data = space.newtuple([version, order, subdescr, names, values, w_size, alignment, flags]) + + return space.newtuple([w_class, builder_args, data]) + + def descr_setstate(self, space, w_data): + if space.int_w(space.getitem(w_data, space.wrap(0))) != 3: + raise OperationError(space.w_NotImplementedError, space.wrap("Pickling protocol version not supported")) + + self.native = space.str_w(space.getitem(w_data, space.wrap(1))) == byteorder_prefix + + fieldnames = space.getitem(w_data, space.wrap(3)) + self.set_names(space, fieldnames) + + fields = space.getitem(w_data, space.wrap(4)) + self.set_fields(space, fields) + print self.itemtype + class W_ComplexDtype(W_Dtype): def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], @@ -238,8 +318,7 @@ num = 20 basename = 'void' w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - raise OperationError(space.w_NotImplementedError, space.wrap( - "pure void dtype")) + return dtype_from_list(space, space.newlist([])) else: assert char == 'U' basename = 'unicode' @@ -252,9 +331,10 @@ def dtype_from_spec(space, name): raise OperationError(space.w_NotImplementedError, space.wrap( - "dtype from spec")) + "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): + # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) if space.is_none(w_dtype): @@ -297,6 +377,9 @@ __ne__ = interp2app(W_Dtype.descr_ne), __getitem__ = interp2app(W_Dtype.descr_getitem), + __reduce__ = interp2app(W_Dtype.descr_reduce), + __setstate__ = interp2app(W_Dtype.descr_setstate), + num = interp_attrproperty("num", cls=W_Dtype), kind = interp_attrproperty("kind", cls=W_Dtype), char = interp_attrproperty("char", cls=W_Dtype), diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -781,6 +781,42 @@ return space.float(self.descr_getitem(space, space.wrap(0))) raise OperationError(space.w_TypeError, space.wrap("only length-1 arrays can be converted to Python scalars")) + def descr_reduce(self, space): + from rpython.rtyper.lltypesystem import rffi + from rpython.rlib.rstring import StringBuilder + from pypy.interpreter.mixedmodule import MixedModule + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + reconstruct = multiarray.get("_reconstruct") + + parameters = space.newtuple([space.gettypefor(W_NDimArray), space.newtuple([space.wrap(0)]), space.wrap("b")]) + + builder = StringBuilder() + builder.append_charpsize(self.implementation.get_storage(), self.implementation.get_storage_size()) + + state = space.newtuple([ + space.wrap(1), # version + self.descr_get_shape(space), + self.get_dtype(), + space.wrap(False), # is_fortran + space.wrap(builder.build()), + ]) + + return space.newtuple([reconstruct, parameters, state]) + + def descr_setstate(self, space, w_state): + from rpython.rtyper.lltypesystem import rffi + + shape = space.getitem(w_state, space.wrap(1)) + dtype = space.getitem(w_state, space.wrap(2)) + assert isinstance(dtype, interp_dtype.W_Dtype) + isfortran = space.getitem(w_state, space.wrap(3)) + storage = space.getitem(w_state, space.wrap(4)) + + self.implementation = W_NDimArray.from_shape_and_storage([space.int_w(i) for i in space.listview(shape)], rffi.str2charp(space.str_w(storage), track_allocation=False), dtype, owning=True).implementation @unwrap_spec(offset=int) @@ -814,6 +850,7 @@ W_NDimArray.typedef = TypeDef( "ndarray", + __module__ = "numpypy", __new__ = interp2app(descr_new_array), __len__ = interp2app(W_NDimArray.descr_len), @@ -932,6 +969,8 @@ __pypy_data__ = GetSetProperty(W_NDimArray.fget___pypy_data__, W_NDimArray.fset___pypy_data__, W_NDimArray.fdel___pypy_data__), + __reduce__ = interp2app(W_NDimArray.descr_reduce), + __setstate__ = interp2app(W_NDimArray.descr_setstate), ) @unwrap_spec(ndmin=int, copy=bool, subok=bool) @@ -1008,6 +1047,9 @@ arr.fill(one) return space.wrap(arr) +def _reconstruct(space, w_subtype, w_shape, w_dtype): + return descr_new_array(space, w_subtype, w_shape, w_dtype) + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -73,8 +73,8 @@ # Coerce to floats, some of these will eventually be float16, or # whatever our smallest float type is. - assert find_unaryop_result_dtype(space, bool_dtype, promote_to_float=True) is float16_dtype - assert find_unaryop_result_dtype(space, int8_dtype, promote_to_float=True) is float16_dtype + assert find_unaryop_result_dtype(space, bool_dtype, promote_to_float=True) is float16_dtype + assert find_unaryop_result_dtype(space, int8_dtype, promote_to_float=True) is float16_dtype assert find_unaryop_result_dtype(space, uint8_dtype, promote_to_float=True) is float16_dtype assert find_unaryop_result_dtype(space, int16_dtype, promote_to_float=True) is float32_dtype assert find_unaryop_result_dtype(space, uint16_dtype, promote_to_float=True) is float32_dtype diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -14,8 +14,9 @@ from rpython.rtyper.lltypesystem import rffi ptr_size = rffi.sizeof(rffi.CCHARP) cls.w_ptr_size = cls.space.wrap(ptr_size) - + class AppTestDtypes(BaseAppTestDtypes): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_dtype(self): from numpypy import dtype @@ -149,7 +150,7 @@ def test_bool_binop_types(self): from numpypy import array, dtype types = [ - '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd', + '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd', 'e' ] a = array([True], '?') @@ -270,6 +271,23 @@ ]: assert hash(tp(value)) == hash(value) + def test_pickle(self): + from numpypy import array, dtype + from cPickle import loads, dumps + a = array([1,2,3]) + assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + assert loads(dumps(a.dtype)) == a.dtype + + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): @@ -340,7 +358,7 @@ import numpypy as numpy assert numpy.int8.mro() == [numpy.int8, numpy.signedinteger, - numpy.integer, numpy.number, + numpy.integer, numpy.number, numpy.generic, object] a = numpy.array([1, 2, 3], numpy.int8) @@ -363,8 +381,8 @@ def test_uint8(self): import numpypy as numpy - assert numpy.uint8.mro() == [numpy.uint8, numpy.unsignedinteger, - numpy.integer, numpy.number, + assert numpy.uint8.mro() == [numpy.uint8, numpy.unsignedinteger, + numpy.integer, numpy.number, numpy.generic, object] a = numpy.array([1, 2, 3], numpy.uint8) @@ -435,8 +453,8 @@ import numpypy as numpy assert numpy.int_ is numpy.dtype(int).type - assert numpy.int_.mro() == [numpy.int_, numpy.signedinteger, - numpy.integer, numpy.number, + assert numpy.int_.mro() == [numpy.int_, numpy.signedinteger, + numpy.integer, numpy.number, numpy.generic, int, object] def test_int64(self): @@ -444,12 +462,12 @@ import numpypy as numpy if sys.maxint == 2 ** 63 -1: - assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, - numpy.integer, numpy.number, + assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, + numpy.integer, numpy.number, numpy.generic, int, object] else: - assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, - numpy.integer, numpy.number, + assert numpy.int64.mro() == [numpy.int64, numpy.signedinteger, + numpy.integer, numpy.number, numpy.generic, object] assert numpy.dtype(numpy.int64).type is numpy.int64 @@ -465,8 +483,8 @@ import sys import numpypy as numpy - assert numpy.uint64.mro() == [numpy.uint64, numpy.unsignedinteger, - numpy.integer, numpy.number, + assert numpy.uint64.mro() == [numpy.uint64, numpy.unsignedinteger, + numpy.integer, numpy.number, numpy.generic, object] assert numpy.dtype(numpy.uint64).type is numpy.uint64 @@ -481,8 +499,8 @@ def test_float16(self): import numpypy as numpy - assert numpy.float16.mro() == [numpy.float16, numpy.floating, - numpy.inexact, numpy.number, + assert numpy.float16.mro() == [numpy.float16, numpy.floating, + numpy.inexact, numpy.number, numpy.generic, object] assert numpy.float16(12) == numpy.float64(12) @@ -493,8 +511,8 @@ def test_float32(self): import numpypy as numpy - assert numpy.float32.mro() == [numpy.float32, numpy.floating, - numpy.inexact, numpy.number, + assert numpy.float32.mro() == [numpy.float32, numpy.floating, + numpy.inexact, numpy.number, numpy.generic, object] assert numpy.float32(12) == numpy.float64(12) @@ -504,8 +522,8 @@ def test_float64(self): import numpypy as numpy - assert numpy.float64.mro() == [numpy.float64, numpy.floating, - numpy.inexact, numpy.number, + assert numpy.float64.mro() == [numpy.float64, numpy.floating, + numpy.inexact, numpy.number, numpy.generic, float, object] a = numpy.array([1, 2, 3], numpy.float64) @@ -856,7 +874,7 @@ # it can be float96 or float128 if numpy.longfloat != numpy.float64: assert numpy.longfloat.mro()[1:] == [numpy.floating, - numpy.inexact, numpy.number, + numpy.inexact, numpy.number, numpy.generic, object] a = numpy.array([1, 2, 3], numpy.longdouble) assert type(a[1]) is numpy.longdouble @@ -898,3 +916,4 @@ a = array([1, 2, 3], dtype=self.non_native_prefix + 'G') # clongdouble assert a[0] == 1 assert (a + a)[1] == 4 + diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -214,6 +214,7 @@ assert get(1, 1) == 3 class AppTestNumArray(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def w_CustomIndexObject(self, index): class CustomIndexObject(object): def __init__(self, index): @@ -1786,6 +1787,17 @@ assert raises(TypeError, "int(array([1, 2]))") assert int(array([1.5])) == 1 + def test__reduce__(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + a = array([1, 2], dtype="int64") + data = a.__reduce__() + + assert data[2][4] == '\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00' + + pickled_data = dumps(a) + assert (loads(pickled_data) == a).all() class AppTestMultiDim(BaseNumpyAppTest): def test_init(self): @@ -2534,6 +2546,8 @@ class AppTestRecordDtype(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) + def test_zeros(self): from numpypy import zeros, integer a = zeros(2, dtype=[('x', int), ('y', float)]) @@ -2666,6 +2680,25 @@ assert s.replace('\n', '') == \ "array(['abc', 'defg', 'ab'], dtype='|S4')" + def test_pickle(self): + from numpypy import dtype, array + from cPickle import loads, dumps + + d = dtype([('x', str), ('y', 'int32')]) + a = array([('a', 2), ('cde', 1)], dtype=d) + + a = loads(dumps(a)) + d = a.dtype + + assert str(d.fields['x'][0]) == '|S0' + assert d.fields['x'][1] == 0 + assert str(d.fields['y'][0]) == 'int32' + assert d.fields['y'][1] == 0 + assert d.name == 'void32' + + assert a[0]['y'] == 2 + assert a[1]['y'] == 1 + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1005,6 +1005,19 @@ """ self.optimize_loop(ops, expected) + def test_virtual_array_of_struct_len(self): + ops = """ + [] + p0 = new_array(2, descr=complexarraydescr) + i0 = arraylen_gc(p0) + finish(i0) + """ + expected = """ + [] + finish(2) + """ + self.optimize_loop(ops, expected) + def test_nonvirtual_1(self): ops = """ [i] diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -332,6 +332,9 @@ self.arraydescr = arraydescr self._items = [{} for _ in xrange(size)] + def getlength(self): + return len(self._items) + def getinteriorfield(self, index, ofs, default): return self._items[index].get(ofs, default) diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -1314,7 +1314,8 @@ assert t1.sign >= 0 assert 2*shift + t1.numdigits() <= ret.numdigits() - ret._digits[2*shift : 2*shift + t1.numdigits()] = t1._digits + for i in range(t1.numdigits()): + ret._digits[2*shift + i] = t1._digits[i] # Zero-out the digits higher than the ah*bh copy. */ ## ignored, assuming that we initialize to zero @@ -1327,7 +1328,8 @@ t2 = al.mul(bl) assert t2.sign >= 0 assert t2.numdigits() <= 2*shift # no overlap with high digits - ret._digits[:t2.numdigits()] = t2._digits + for i in range(t2.numdigits()): + ret._digits[i] = t2._digits[i] # Zero out remaining digits. ## ignored, assuming that we initialize to zero diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -446,7 +446,7 @@ TYPES += ['__int128_t'] except CompilationError: pass - + _TYPES_ARE_UNSIGNED = set(['size_t', 'uintptr_t']) # plus "unsigned *" if os.name != 'nt': TYPES.append('mode_t') @@ -693,10 +693,13 @@ builder_class = UnicodeBuilder # str -> char* - def str2charp(s): + def str2charp(s, track_allocation=True): """ str -> char* """ - array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw') + if track_allocation: + array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=True) + else: + array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw', track_allocation=False) i = len(s) array[i] = lastchar i -= 1 @@ -704,10 +707,13 @@ array[i] = s[i] i -= 1 return array - str2charp._annenforceargs_ = [strtype] + str2charp._annenforceargs_ = [strtype, bool] - def free_charp(cp): - lltype.free(cp, flavor='raw') + def free_charp(cp, track_allocation=True): + if track_allocation: + lltype.free(cp, flavor='raw', track_allocation=True) + else: + lltype.free(cp, flavor='raw', track_allocation=False) # char* -> str # doesn't free char* From noreply at buildbot.pypy.org Sat May 11 17:44:23 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 11 May 2013 17:44:23 +0200 (CEST) Subject: [pypy-commit] pypy default: don't set this attr to none Message-ID: <20130511154423.0C1211C0307@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63984:ce9ddb64ff3b Date: 2013-05-11 17:43 +0200 http://bitbucket.org/pypy/pypy/changeset/ce9ddb64ff3b/ Log: don't set this attr to none diff --git a/rpython/rtyper/lltypesystem/lltype.py b/rpython/rtyper/lltypesystem/lltype.py --- a/rpython/rtyper/lltypesystem/lltype.py +++ b/rpython/rtyper/lltypesystem/lltype.py @@ -1891,8 +1891,8 @@ attrs.setdefault('_name', '?') attrs.setdefault('_callable', None) self.__dict__.update(attrs) - if '_callable' in attrs: - self.__dict__['compilation_info'] = getattr(attrs['_callable'], '_compilation_info', None) + if '_callable' in attrs and hasattr(attrs['_callable'], '_compilation_info'): + self.__dict__['compilation_info'] = attrs['_callable']._compilation_info def __repr__(self): return '<%s>' % (self,) From noreply at buildbot.pypy.org Sat May 11 18:09:55 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 11 May 2013 18:09:55 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Add a test for subarrays Message-ID: <20130511160955.D8E0A1C029E@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r63985:2ed9933ad5ce Date: 2013-05-11 16:55 +0200 http://bitbucket.org/pypy/pypy/changeset/2ed9933ad5ce/ Log: Add a test for subarrays diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -723,7 +723,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -790,6 +790,15 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) From noreply at buildbot.pypy.org Sat May 11 18:09:57 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 11 May 2013 18:09:57 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Implement dtype.shape Message-ID: <20130511160957.398971C029E@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r63986:159e1024713b Date: 2013-05-11 18:08 +0200 http://bitbucket.org/pypy/pypy/changeset/159e1024713b/ Log: Implement dtype.shape diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -50,7 +50,7 @@ def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,8 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = shape + self.subdtype = subdtype @specialize.argtype(1) def box(self, value): @@ -111,8 +113,11 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), space.newtuple(shape)]) + def descr_get_shape(self, space): - return space.newtuple([]) + return space.newtuple(self.shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -279,17 +284,23 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_shape = space.getitem(w_elem, space.wrap(2)) + w_fldname = space.getitem(w_elem, space.wrap(0)) + w_flddesc = space.getitem(w_elem, space.wrap(1)) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) + import pdb; pdb.set_trace() return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), "V", space.gettypefor(interp_boxes.W_VoidBox), fields=fields, fieldnames=fieldnames) @@ -333,10 +344,19 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and space.len_w(w_shape) > 0: + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + size = 1 + shape = space.listview(w_shape) + for dim in shape: + size *= space.int_w(dim) + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -391,6 +411,7 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1076,7 +1076,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1217,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1225,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1341,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1696,7 +1696,7 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char From noreply at buildbot.pypy.org Sat May 11 18:16:48 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 11 May 2013 18:16:48 +0200 (CEST) Subject: [pypy-commit] pypy default: Relax the signature check - it's necessary for *args which we have Message-ID: <20130511161648.A61F91C029E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63987:7607e77438bf Date: 2013-05-11 18:15 +0200 http://bitbucket.org/pypy/pypy/changeset/7607e77438bf/ Log: Relax the signature check - it's necessary for *args which we have in wrapper diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -6,7 +6,7 @@ pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) -def entrypoint(key, argtypes, c_name=None, relax=False): +def entrypoint(key, argtypes, c_name=None, relax=True): """ Note: entrypoint should call llop.gc_stack_bottom on it's own. That's necessary for making it work with asmgcc and hence JIT From noreply at buildbot.pypy.org Sat May 11 18:32:14 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 11 May 2013 18:32:14 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Add more checks Message-ID: <20130511163214.B99E81C0307@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r63988:eae319856642 Date: 2013-05-11 18:31 +0200 http://bitbucket.org/pypy/pypy/changeset/eae319856642/ Log: Add more checks diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -794,10 +794,13 @@ from numpypy import dtype d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) assert d.itemsize == 32 + assert d.name == "void256" keys = d.fields.keys() assert "x" in keys assert "y" in keys assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): From noreply at buildbot.pypy.org Sat May 11 18:55:46 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 11 May 2013 18:55:46 +0200 (CEST) Subject: [pypy-commit] pypy default: ARGH Message-ID: <20130511165546.C31131C029E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r63989:6545ccd0c972 Date: 2013-05-11 18:54 +0200 http://bitbucket.org/pypy/pypy/changeset/6545ccd0c972/ Log: ARGH diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -30,7 +30,7 @@ else: print str(e) pypy_debug_catch_fatal_exception() - llop.debug_fatalerror(lltype.Void) + llop.debug_fatalerror(lltype.Void, "error in c callback") assert 0 # dead code rffi.stackcounter.stacks_counter -= 1 return res From noreply at buildbot.pypy.org Sat May 11 20:27:52 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 11 May 2013 20:27:52 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Start fixing translation Message-ID: <20130511182752.9B41E1C009D@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r63990:3842cf257b00 Date: 2013-05-11 20:27 +0200 http://bitbucket.org/pypy/pypy/changeset/3842cf257b00/ Log: Start fixing translation diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -114,7 +114,7 @@ return space.wrap(self.itemtype.alignment) def descr_get_subdtype(self, space): - return space.newtuple([space.wrap(self.subdtype), space.newtuple(shape)]) + return space.newtuple([space.wrap(self.subdtype), space.newtuple(self.shape)]) def descr_get_shape(self, space): return space.newtuple(self.shape) @@ -350,6 +350,7 @@ if w_shape is not None and space.len_w(w_shape) > 0: subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) size = 1 shape = space.listview(w_shape) for dim in shape: From noreply at buildbot.pypy.org Sat May 11 21:42:52 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sat, 11 May 2013 21:42:52 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: nditer class from numpy 1.6 Message-ID: <20130511194252.B16F11C029E@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r63991:7a2730528d98 Date: 2013-05-10 09:34 +0300 http://bitbucket.org/pypy/pypy/changeset/7a2730528d98/ Log: nditer class from numpy 1.6 From noreply at buildbot.pypy.org Sat May 11 21:42:54 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sat, 11 May 2013 21:42:54 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: add tests from numpy docstring documentation Message-ID: <20130511194254.1942F1C1024@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r63992:91e7fea3c006 Date: 2013-05-10 14:55 +0300 http://bitbucket.org/pypy/pypy/changeset/91e7fea3c006/ Log: add tests from numpy docstring documentation diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_nditer.py @@ -0,0 +1,203 @@ +import py +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +def raises(*args, **kwargs): + #sometimes ValueError, sometimes TypeError, but we don't really care which + exc = py.test.raises((ValueError, TypeError), *args, **kwargs) + return exc + +class AppTestNDIter(BaseNumpyAppTest): + def setup_class(cls): + BaseNumpyAppTest.setup_class.im_func(cls) + + def test_basic(self): + from numpypy import arange, nditer + a = arange(6).reshape(2,3) + r = [] + for x in nditer(a): + r.append(x) + assert r == [0, 1, 2, 3, 4, 5] + r = [] + + for x in nditer(a.T): + r.append(x) + assert r == [0, 1, 2, 3, 4, 5] + + def test_order(self): + from numpypy import arange, nditer + a = arange(6).reshape(2,3) + r = [] + for x in nditer(a, order='C'): + r.append(x) + assert r == [0, 1, 2, 3, 4, 5] + r = [] + for x in nditer(a, order='F'): + r.append(x) + assert r == [0, 3, 1, 4, 2, 5] + + def test_readwrite(self): + from numpypy import arange, nditer + a = arange(6).reshape(2,3) + for x in nditer(a, op_flags=['readwrite']): + x[...] = 2 * x + assert (a == [[0, 2, 4], [6, 8, 10]]).all() + + def test_external_loop(self): + from numpypy import arange, nditer, array + a = arange(6).reshape(2,3) + r = [] + for x in nditer(a, flags=['external_loop']): + r.append(x) + assert (array(r) == [0, 1, 2, 3, 4, 5]).all() + r = [] + for x in nditer(a, flags=['external_loop'], order='F'): + r.append(x) + assert (array(r) == [[0, 3], [1, 4], [2, 5]]).all() + + def test_interface(self): + from numpypy import arange, nditer, zeros + a = arange(6).reshape(2,3) + r = [] + it = nditer(a, flags=['f_index']) + while not it.finished: + r.append((it[0], it.index)) + it.iternext() + assert r == [(0, 0), (1, 2), (2, 4), (3, 1), (4, 3), (5, 5)] + it = nditer(a, flags=['multi_index'], op_flags=['writeonly']) + while not it.finished: + it[0] = it.multi_index[1] - it.multi_index[0] + it.iternext() + assert (a == [[0, 1, 2], [-1, 0, 1]]).all() + b = zeros((2, 3)) + exc = raises(nditer, b, flags=['c_index', 'external_loop']) + assert str(exc.value).startswith("Iterator flag EXTERNAL_LOOP cannot") + + def test_buffered(self): + from numpypy import arange, nditer, array + a = arange(6).reshape(2,3) + r = [] + for x in nditer(a, flags=['external_loop', 'buffered'], order='F'): + r.append(x) + assert (array(r) == [0, 3, 1, 4, 2, 5]).all() + + def test_op_dtype(self): + from numpypy import arange, nditer, sqrt, array + a = arange(6).reshape(2,3) - 3 + exc = raises(nditer, a, op_dtypes=['complex']) + assert str(exc.value).startswith("Iterator operand required copying or buffering") + r = [] + for x in nditer(a, op_flags=['readonly','copy'], + op_dtypes=['complex128']): + r.append(sqrt(x)) + assert abs((array(r) - [1.73205080757j, 1.41421356237j, 1j, 0j, + 1+0j, 1.41421356237+0j]).sum()) < 1e-5 + r = [] + for x in nditer(a, flags=['buffered'], + op_dtypes=['complex128']): + r.append(sqrt(x)) + assert abs((array(r) - [1.73205080757j, 1.41421356237j, 1j, 0j, + 1+0j, 1.41421356237+0j]).sum()) < 1e-5 + + def test_casting(self): + from numpypy import arange, nditer + a = arange(6.) + exc = raises(nditer, a, flags=['buffered'], op_dtypes=['float32']) + assert str(exc.value).startswith("Iterator operand 0 dtype could not be cast") + r = [] + for x in nditer(a, flags=['buffered'], op_dtypes=['float32'], + casting='same_kind'): + r.append(x) + assert r == [0., 1., 2., 3., 4., 5.] + exc = raises(nditer, a, flags=['buffered'], + op_dtypes=['int32'], casting='same_kind') + assert str(exc.value).startswith("Iterator operand 0 dtype could not be cast") + r = [] + b = arange(6) + exc = raises(nditer, b, flags=['buffered'], op_dtypes=['float64'], + op_flags=['readwrite'], casting='same_kind') + assert str(exc.value).startswith("Iterator requested dtype could not be cast") + + def test_broadcast(self): + from numpypy import arange, nditer + a = arange(3) + b = arange(6).reshape(2,3) + r = [] + for x,y in nditer([a, b]): + r.append((x, y)) + assert r == [(0, 0), (1, 1), (2, 2), (0, 3), (1, 4), (2, 5)] + a = arange(2) + exc = raises(nditer, [a, b]) + assert str(exc.value).find('shapes (2) (2,3)') > 0 + + def test_outarg(self): + from numpypy import nditer, zeros, arange + + def square1(a): + it = nditer([a, None]) + for x,y in it: + y[...] = x*x + return it.operands[1] + assert (square1([1, 2, 3]) == [1, 4, 9]).all() + + def square2(a, out=None): + it = nditer([a, out], flags=['external_loop', 'buffered'], + op_flags=[['readonly'], + ['writeonly', 'allocate', 'no_broadcast']]) + for x,y in it: + y[...] = x*x + return it.operands[1] + assert (square2([1, 2, 3]) == [1, 4, 9]).all() + b = zeros((3, )) + c = square2([1, 2, 3], out=b) + assert (c == [1., 4., 9.]).all() + assert (b == c).all() + exc = raises(square2, arange(6).reshape(2, 3), out=b) + assert str(exc.value).startswith('non-broadcastable output') + + def test_outer_product(self): + from numpypy import nditer, arange + a = arange(3) + b = arange(8).reshape(2,4) + it = nditer([a, b, None], flags=['external_loop'], + op_axes=[[0, -1, -1], [-1, 0, 1], None]) + for x, y, z in it: + z[...] = x*y + assert it.operands[2].shape == (3, 2, 4) + for i in range(a.size): + assert (it.operands[2][i] == a[i]*b).all() + + def test_reduction(self): + from numpypy import nditer, arange, array + a = arange(24).reshape(2, 3, 4) + b = array(0) + #reduction operands must be readwrite + for x, y in nditer([a, b], flags=['reduce_ok', 'external_loop'], + op_flags=[['readonly'], ['readwrite']]): + y[...] += x + assert b == 276 + assert b == a.sum() + + # reduction and allocation requires op_axes and initialization + it = nditer([a, None], flags=['reduce_ok', 'external_loop'], + op_flags=[['readonly'], ['readwrite', 'allocate']], + op_axes=[None, [0,1,-1]]) + it.operands[1][...] = 0 + for x, y in it: + y[...] += x + + assert (it.operands[1] == [[6, 22, 38], [54, 70, 86]]).all() + assert (it.operands[1] == a.sum(axis=2)).all() + + # previous example with buffering, requires more flags and reset + it = nditer([a, None], flags=['reduce_ok', 'external_loop', + 'buffered', 'delay_bufalloc'], + op_flags=[['readonly'], ['readwrite', 'allocate']], + op_axes=[None, [0,1,-1]]) + it.operands[1][...] = 0 + it.reset() + for x, y in it: + y[...] += x + + assert (it.operands[1] == [[6, 22, 38], [54, 70, 86]]).all() + assert (it.operands[1] == a.sum(axis=2)).all() + From noreply at buildbot.pypy.org Sat May 11 21:42:55 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sat, 11 May 2013 21:42:55 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: implement skeleton interface for nditer Message-ID: <20130511194255.6339B1C1106@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r63993:d10c6ec5d2d6 Date: 2013-05-11 22:22 +0300 http://bitbucket.org/pypy/pypy/changeset/d10c6ec5d2d6/ Log: implement skeleton interface for nditer diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -21,6 +21,7 @@ 'set_string_function': 'appbridge.set_string_function', 'typeinfo': 'interp_dtype.get_dtype_cache(space).w_typeinfo', + 'nditer': 'interp_nditer.nditer', } diff --git a/pypy/module/micronumpy/interp_nditer.py b/pypy/module/micronumpy/interp_nditer.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/interp_nditer.py @@ -0,0 +1,165 @@ +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr +from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault +from pypy.interpreter.error import OperationError +#from pypy.module.micronumpy.iter import W_NDIter + +class W_NDIter(W_Root): + + def __init__(self, *args, **kwargs): + pass + + def descr_iter(self, space): + return space.wrap(self) + + def descr_getitem(self, space, w_idx): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_setitem(self, space, w_idx, w_value): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_len(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_next(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_iternext(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_copy(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_debug_print(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_enable_external_loop(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + @unwrap_spec(axis=int) + def descr_remove_axis(self, space, axis): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_remove_multi_index(self, space, w_multi_index): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_reset(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_operands(self, space, w_indx): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_dtypes(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_finished(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_has_delayed_bufalloc(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_has_index(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_index(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_has_multi_index(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_multi_index(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_iterationneedsapi(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_iterindex(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_itersize(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_itviews(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_ndim(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_nop(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_shape(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + def descr_get_value(self, space): + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + + at unwrap_spec(w_flags = WrappedDefault(None), w_op_flags=WrappedDefault(None), + w_op_dtypes = WrappedDefault(None), order=str, + w_casting=WrappedDefault(None), w_op_axes=WrappedDefault(None), + w_itershape=WrappedDefault(None), w_buffersize=WrappedDefault(None)) +def nditer(space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, + w_itershape, w_buffersize, order='K'): + return W_NDIter() + +W_NDIter.typedef = TypeDef( + 'nditer', + __iter__ = interp2app(W_NDIter.descr_iter), + __getitem__ = interp2app(W_NDIter.descr_getitem), + __setitem__ = interp2app(W_NDIter.descr_setitem), + __len__ = interp2app(W_NDIter.descr_len), + + next = interp2app(W_NDIter.descr_next), + iternext = interp2app(W_NDIter.descr_iternext), + copy = interp2app(W_NDIter.descr_copy), + debug_print = interp2app(W_NDIter.descr_debug_print), + enable_external_loop = interp2app(W_NDIter.descr_enable_external_loop), + remove_axis = interp2app(W_NDIter.descr_remove_axis), + remove_multi_index = interp2app(W_NDIter.descr_remove_multi_index), + reset = interp2app(W_NDIter.descr_reset), + + operands = GetSetProperty(W_NDIter.descr_get_operands), + dtypes = GetSetProperty(W_NDIter.descr_get_dtypes), + finished = GetSetProperty(W_NDIter.descr_get_finished), + has_delayed_bufalloc = GetSetProperty(W_NDIter.descr_get_has_delayed_bufalloc), + has_index = GetSetProperty(W_NDIter.descr_get_has_index), + index = GetSetProperty(W_NDIter.descr_get_index), + has_multi_index = GetSetProperty(W_NDIter.descr_get_has_multi_index), + multi_index = GetSetProperty(W_NDIter.descr_get_multi_index), + iterationneedsapi = GetSetProperty(W_NDIter.descr_get_iterationneedsapi), + iterindex = GetSetProperty(W_NDIter.descr_get_iterindex), + itersize = GetSetProperty(W_NDIter.descr_get_itersize), + itviews = GetSetProperty(W_NDIter.descr_get_itviews), + ndim = GetSetProperty(W_NDIter.descr_get_ndim), + nop = GetSetProperty(W_NDIter.descr_get_nop), + shape = GetSetProperty(W_NDIter.descr_get_shape), + value = GetSetProperty(W_NDIter.descr_get_value), +) From noreply at buildbot.pypy.org Sat May 11 22:13:38 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sat, 11 May 2013 22:13:38 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: small fixes Message-ID: <20130511201338.18B501C029E@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r63994:3188b490838c Date: 2013-05-11 23:12 +0300 http://bitbucket.org/pypy/pypy/changeset/3188b490838c/ Log: small fixes diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -285,7 +285,7 @@ fieldnames = [] for w_elem in lst_w: size = 1 - shape = space.newtuple([]) + w_shape = space.newtuple([]) if space.len_w(w_elem) == 3: w_shape = space.getitem(w_elem, space.wrap(2)) w_fldname = space.getitem(w_elem, space.wrap(0)) @@ -300,7 +300,6 @@ offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) - import pdb; pdb.set_trace() return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), "V", space.gettypefor(interp_boxes.W_VoidBox), fields=fields, fieldnames=fieldnames) From noreply at buildbot.pypy.org Sat May 11 22:27:25 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 11 May 2013 22:27:25 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Bump the version number Message-ID: <20130511202725.0BA361C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r63995:5ee5fbb285e7 Date: 2013-05-11 22:26 +0200 http://bitbucket.org/pypy/pypy/changeset/5ee5fbb285e7/ Log: Bump the version number diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.3" /* PyPy version as a string */ -#define PYPY_VERSION "2.0.0" +#define PYPY_VERSION "2.0.1" /* Subversion Revision number of this file (not of the repository). * Empty since Mercurial migration. */ diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -11,7 +11,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (2, 0, 0, "final", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (2, 0, 1, "final", 0) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) From noreply at buildbot.pypy.org Sat May 11 23:16:49 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sat, 11 May 2013 23:16:49 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Don't mention object spaces when describing rpython.flowspace Message-ID: <20130511211649.B94F91C029E@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: improve-docs Changeset: r63996:db5090c34565 Date: 2013-05-11 22:15 +0100 http://bitbucket.org/pypy/pypy/changeset/db5090c34565/ Log: Don't mention object spaces when describing rpython.flowspace diff --git a/rpython/doc/ronan.rst b/rpython/doc/ronan.rst --- a/rpython/doc/ronan.rst +++ b/rpython/doc/ronan.rst @@ -5,55 +5,45 @@ .. _flow-object-space: -The Flow Object Space ---------------------- +Building Flow Graphs +-------------------- Introduction ~~~~~~~~~~~~ -The task of the FlowObjSpace (the source is at :source:`pypy/objspace/flow/`) is to generate a control-flow graph from a -function. This graph will also contain a trace of the individual operations, so -that it is actually just an alternate representation for the function. +The task of the flow graph builder (the source is at :source:`rpython/flowspace/`) +is to generate a control-flow graph from a function. This graph will also +contain a trace of the individual operations, so that it is actually just an +alternate representation for the function. -The FlowObjSpace is an object space, which means that it exports the standard -object space interface and it is driven by the bytecode interpreter. - -The basic idea is that if the bytecode interpreter is given a function, e.g.:: +The basic idea is that if an interpreter is given a function, e.g.:: def f(n): return 3*n+2 -it will do whatever bytecode dispatching and stack-shuffling needed, during -which it issues a sequence of calls to the object space. The FlowObjSpace -merely records these calls (corresponding to "operations") in a structure called -a basic block. To track which value goes where, the FlowObjSpace invents -placeholder "wrapped objects" and give them to the interpreter, so that they -appear in some next operation. This technique is an example of `Abstract -Interpretation`_. +it will compile it to bytecode and then execute it on its VM. +Instead, the flow graph builder contains an `abstract interpreter`_ which takes the bytecode +and performs whatever stack-shuffling and variable juggling is needed, but +merely records any actual operation performed on a Python object into +a structure called a basic block. The result of the operation is represented by a +placeholder value that can appear in further operations. -.. _Abstract Interpretation: http://en.wikipedia.org/wiki/Abstract_interpretation +.. _abstract interpreter: http://en.wikipedia.org/wiki/Abstract_interpretation For example, if the placeholder ``v1`` is given as the argument to the above function, the bytecode interpreter will call ``v2 = space.mul(space.wrap(3), v1)`` and then ``v3 = space.add(v2, space.wrap(2))`` and return ``v3`` as the -result. During these calls the FlowObjSpace will record a basic block:: +result. During these calls, the following block is recorded:: Block(v1): # input argument v2 = mul(Constant(3), v1) v3 = add(v2, Constant(2)) -The Flow model -~~~~~~~~~~~~~~ +Abstract interpretation +~~~~~~~~~~~~~~~~~~~~~~~ -The data structures built up by the flow object space are described in the -:ref:`translation document `. - - -How the FlowObjSpace works -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The FlowObjSpace works by recording all operations issued by the bytecode +``build_flow()`` works by recording all operations issued by the bytecode interpreter into basic blocks. A basic block ends in one of two cases: when the bytecode interpreters calls ``is_true()``, or when a joinpoint is reached. @@ -66,7 +56,7 @@ in the flow graph as well. (Note that this occurs only when an operation is about to be recorded, which allows some amount of constant-folding.) -* If the bytecode interpreter calls ``is_true()``, the FlowObjSpace doesn't +* If the bytecode interpreter calls ``is_true()``, the abstract interpreter doesn't generally know if the answer should be True or False, so it puts a conditional jump and generates two successor blocks for the current basic block. There is some trickery involved so that the bytecode interpreter is @@ -84,13 +74,11 @@ The Flow Model -------------- -The :ref:`Flow Object Space ` is described in the `document -describing object spaces`_. Here we describe the data structures produced by it, -which are the basic data structures of the translation -process. +Here we describe the data structures produced by ``build_flow()``, which are +the basic data structures of the translation process. -All these types are defined in :source:`rpython/flowspace/model.py` (which is a rather -important module in the PyPy source base, to reinforce the point). +All these types are defined in :source:`rpython/flowspace/model.py` (which is a +rather important module in the PyPy source base, to reinforce the point). The flow graph of a function is represented by the class ``FunctionGraph``. It contains a reference to a collection of ``Block``\ s connected by ``Link``\ s. @@ -203,8 +191,8 @@ ``SpaceOperation`` A recorded (or otherwise generated) basic operation. - :opname: the name of the operation. The Flow Space produces only operations - from the list in ``pypy.interpreter.baseobjspace``, but later the + :opname: the name of the operation. ``build_flow()`` produces only operations + from the list in ``rpython.flowspace.operation``, but later the names can be changed arbitrarily. :args: list of arguments. Each one is a Constant or a Variable seen @@ -241,5 +229,3 @@ A Constant can occasionally store a mutable Python object. It represents a static, pre-initialized, read-only version of that object. The flow graph should not attempt to actually mutate such Constants. - -.. _document describing object spaces: objspace.html From noreply at buildbot.pypy.org Sun May 12 00:14:48 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 12 May 2013 00:14:48 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: handle non-sequence shape specifiers Message-ID: <20130511221448.DF25B1C1387@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r63997:756280f0295a Date: 2013-05-12 01:04 +0300 http://bitbucket.org/pypy/pypy/changeset/756280f0295a/ Log: handle non-sequence shape specifiers diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -286,8 +286,10 @@ for w_elem in lst_w: size = 1 w_shape = space.newtuple([]) - if space.len_w(w_elem) == 3: + if space.len_w(w_elem) >2: w_shape = space.getitem(w_elem, space.wrap(2)) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) w_fldname = space.getitem(w_elem, space.wrap(0)) w_flddesc = space.getitem(w_elem, space.wrap(1)) subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -800,6 +800,9 @@ assert "y" in keys assert d["x"].shape == (2,) assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) class AppTestNotDirect(BaseNumpyAppTest): From noreply at buildbot.pypy.org Sun May 12 07:40:04 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 12 May 2013 07:40:04 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: fix translation Message-ID: <20130512054004.8DC351C026D@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r63998:e57bd2b23a7a Date: 2013-05-12 08:38 +0300 http://bitbucket.org/pypy/pypy/changeset/e57bd2b23a7a/ Log: fix translation diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,7 +46,7 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], @@ -63,7 +63,7 @@ self.fieldnames = fieldnames self.native = native self.float_type = None - self.shape = shape + self.shape = list(shape) self.subdtype = subdtype @specialize.argtype(1) From noreply at buildbot.pypy.org Sun May 12 08:43:26 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 12 May 2013 08:43:26 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix: pass the -O2 option by default to the C compiler. Previously, Message-ID: <20130512064326.CBF611C026D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r63999:9ffefaf25ca3 Date: 2013-05-12 08:42 +0200 http://bitbucket.org/pypy/pypy/changeset/9ffefaf25ca3/ Log: Fix: pass the -O2 option by default to the C compiler. Previously, it was building any C code with the default -O0. 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 @@ -119,7 +119,7 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: cflags = os.environ["CFLAGS"].split() From noreply at buildbot.pypy.org Sun May 12 08:45:23 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 12 May 2013 08:45:23 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Fix: pass the -O2 option by default to the C compiler. Previously, Message-ID: <20130512064523.B2B521C009D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64000:bf82c2a60166 Date: 2013-05-12 08:42 +0200 http://bitbucket.org/pypy/pypy/changeset/bf82c2a60166/ Log: Fix: pass the -O2 option by default to the C compiler. Previously, it was building any C code with the default -O0. 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 @@ -119,7 +119,7 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: cflags = os.environ["CFLAGS"] From noreply at buildbot.pypy.org Sun May 12 13:10:43 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 13:10:43 +0200 (CEST) Subject: [pypy-commit] pypy default: fix test_standalone and provide -fPIC to DEBUGFLAGS Message-ID: <20130512111043.1CC701C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64001:6f295ae6bdfd Date: 2013-05-12 13:09 +0200 http://bitbucket.org/pypy/pypy/changeset/6f295ae6bdfd/ Log: fix test_standalone and provide -fPIC to DEBUGFLAGS diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -427,7 +427,10 @@ if sys.platform == 'win32': mk.definition('DEBUGFLAGS', '/MD /Zi') else: - mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') + if self.config.translation.shared: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g -fPIC') + else: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') if self.config.translation.shared: mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup") 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 @@ -25,7 +25,7 @@ t = TranslationContext(self.config) ann = t.buildannotator() ann.build_types(entry_point, [s_list_of_strings]) - if secondary_entrypoints is not None: + if entrypoints is not None: anns = {} for func, annotation in secondary_entrypoints['test']: anns[func] = annotation @@ -39,8 +39,11 @@ t.config.translation.shared = shared - cbuilder = CStandaloneBuilder(t, entry_point, t.config, - secondary_entrypoints=[(i, None) for i in entrypoints]) + if entrypoints is not None: + kwds = {'secondary_entrypoints': [(i, None) for i in entrypoints]} + else: + kwds = {} + cbuilder = CStandaloneBuilder(t, entry_point, t.config, **kwds) if debug: cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) else: From noreply at buildbot.pypy.org Sun May 12 13:33:10 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 13:33:10 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix some (but not all) problems with test_zjit Message-ID: <20130512113310.92F3A1C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64002:31390ca4bf23 Date: 2013-05-12 13:32 +0200 http://bitbucket.org/pypy/pypy/changeset/31390ca4bf23/ Log: Fix some (but not all) problems with test_zjit diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -58,7 +58,8 @@ w_str = "str" w_unicode = "unicode" w_complex = "complex" - + w_dict = "dict" + def __init__(self): """NOT_RPYTHON""" self.fromcache = InternalSpaceCache(self).getorbuild @@ -115,9 +116,13 @@ def newcomplex(self, r, i): return ComplexObject(r, i) - def listview(self, obj): + def listview(self, obj, number=-1): assert isinstance(obj, ListObject) + if number != -1: + assert number == 2 + return [obj.items[0], obj.items[1]] return obj.items + fixedview = listview def float(self, w_obj): @@ -480,7 +485,7 @@ w_res = neg.call(interp.space, [arr]) elif self.name == "cos": cos = interp_ufuncs.get(interp.space).cos - w_res = cos.call(interp.space, [arr]) + w_res = cos.call(interp.space, [arr]) elif self.name == "flat": w_res = arr.descr_get_flatiter(interp.space) elif self.name == "argsort": From noreply at buildbot.pypy.org Sun May 12 14:05:45 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 14:05:45 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove unnecessary comment and give up on *args in wrapper Message-ID: <20130512120545.35BB01C13CC@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64003:9fe84dae72e9 Date: 2013-05-12 14:04 +0200 http://bitbucket.org/pypy/pypy/changeset/9fe84dae72e9/ Log: Remove unnecessary comment and give up on *args in wrapper diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -552,8 +552,6 @@ def wrapper(*args): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference - # we hope that malloc removal removes the newtuple() that is - # inserted exactly here by the varargs specializer retval = fatal_value boxed_args = () try: diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -1,5 +1,6 @@ secondary_entrypoints = {} +import py from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import we_are_translated @@ -15,14 +16,15 @@ from rpython.translator.tool.cbuild import ExternalCompilationInfo def deco(func): - def wrapper(*args): + source = py.code.Source(""" + def wrapper(%(args)s): # the tuple has to be killed, but it's fine because this is # called from C rffi.stackcounter.stacks_counter += 1 llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py # this should not raise try: - res = func(*args) + res = func(%(args)s) except Exception, e: if not we_are_translated(): import traceback @@ -34,7 +36,12 @@ assert 0 # dead code rffi.stackcounter.stacks_counter -= 1 return res - + """ % {'args': ', '.join(['arg%d' % i for i in range(len(argtypes))])}) + d = {'rffi': rffi, 'lltype': lltype, + 'pypy_debug_catch_fatal_exception': pypy_debug_catch_fatal_exception, + 'llop': llop, 'func': func, 'we_are_translated': we_are_translated} + exec source.compile() in d + wrapper = d['wrapper'] secondary_entrypoints.setdefault(key, []).append((wrapper, argtypes)) wrapper.func_name = func.func_name if c_name is not None: From noreply at buildbot.pypy.org Sun May 12 14:05:46 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 14:05:46 +0200 (CEST) Subject: [pypy-commit] pypy default: now we can make relax=False by default Message-ID: <20130512120546.57AB21C13CC@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64004:ec8f74e3fb25 Date: 2013-05-12 14:04 +0200 http://bitbucket.org/pypy/pypy/changeset/ec8f74e3fb25/ Log: now we can make relax=False by default diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -7,7 +7,7 @@ pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) -def entrypoint(key, argtypes, c_name=None, relax=True): +def entrypoint(key, argtypes, c_name=None, relax=False): """ Note: entrypoint should call llop.gc_stack_bottom on it's own. That's necessary for making it work with asmgcc and hence JIT From noreply at buildbot.pypy.org Sun May 12 14:20:13 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 14:20:13 +0200 (CEST) Subject: [pypy-commit] pypy default: use 0 as a default for stack number and increase it by 1 when running main Message-ID: <20130512122013.C03461C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64005:e757f9bffff3 Date: 2013-05-12 14:19 +0200 http://bitbucket.org/pypy/pypy/changeset/e757f9bffff3/ Log: use 0 as a default for stack number and increase it by 1 when running main diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -329,8 +329,9 @@ class StackCounter: def _cleanup_(self): - self.stacks_counter = 1 # number of "stack pieces": callbacks + self.stacks_counter = 0 # number of "stack pieces": callbacks # and threads increase it by one + stackcounter = StackCounter() stackcounter._cleanup_() diff --git a/rpython/translator/c/src/entrypoint.c b/rpython/translator/c/src/entrypoint.c --- a/rpython/translator/c/src/entrypoint.c +++ b/rpython/translator/c/src/entrypoint.c @@ -20,12 +20,20 @@ int pypy_main_function(int argc, char *argv[]) __attribute__((__noinline__)); #endif +# ifdef PYPY_USE_ASMGCC +# include "structdef.h" +# include "forwarddecl.h" +# endif + int pypy_main_function(int argc, char *argv[]) { char *errmsg; int i, exitcode; RPyListOfString *list; +#ifdef PYPY_USE_ASMGCC + pypy_g_rpython_rtyper_lltypesystem_rffi_StackCounter.sc_inst_stacks_counter++; +#endif pypy_asm_stack_bottom(); #ifdef PYPY_X86_CHECK_SSE2_DEFINED pypy_x86_check_sse2(); From noreply at buildbot.pypy.org Sun May 12 16:24:11 2013 From: noreply at buildbot.pypy.org (hodgestar) Date: Sun, 12 May 2013 16:24:11 +0200 (CEST) Subject: [pypy-commit] pypy default: Add support for func_doc/__doc__ to interpindirect2app. Message-ID: <20130512142411.115D01C1439@cobra.cs.uni-duesseldorf.de> Author: Simon Cross Branch: Changeset: r64009:c7ed613a458c Date: 2013-04-16 21:07 +0200 http://bitbucket.org/pypy/pypy/changeset/c7ed613a458c/ Log: Add support for func_doc/__doc__ to interpindirect2app. diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -812,6 +812,7 @@ exec func_code.compile() in d f = d['f'] f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -138,6 +138,7 @@ class BaseA(W_Root): def method(self, space, x): + "This is a method" pass def method_with_default(self, space, x=5): @@ -173,6 +174,9 @@ assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2 assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1 + doc = space.str_w(space.getattr(w_c, space.wrap('__doc__'))) + assert doc == "This is a method" + meth_with_default = gateway.interpindirect2app( BaseA.method_with_default, {'x': int}) w_d = space.wrap(meth_with_default) From noreply at buildbot.pypy.org Sun May 12 16:24:09 2013 From: noreply at buildbot.pypy.org (hodgestar) Date: Sun, 12 May 2013 16:24:09 +0200 (CEST) Subject: [pypy-commit] pypy default: Add support for func_defaults to interpdirect2app. Message-ID: <20130512142409.CBA081C13CC@cobra.cs.uni-duesseldorf.de> Author: Simon Cross Branch: Changeset: r64008:5d6cdfad854a Date: 2013-04-16 21:00 +0200 http://bitbucket.org/pypy/pypy/changeset/5d6cdfad854a/ Log: Add support for func_defaults to interpdirect2app. diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -803,7 +803,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -812,6 +811,7 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -135,18 +135,28 @@ def test_interpindirect2app(self): space = self.space + class BaseA(W_Root): def method(self, space, x): pass + def method_with_default(self, space, x=5): + pass + class A(BaseA): def method(self, space, x): return space.wrap(x + 2) + def method_with_default(self, space, x): + return space.wrap(x + 2) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) + def method_with_default(self, space, x): + return space.wrap(x + 1) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -163,6 +173,15 @@ assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2 assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1 + meth_with_default = gateway.interpindirect2app( + BaseA.method_with_default, {'x': int}) + w_d = space.wrap(meth_with_default) + + assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2 + assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1 + assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2 + assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1 + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap From noreply at buildbot.pypy.org Sun May 12 16:24:12 2013 From: noreply at buildbot.pypy.org (hodgestar) Date: Sun, 12 May 2013 16:24:12 +0200 (CEST) Subject: [pypy-commit] pypy default: Add support for copying unwrap_spec to interpindirect2app. Message-ID: <20130512142412.3EBA01C13CC@cobra.cs.uni-duesseldorf.de> Author: Simon Cross Branch: Changeset: r64010:310b0c27ddc3 Date: 2013-04-16 21:31 +0200 http://bitbucket.org/pypy/pypy/changeset/310b0c27ddc3/ Log: Add support for copying unwrap_spec to interpindirect2app. diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -817,7 +817,7 @@ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = {} + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -144,6 +144,10 @@ def method_with_default(self, space, x=5): pass + @gateway.unwrap_spec(x=int) + def method_with_unwrap_spec(self, space, x): + pass + class A(BaseA): def method(self, space, x): return space.wrap(x + 2) @@ -151,6 +155,9 @@ def method_with_default(self, space, x): return space.wrap(x + 2) + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 2) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) @@ -158,6 +165,9 @@ def method_with_default(self, space, x): return space.wrap(x + 1) + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 1) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -186,6 +196,11 @@ assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2 assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1 + meth_with_unwrap_spec = gateway.interpindirect2app( + BaseA.method_with_unwrap_spec) + w_e = space.wrap(meth_with_unwrap_spec) + assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2 + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap From noreply at buildbot.pypy.org Sun May 12 18:30:22 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 18:30:22 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: work some more on array smm removal Message-ID: <20130512163022.9E03A1C10E6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64011:2b3d8b334946 Date: 2013-05-12 16:24 +0200 http://bitbucket.org/pypy/pypy/changeset/2b3d8b334946/ Log: work some more on array smm removal 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 @@ -51,11 +51,6 @@ return a -array_reverse = SMM('reverse', 1) -array_remove = SMM('remove', 2) -array_pop = SMM('pop', 2, defaults=(-1,)) -array_insert = SMM('insert', 3) - array_tolist = SMM('tolist', 1) array_fromlist = SMM('fromlist', 2) array_tostring = SMM('tostring', 1) @@ -108,6 +103,36 @@ """ raise NotImplementedError + def descr_reverse(self, space): + """ reverse() + + Reverse the order of the items in the array. + """ + raise NotImplementedError + + def descr_remove(self, space, w_val): + """ remove(x) + + Remove the first occurrence of x in the array. + """ + raise NotImplementedError + + @unwrap_spec(i=int) + def descr_pop(self, space, i=-1): + """ pop([i]) + + Return the i-th element and delete it from the array. i defaults to -1. + """ + raise NotImplementedError + + @unwrap_spec(idx=int) + def descr_insert(self, space, idx, w_val): + """ insert(i,x) + + Insert a new item x into the array before position i. + """ + raise NotImplementedError + @staticmethod def register(typeorder): typeorder[W_ArrayBase] = [] @@ -123,6 +148,10 @@ extend = interp2app(W_ArrayBase.descr_extend), count = interpindirect2app(W_ArrayBase.descr_count), index = interpindirect2app(W_ArrayBase.descr_index), + reverse = interpindirect2app(W_ArrayBase.descr_reverse), + remove = interpindirect2app(W_ArrayBase.descr_remove), + pop = interpindirect2app(W_ArrayBase.descr_pop), + insert = interpindirect2app(W_ArrayBase.descr_insert), ) W_ArrayBase.typedef.registermethods(globals()) @@ -394,6 +423,44 @@ msg = 'array.index(x): x not in list' raise OperationError(space.w_ValueError, space.wrap(msg)) + def descr_reverse(self, space): + b = self.buffer + for i in range(self.len / 2): + b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] + + def descr_pop(self, space, i): + if i < 0: + i += self.len + if i < 0 or i >= self.len: + msg = 'pop index out of range' + raise OperationError(space.w_IndexError, space.wrap(msg)) + w_val = self.w_getitem(space, i) + while i < self.len - 1: + self.buffer[i] = self.buffer[i + 1] + i += 1 + self.setlen(self.len - 1) + return w_val + + def descr_remove(self, space, w_val): + w_idx = self.descr_index(space, w_val) + self.descr_pop(space, space.int_w(w_idx)) + + def descr_insert(self, space, idx, w_val): + if idx < 0: + idx += self.len + if idx < 0: + idx = 0 + if idx > self.len: + idx = self.len + + val = self.item_w(w_val) + self.setlen(self.len + 1) + i = self.len - 1 + while i > idx: + self.buffer[i] = self.buffer[i - 1] + i -= 1 + self.buffer[i] = val + # Basic get/set/append/extend methods def len__Array(space, self): @@ -445,46 +512,6 @@ def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x): space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x) - def array_reverse__Array(space, self): - b = self.buffer - for i in range(self.len / 2): - b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] - - def array_pop__Array_ANY(space, self, w_idx): - i = space.int_w(w_idx) - if i < 0: - i += self.len - if i < 0 or i >= self.len: - msg = 'pop index out of range' - raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = self.w_getitem(space, i) - while i < self.len - 1: - self.buffer[i] = self.buffer[i + 1] - i += 1 - self.setlen(self.len - 1) - return w_val - - def array_remove__Array_ANY(space, self, w_val): - w_idx = self.descr_index(space, w_val) - array_pop__Array_ANY(space, self, w_idx) - - def array_insert__Array_ANY_ANY(space, self, w_idx, w_val): - idx = space.int_w(w_idx) - if idx < 0: - idx += self.len - if idx < 0: - idx = 0 - if idx > self.len: - idx = self.len - - val = self.item_w(w_val) - self.setlen(self.len + 1) - i = self.len - 1 - while i > idx: - self.buffer[i] = self.buffer[i - 1] - i -= 1 - self.buffer[i] = val - def delitem__Array_ANY(space, self, w_idx): # XXX this is a giant slow hack w_lst = array_tolist__Array(space, self) From noreply at buildbot.pypy.org Sun May 12 18:30:23 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 18:30:23 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: merge default Message-ID: <20130512163023.DC57B1C13CC@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64012:dc1a1bfd938e Date: 2013-05-12 16:24 +0200 http://bitbucket.org/pypy/pypy/changeset/dc1a1bfd938e/ Log: merge default diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -803,7 +803,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -812,11 +811,13 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = getattr(func, 'unwrap_spec', {}) + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -135,18 +135,39 @@ def test_interpindirect2app(self): space = self.space + class BaseA(W_Root): def method(self, space, x): + "This is a method" + pass + + def method_with_default(self, space, x=5): + pass + + @gateway.unwrap_spec(x=int) + def method_with_unwrap_spec(self, space, x): pass class A(BaseA): def method(self, space, x): return space.wrap(x + 2) + def method_with_default(self, space, x): + return space.wrap(x + 2) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 2) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) + def method_with_default(self, space, x): + return space.wrap(x + 1) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 1) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -163,6 +184,23 @@ assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2 assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1 + doc = space.str_w(space.getattr(w_c, space.wrap('__doc__'))) + assert doc == "This is a method" + + meth_with_default = gateway.interpindirect2app( + BaseA.method_with_default, {'x': int}) + w_d = space.wrap(meth_with_default) + + assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2 + assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1 + assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2 + assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1 + + meth_with_unwrap_spec = gateway.interpindirect2app( + BaseA.method_with_unwrap_spec) + w_e = space.wrap(meth_with_unwrap_spec) + assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2 + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap From noreply at buildbot.pypy.org Sun May 12 18:30:25 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 18:30:25 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: another batch of multimethods Message-ID: <20130512163025.20E4F1C141B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64013:635881d9a4d1 Date: 2013-05-12 18:14 +0200 http://bitbucket.org/pypy/pypy/changeset/635881d9a4d1/ Log: another batch of multimethods 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 @@ -39,9 +39,9 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(space.str_w(w_initializer)) + a.descr_fromstring(space, space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_list: - a.fromlist(w_initializer) + a.descr_fromlist(space, w_initializer) else: a.extend(w_initializer, True) break @@ -51,14 +51,8 @@ return a -array_tolist = SMM('tolist', 1) -array_fromlist = SMM('fromlist', 2) -array_tostring = SMM('tostring', 1) -array_fromstring = SMM('fromstring', 2) array_tounicode = SMM('tounicode', 1) array_fromunicode = SMM('fromunicode', 2) -array_tofile = SMM('tofile', 2) -array_fromfile = SMM('fromfile', 3) array_buffer_info = SMM('buffer_info', 1) array_reduce = SMM('__reduce__', 1) @@ -75,6 +69,11 @@ class W_ArrayBase(W_Object): + def __init__(self, space): + self.space = space + self.len = 0 + self.allocated = 0 + def descr_append(self, space, w_x): """ append(x) @@ -133,6 +132,83 @@ """ raise NotImplementedError + def descr_tolist(self, space): + """ tolist() -> list + + Convert array to an ordinary list with the same items. + """ + w_l = space.newlist([]) + for i in range(self.len): + w_l.append(self.w_getitem(space, i)) + return w_l + + def descr_fromlist(self, space, w_lst): + """ fromlist(list) + + Append items to array from list. + """ + if not space.isinstance_w(w_lst, space.w_list): + raise OperationError(space.w_TypeError, + space.wrap("arg must be list")) + s = self.len + try: + self.fromsequence(w_lst) + except OperationError: + self.setlen(s) + raise + + def descr_tostring(self, space): + """ tostring() -> string + + Convert the array to an array of machine values and return the string + representation. + """ + cbuf = self._charbuf_start() + s = rffi.charpsize2str(cbuf, self.len * self.itemsize) + self._charbuf_stop() + return self.space.wrap(s) + + @unwrap_spec(s=str) + def descr_fromstring(self, space, s): + """ fromstring(string) + + Appends items from the string, interpreting it as an array of machine + values,as if it had been read from a file using the fromfile() method). + """ + if len(s) % self.itemsize != 0: + msg = 'string length not a multiple of item size' + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) + oldlen = self.len + new = len(s) / self.itemsize + self.setlen(oldlen + new) + cbuf = self._charbuf_start() + for i in range(len(s)): + cbuf[oldlen * self.itemsize + i] = s[i] + self._charbuf_stop() + + @unwrap_spec(w_f=W_File, n=int) + def descr_fromfile(self, space, w_f, n): + try: + size = ovfcheck(self.itemsize * n) + except OverflowError: + raise MemoryError + w_item = space.call_method(w_f, 'read', space.wrap(size)) + item = space.str_w(w_item) + if len(item) < size: + n = len(item) % self.itemsize + elems = max(0, len(item) - (len(item) % self.itemsize)) + if n != 0: + item = item[0:elems] + self.descr_fromstring(space, item) + msg = "not enough items in file" + raise OperationError(space.w_EOFError, space.wrap(msg)) + self.descr_fromstring(space, item) + + @unwrap_spec(w_f=W_File) + def descr_tofile(self, space, w_f): + w_s = self.descr_tostring(space) + space.call_method(w_f, 'write', w_s) + @staticmethod def register(typeorder): typeorder[W_ArrayBase] = [] @@ -152,6 +228,12 @@ remove = interpindirect2app(W_ArrayBase.descr_remove), pop = interpindirect2app(W_ArrayBase.descr_pop), insert = interpindirect2app(W_ArrayBase.descr_insert), + tolist = interp2app(W_ArrayBase.descr_tolist), + fromlist = interp2app(W_ArrayBase.descr_fromlist), + tostring = interp2app(W_ArrayBase.descr_tostring), + fromstring = interp2app(W_ArrayBase.descr_fromstring), + tofile = interp2app(W_ArrayBase.descr_tofile), + fromfile = interp2app(W_ArrayBase.descr_fromfile), ) W_ArrayBase.typedef.registermethods(globals()) @@ -235,9 +317,7 @@ typeorder[W_Array] = [(W_ArrayBase, None)] def __init__(self, space): - self.space = space - self.len = 0 - self.allocated = 0 + W_ArrayBase.__init__(self, space) self.buffer = lltype.nullptr(mytype.arraytype) def item_w(self, w_item): @@ -344,26 +424,6 @@ raise self.setlen(oldlen + i) - def fromstring(self, s): - if len(s) % self.itemsize != 0: - msg = 'string length not a multiple of item size' - raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) - oldlen = self.len - new = len(s) / mytype.bytes - self.setlen(oldlen + new) - cbuf = self._charbuf_start() - for i in range(len(s)): - cbuf[oldlen * mytype.bytes + i] = s[i] - self._charbuf_stop() - - def fromlist(self, w_lst): - s = self.len - try: - self.fromsequence(w_lst) - except OperationError: - self.setlen(s) - raise - def extend(self, w_iterable, accept_different_array=False): space = self.space if isinstance(w_iterable, W_Array): @@ -498,7 +558,7 @@ assert step != 0 if w_item.len != size or self is w_item: # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) + w_lst = self.descr_tolist(space) w_item = space.call_method(w_item, 'tolist') space.setitem(w_lst, w_idx, w_item) self.setlen(0) @@ -514,7 +574,7 @@ def delitem__Array_ANY(space, self, w_idx): # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) + w_lst = self.descr_tolist(space) space.delitem(w_lst, w_idx) self.setlen(0) self.fromsequence(w_lst) @@ -632,54 +692,6 @@ # Convertions - def array_tolist__Array(space, self): - w_l = space.newlist([]) - for i in range(self.len): - w_l.append(self.w_getitem(space, i)) - return w_l - - def array_fromlist__Array_List(space, self, w_lst): - self.fromlist(w_lst) - - def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(space.str_w(w_s)) - - def array_tostring__Array(space, self): - cbuf = self._charbuf_start() - s = rffi.charpsize2str(cbuf, self.len * mytype.bytes) - self._charbuf_stop() - return self.space.wrap(s) - - def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - n = space.int_w(w_n) - - try: - size = ovfcheck(self.itemsize * n) - except OverflowError: - raise MemoryError - w_item = space.call_method(w_f, 'read', space.wrap(size)) - item = space.str_w(w_item) - if len(item) < size: - n = len(item) % self.itemsize - elems = max(0, len(item) - (len(item) % self.itemsize)) - if n != 0: - item = item[0:elems] - w_item = space.wrap(item) - array_fromstring__Array_ANY(space, self, w_item) - msg = "not enough items in file" - raise OperationError(space.w_EOFError, space.wrap(msg)) - array_fromstring__Array_ANY(space, self, w_item) - - def array_tofile__Array_ANY(space, self, w_f): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_s = array_tostring__Array(space, self) - space.call_method(w_f, 'write', w_s) - if mytype.typecode == 'u': def array_fromunicode__Array_Unicode(space, self, w_ustr): @@ -706,7 +718,7 @@ @specialize.arg(3) def _cmp_impl(space, self, other, space_fn): # XXX this is a giant slow hack - w_lst1 = array_tolist__Array(space, self) + w_lst1 = self.descr_tolist(space) w_lst2 = space.call_method(other, 'tolist') return space_fn(w_lst1, w_lst2) @@ -740,7 +752,7 @@ def array_reduce__Array(space, self): if self.len > 0: - w_s = array_tostring__Array(space, self) + w_s = self.descr_tostring(space) args = [space.wrap(mytype.typecode), w_s] else: args = [space.wrap(mytype.typecode)] @@ -780,7 +792,7 @@ if self.len == 0: return space.wrap("array('%s')" % self.typecode) elif self.typecode == "c": - r = space.repr(array_tostring__Array(space, self)) + r = space.repr(self.descr_tostring(space)) s = "array('%s', %s)" % (self.typecode, space.str_w(r)) return space.wrap(s) elif self.typecode == "u": @@ -788,7 +800,7 @@ s = "array('%s', %s)" % (self.typecode, space.str_w(r)) return space.wrap(s) else: - r = space.repr(array_tolist__Array(space, self)) + r = space.repr(self.descr_tolist(space)) s = "array('%s', %s)" % (self.typecode, space.str_w(r)) return space.wrap(s) @@ -811,5 +823,6 @@ for mytype in types.values(): make_array(mytype) +del mytype register_all(locals(), globals()) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -19,7 +19,7 @@ class BaseArrayTests: - + def test_ctor(self): assert len(self.array('c')) == 0 assert len(self.array('i')) == 0 @@ -390,7 +390,6 @@ assert self.array('c', ('h', 'i')).tostring() == 'hi' a = self.array('i', [0, 0, 0]) assert a.tostring() == '\x00' * 3 * a.itemsize - s = self.array('i', [1, 2, 3]).tostring() assert '\x00' in s assert '\x01' in s @@ -502,7 +501,7 @@ return 0 class incomparable(object): pass - + for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'), ('abc', 'acb', 'c'), (unicode('abc'), unicode('acb'), 'u')): @@ -653,14 +652,14 @@ raises(TypeError, "a * 'hi'") raises(TypeError, "'hi' * a") raises(TypeError, "a *= 'hi'") - + class mulable(object): def __mul__(self, other): return "mul" def __rmul__(self, other): return "rmul" - + assert mulable() * self.array('i') == 'mul' assert self.array('i') * mulable() == 'rmul' @@ -769,7 +768,7 @@ def __getitem__(self, i): return array.__getitem__(self, self._index(i)) - + def __setitem__(self, i, val): return array.__setitem__(self, self._index(i), val) @@ -783,7 +782,7 @@ assert img[3, 25] == 3 * 9 - + def test_override_from(self): class mya(self.array): def fromlist(self, lst): @@ -854,7 +853,7 @@ def test_subclass_del(self): import array, gc, weakref l = [] - + class A(array.array): pass From noreply at buildbot.pypy.org Sun May 12 18:30:26 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 18:30:26 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: Remove all of SMMs Message-ID: <20130512163026.5A83B1C10E6@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64014:b03c4ec67bdd Date: 2013-05-12 18:29 +0200 http://bitbucket.org/pypy/pypy/changeset/b03c4ec67bdd/ Log: Remove all of SMMs 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 @@ -7,7 +7,7 @@ from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object from pypy.objspace.std.multimethod import FailedToImplement -from pypy.objspace.std.stdtypedef import SMM, StdTypeDef +from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.register_all import register_all from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen @@ -51,14 +51,6 @@ return a -array_tounicode = SMM('tounicode', 1) -array_fromunicode = SMM('fromunicode', 2) - -array_buffer_info = SMM('buffer_info', 1) -array_reduce = SMM('__reduce__', 1) -array_copy = SMM('__copy__', 1) -array_byteswap = SMM('byteswap', 1) - def descr_itemsize(space, self): return space.wrap(self.itemsize) @@ -188,6 +180,11 @@ @unwrap_spec(w_f=W_File, n=int) def descr_fromfile(self, space, w_f, n): + """ fromfile(f, n) + + Read n objects from the file object f and append them to the end of the + array. Also called as read. + """ try: size = ovfcheck(self.itemsize * n) except OverflowError: @@ -206,9 +203,108 @@ @unwrap_spec(w_f=W_File) def descr_tofile(self, space, w_f): + """ tofile(f) + + Write all items (as machine values) to the file object f. Also called as + write. + """ w_s = self.descr_tostring(space) space.call_method(w_f, 'write', w_s) + def descr_fromunicode(self, space, w_ustr): + """ fromunicode(ustr) + + Extends this array with data from the unicode string ustr. + The array must be a type 'u' array; otherwise a ValueError + is raised. Use array.fromstring(ustr.decode(...)) to + append Unicode data to an array of some other type. + """ + # XXX the following probable bug is not emulated: + # CPython accepts a non-unicode string or a buffer, and then + # behaves just like fromstring(), except that it strangely truncate + # string arguments at multiples of the unicode byte size. + # Let's only accept unicode arguments for now. + if self.typecode == 'u': + self.fromsequence(w_ustr) + else: + msg = "fromunicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_tounicode(self, space): + """ tounicode() -> unicode + + Convert the array to a unicode string. The array must be + a type 'u' array; otherwise a ValueError is raised. Use + array.tostring().decode() to obtain a unicode string from + an array of some other type. + """ + if self.typecode == 'u': + return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) + else: + msg = "tounicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_buffer_info(self, space): + """ buffer_info() -> (address, length) + + Return a tuple (address, length) giving the current memory address and + the length in items of the buffer used to hold array's contents + The length should be multiplied by the itemsize attribute to calculate + the buffer length in bytes. + """ + w_ptr = space.wrap(self._buffer_as_unsigned()) + w_len = space.wrap(self.len) + return space.newtuple([w_ptr, w_len]) + + def descr_reduce(self, space): + """ Return state information for pickling. + """ + if self.len > 0: + w_s = self.descr_tostring(space) + args = [space.wrap(self.typecode), w_s] + else: + args = [space.wrap(self.typecode)] + try: + dct = space.getattr(self, space.wrap('__dict__')) + except OperationError: + dct = space.w_None + return space.newtuple([space.type(self), space.newtuple(args), dct]) + + def descr_copy(self, space): + """ copy(array) + + Return a copy of the array. + """ + w_a = self.constructor(self.space) + w_a.setlen(self.len, overallocate=False) + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()), + rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()), + self.len * self.itemsize + ) + return w_a + + def descr_byteswap(self, space): + """ byteswap() + + Byteswap all items of the array. If the items in the array are not 1, 2, + 4, or 8 bytes in size, RuntimeError is raised. + """ + if self.itemsize not in [1, 2, 4, 8]: + msg = "byteswap not supported for this array" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + if self.len == 0: + return + bytes = self._charbuf_start() + tmp = [bytes[0]] * self.itemsize + for start in range(0, self.len * self.itemsize, self.itemsize): + stop = start + self.itemsize - 1 + for i in range(self.itemsize): + tmp[i] = bytes[start + i] + for i in range(self.itemsize): + bytes[stop - i] = tmp[i] + self._charbuf_stop() + @staticmethod def register(typeorder): typeorder[W_ArrayBase] = [] @@ -228,12 +324,20 @@ remove = interpindirect2app(W_ArrayBase.descr_remove), pop = interpindirect2app(W_ArrayBase.descr_pop), insert = interpindirect2app(W_ArrayBase.descr_insert), + tolist = interp2app(W_ArrayBase.descr_tolist), fromlist = interp2app(W_ArrayBase.descr_fromlist), tostring = interp2app(W_ArrayBase.descr_tostring), fromstring = interp2app(W_ArrayBase.descr_fromstring), tofile = interp2app(W_ArrayBase.descr_tofile), fromfile = interp2app(W_ArrayBase.descr_fromfile), + fromunicode = interp2app(W_ArrayBase.descr_fromunicode), + tounicode = interp2app(W_ArrayBase.descr_tounicode), + + buffer_info = interp2app(W_ArrayBase.descr_buffer_info), + __copy__ = interp2app(W_ArrayBase.descr_copy), + __reduce__ = interp2app(W_ArrayBase.descr_reduce), + byteswap = interp2app(W_ArrayBase.descr_byteswap), ) W_ArrayBase.typedef.registermethods(globals()) @@ -242,7 +346,6 @@ def __init__(self, itemtype, unwrap, canoverflow=False, signed=False): self.itemtype = itemtype self.bytes = rffi.sizeof(itemtype) - #self.arraytype = lltype.GcArray(itemtype) self.arraytype = lltype.Array(itemtype, hints={'nolength': True}) self.unwrap = unwrap self.signed = signed @@ -447,6 +550,9 @@ def _charbuf_start(self): return rffi.cast(rffi.CCHARP, self.buffer) + def _buffer_as_unsigned(self): + return rffi.cast(lltype.Unsigned, self.buffer) + def _charbuf_stop(self): keepalive_until_here(self) @@ -690,30 +796,6 @@ a.buffer[r * oldlen + i] = self.buffer[i] return a - # Convertions - - if mytype.typecode == 'u': - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - # XXX the following probable bug is not emulated: - # CPython accepts a non-unicode string or a buffer, and then - # behaves just like fromstring(), except that it strangely truncate - # string arguments at multiples of the unicode byte size. - # Let's only accept unicode arguments for now. - self.fromsequence(w_ustr) - - def array_tounicode__Array(space, self): - return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) - else: - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - msg = "fromunicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - def array_tounicode__Array(space, self): - msg = "tounicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - # Compare methods @specialize.arg(3) def _cmp_impl(space, self, other, space_fn): @@ -745,49 +827,6 @@ def buffer__Array(space, self): return space.wrap(ArrayBuffer(self)) - def array_buffer_info__Array(space, self): - w_ptr = space.wrap(rffi.cast(lltype.Unsigned, self.buffer)) - w_len = space.wrap(self.len) - return space.newtuple([w_ptr, w_len]) - - def array_reduce__Array(space, self): - if self.len > 0: - w_s = self.descr_tostring(space) - args = [space.wrap(mytype.typecode), w_s] - else: - args = [space.wrap(mytype.typecode)] - try: - dct = space.getattr(self, space.wrap('__dict__')) - except OperationError: - dct = space.w_None - return space.newtuple([space.type(self), space.newtuple(args), dct]) - - def array_copy__Array(space, self): - w_a = mytype.w_class(self.space) - w_a.setlen(self.len, overallocate=False) - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, w_a.buffer), - rffi.cast(rffi.VOIDP, self.buffer), - self.len * mytype.bytes - ) - return w_a - - def array_byteswap__Array(space, self): - if mytype.bytes not in [1, 2, 4, 8]: - msg = "byteswap not supported for this array" - raise OperationError(space.w_RuntimeError, space.wrap(msg)) - if self.len == 0: - return - bytes = self._charbuf_start() - tmp = [bytes[0]] * mytype.bytes - for start in range(0, self.len * mytype.bytes, mytype.bytes): - stop = start + mytype.bytes - 1 - for i in range(mytype.bytes): - tmp[i] = bytes[start + i] - for i in range(mytype.bytes): - bytes[stop - i] = tmp[i] - self._charbuf_stop() - def repr__Array(space, self): if self.len == 0: return space.wrap("array('%s')" % self.typecode) @@ -796,7 +835,7 @@ s = "array('%s', %s)" % (self.typecode, space.str_w(r)) return space.wrap(s) elif self.typecode == "u": - r = space.repr(array_tounicode__Array(space, self)) + r = space.repr(self.descr_tounicode(space)) s = "array('%s', %s)" % (self.typecode, space.str_w(r)) return space.wrap(s) else: @@ -805,6 +844,7 @@ return space.wrap(s) mytype.w_class = W_Array + W_Array.constructor = W_Array # Annotator seems to mess up if the names are not unique name = 'ArrayType' + mytype.typecode From noreply at buildbot.pypy.org Sun May 12 19:22:13 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 19:22:13 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: Remove the obscure hack about comparisons in arrays. Also remove the multimethod Message-ID: <20130512172213.DFE3B1C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64015:0ee304706655 Date: 2013-05-12 19:21 +0200 http://bitbucket.org/pypy/pypy/changeset/0ee304706655/ Log: Remove the obscure hack about comparisons in arrays. Also remove the multimethod 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 @@ -305,14 +305,99 @@ bytes[stop - i] = tmp[i] self._charbuf_stop() + def descr_len(self, space): + return space.wrap(self.len) + + def descr_eq(self, space, w_arr2): + "x.__eq__(y) <==> x==y" + return compare_arrays(space, self, w_arr2, space.eq) + + def descr_ne(self, space, w_arr2): + "x.__ne__(y) <==> x!=y" + return compare_arrays(space, self, w_arr2, space.ne) + + def descr_lt(self, space, w_arr2): + "x.__lt__(y) <==> x x<=y" + return compare_arrays(space, self, w_arr2, space.le) + + def descr_gt(self, space, w_arr2): + "x.__gt__(y) <==> x>y" + return compare_arrays(space, self, w_arr2, space.gt) + + def descr_ge(self, space, w_arr2): + "x.__ge__(y) <==> x>=y" + return compare_arrays(space, self, w_arr2, space.ge) + @staticmethod def register(typeorder): typeorder[W_ArrayBase] = [] +arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') + +def compare_arrays(space, arr1, arr2, comp_func): + if (not isinstance(arr1, W_ArrayBase) or + not isinstance(arr2, W_ArrayBase)): + return space.w_NotImplemented + if comp_func == space.eq and arr1.len != arr2.len: + return space.w_False + if comp_func == space.ne and arr1.len != arr2.len: + return space.w_True + lgt = min(arr1.len, arr2.len) + for i in range(lgt): + arr_eq_driver.jit_merge_point(comp_func=comp_func) + w_elem1 = arr1.w_getitem(space, i) + w_elem2 = arr2.w_getitem(space, i) + res = space.is_true(comp_func(w_elem1, w_elem2)) + if comp_func == space.eq: + if not res: + return space.w_False + elif comp_func == space.ne: + if res: + return space.w_True + elif comp_func == space.lt or comp_func == space.gt: + if res: + return space.w_True + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_False + else: + if not res: + return space.w_False + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_True + # we have some leftovers + if comp_func == space.eq: + return space.w_True + elif comp_func == space.ne: + return space.w_False + if arr1.len == arr2.len: + if comp_func == space.lt or comp_func == space.gt: + return space.w_False + return space.w_True + if comp_func == space.lt or comp_func == space.le: + if arr1.len < arr2.len: + return space.w_False + return space.w_True + if arr1.len > arr2.len: + return space.w_False + return space.w_True + W_ArrayBase.typedef = StdTypeDef( 'array', __new__ = interp2app(w_array), __module__ = 'array', + + __len__ = interp2app(W_ArrayBase.descr_len), + __eq__ = interp2app(W_ArrayBase.descr_eq), + __ne__ = interp2app(W_ArrayBase.descr_ne), + __lt__ = interp2app(W_ArrayBase.descr_lt), + __le__ = interp2app(W_ArrayBase.descr_le), + __gt__ = interp2app(W_ArrayBase.descr_gt), + __ge__ = interp2app(W_ArrayBase.descr_ge), + itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), @@ -629,9 +714,6 @@ # Basic get/set/append/extend methods - def len__Array(space, self): - return space.wrap(self.len) - def getitem__Array_ANY(space, self, w_idx): idx, stop, step = space.decode_index(w_idx, self.len) assert step == 0 @@ -796,32 +878,6 @@ a.buffer[r * oldlen + i] = self.buffer[i] return a - # Compare methods - @specialize.arg(3) - def _cmp_impl(space, self, other, space_fn): - # XXX this is a giant slow hack - w_lst1 = self.descr_tolist(space) - w_lst2 = space.call_method(other, 'tolist') - return space_fn(w_lst1, w_lst2) - - def eq__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.eq) - - def ne__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ne) - - def lt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.lt) - - def le__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.le) - - def gt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.gt) - - def ge__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ge) - # Misc methods def buffer__Array(space, self): From noreply at buildbot.pypy.org Sun May 12 20:03:06 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 12 May 2013 20:03:06 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: implement something Message-ID: <20130512180306.C1C501C13CC@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r64016:07782daba0f3 Date: 2013-05-12 21:02 +0300 http://bitbucket.org/pypy/pypy/changeset/07782daba0f3/ Log: implement something diff --git a/pypy/module/micronumpy/interp_nditer.py b/pypy/module/micronumpy/interp_nditer.py --- a/pypy/module/micronumpy/interp_nditer.py +++ b/pypy/module/micronumpy/interp_nditer.py @@ -2,11 +2,30 @@ from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.error import OperationError +from pypy.module.micronumpy.interp_numarray import array #from pypy.module.micronumpy.iter import W_NDIter + +def handle_sequence_args(space, cls, w_seq, w_op_flags, w_op_types, w_op_axes): + ''' + Make sure that len(args) == 1 or len(w_seq) + and set attribs on cls appropriately + ''' + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + + class W_NDIter(W_Root): - def __init__(self, *args, **kwargs): + def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, + w_op_axes, w_itershape, w_buffersize, order): + self.order = order + if space.isinstance_w(w_seq, space.w_tuple) or space.isinstance_w(w_seq, space.w_list): + handle_sequence_args(space, self, w_seq, w_op_flags, w_op_dtypes, w_op_axes) + else: + self.seq =array(space, w_seq, copy=False) + # XXX handle args + self.iters = [self.seq.implementation.create_iter()] pass def descr_iter(self, space): @@ -25,8 +44,18 @@ 'not implemented yet')) def descr_next(self, space): - raise OperationError(space.w_NotImplementedError, space.wrap( - 'not implemented yet')) + for it in self.iters: + if not it.done(): + break + else: + raise OperationError(space.w_StopIteration, space.w_None) + res = [] + for it in self.iters: + res.append(space.wrap(it.getitem())) + it.next() + if len(res) <2: + return res[0] + return space.newtuple(res) def descr_iternext(self, space): raise OperationError(space.w_NotImplementedError, space.wrap( @@ -57,7 +86,7 @@ raise OperationError(space.w_NotImplementedError, space.wrap( 'not implemented yet')) - def descr_get_operands(self, space, w_indx): + def descr_get_operands(self, space): raise OperationError(space.w_NotImplementedError, space.wrap( 'not implemented yet')) @@ -128,7 +157,8 @@ w_itershape=WrappedDefault(None), w_buffersize=WrappedDefault(None)) def nditer(space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, w_itershape, w_buffersize, order='K'): - return W_NDIter() + return W_NDIter(space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, + w_itershape, w_buffersize, order) W_NDIter.typedef = TypeDef( 'nditer', From noreply at buildbot.pypy.org Sun May 12 20:33:57 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 20:33:57 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: Die die die Message-ID: <20130512183357.A63C01C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64017:cd165d9b9fbc Date: 2013-05-12 20:33 +0200 http://bitbucket.org/pypy/pypy/changeset/cd165d9b9fbc/ Log: Die die die 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 @@ -59,6 +59,55 @@ def descr_typecode(space, self): return space.wrap(self.typecode) +arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') + +def compare_arrays(space, arr1, arr2, comp_func): + if (not isinstance(arr1, W_ArrayBase) or + not isinstance(arr2, W_ArrayBase)): + return space.w_NotImplemented + if comp_func == space.eq and arr1.len != arr2.len: + return space.w_False + if comp_func == space.ne and arr1.len != arr2.len: + return space.w_True + lgt = min(arr1.len, arr2.len) + for i in range(lgt): + arr_eq_driver.jit_merge_point(comp_func=comp_func) + w_elem1 = arr1.w_getitem(space, i) + w_elem2 = arr2.w_getitem(space, i) + res = space.is_true(comp_func(w_elem1, w_elem2)) + if comp_func == space.eq: + if not res: + return space.w_False + elif comp_func == space.ne: + if res: + return space.w_True + elif comp_func == space.lt or comp_func == space.gt: + if res: + return space.w_True + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_False + else: + if not res: + return space.w_False + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_True + # we have some leftovers + if comp_func == space.eq: + return space.w_True + elif comp_func == space.ne: + return space.w_False + if arr1.len == arr2.len: + if comp_func == space.lt or comp_func == space.gt: + return space.w_False + return space.w_True + if comp_func == space.lt or comp_func == space.le: + if arr1.len < arr2.len: + return space.w_False + return space.w_True + if arr1.len > arr2.len: + return space.w_False + return space.w_True + class W_ArrayBase(W_Object): def __init__(self, space): @@ -332,59 +381,51 @@ "x.__ge__(y) <==> x>=y" return compare_arrays(space, self, w_arr2, space.ge) + # Basic get/set/append/extend methods + + def descr_getitem(self, space, w_idx): + "x.__getitem__(y) <==> x[y]" + if not space.isinstance_w(w_idx, space.w_slice): + idx, stop, step = space.decode_index(w_idx, self.len) + assert step == 0 + return self.w_getitem(space, idx) + else: + return self.getitem_slice(space, w_idx) + + def descr_getslice(self, space, w_i, w_j): + return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) + + + def descr_setitem(self, space, w_idx, w_item): + "x.__setitem__(i, y) <==> x[i]=y" + if space.isinstance_w(w_idx, space.w_slice): + self.setitem_slice(space, w_idx, w_item) + else: + self.setitem(space, w_idx, w_item) + + def descr_setslice(self, space, w_start, w_stop, w_item): + self.setitem_slice(space, + space.newslice(w_start, w_stop, space.w_None), + w_item) + + def descr_delitem(self, space, w_idx): + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + if step != 1: + # I don't care about efficiency of that so far + w_lst = self.descr_tolist(space) + space.delitem(w_lst, w_idx) + self.setlen(0) + self.fromsequence(w_lst) + return + return self.delitem(space, start, stop) + + def descr_delslice(self, space, w_start, w_stop): + self.descr_delitem(space, space.newslice(w_start, w_stop, space.w_None)) + @staticmethod def register(typeorder): typeorder[W_ArrayBase] = [] -arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') - -def compare_arrays(space, arr1, arr2, comp_func): - if (not isinstance(arr1, W_ArrayBase) or - not isinstance(arr2, W_ArrayBase)): - return space.w_NotImplemented - if comp_func == space.eq and arr1.len != arr2.len: - return space.w_False - if comp_func == space.ne and arr1.len != arr2.len: - return space.w_True - lgt = min(arr1.len, arr2.len) - for i in range(lgt): - arr_eq_driver.jit_merge_point(comp_func=comp_func) - w_elem1 = arr1.w_getitem(space, i) - w_elem2 = arr2.w_getitem(space, i) - res = space.is_true(comp_func(w_elem1, w_elem2)) - if comp_func == space.eq: - if not res: - return space.w_False - elif comp_func == space.ne: - if res: - return space.w_True - elif comp_func == space.lt or comp_func == space.gt: - if res: - return space.w_True - elif not space.is_true(space.eq(w_elem1, w_elem2)): - return space.w_False - else: - if not res: - return space.w_False - elif not space.is_true(space.eq(w_elem1, w_elem2)): - return space.w_True - # we have some leftovers - if comp_func == space.eq: - return space.w_True - elif comp_func == space.ne: - return space.w_False - if arr1.len == arr2.len: - if comp_func == space.lt or comp_func == space.gt: - return space.w_False - return space.w_True - if comp_func == space.lt or comp_func == space.le: - if arr1.len < arr2.len: - return space.w_False - return space.w_True - if arr1.len > arr2.len: - return space.w_False - return space.w_True - W_ArrayBase.typedef = StdTypeDef( 'array', __new__ = interp2app(w_array), @@ -398,6 +439,13 @@ __gt__ = interp2app(W_ArrayBase.descr_gt), __ge__ = interp2app(W_ArrayBase.descr_ge), + __getitem__ = interp2app(W_ArrayBase.descr_getitem), + __getslice__ = interp2app(W_ArrayBase.descr_getslice), + __setitem__ = interp2app(W_ArrayBase.descr_setitem), + __setslice__ = interp2app(W_ArrayBase.descr_setslice), + __delitem__ = interp2app(W_ArrayBase.descr_delitem), + __delslice__ = interp2app(W_ArrayBase.descr_delslice), + itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), @@ -712,99 +760,81 @@ i -= 1 self.buffer[i] = val - # Basic get/set/append/extend methods - - def getitem__Array_ANY(space, self, w_idx): - idx, stop, step = space.decode_index(w_idx, self.len) - assert step == 0 - return self.w_getitem(space, idx) - - def getitem__Array_Slice(space, self, w_slice): - start, stop, step, size = space.decode_index4(w_slice, self.len) - w_a = mytype.w_class(self.space) - w_a.setlen(size, overallocate=False) - assert step != 0 - j = 0 - for i in range(start, stop, step): - w_a.buffer[j] = self.buffer[i] - j += 1 - return w_a - - def getslice__Array_ANY_ANY(space, self, w_i, w_j): - return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) - - def setitem__Array_ANY_ANY(space, self, w_idx, w_item): - idx, stop, step = space.decode_index(w_idx, self.len) - if step != 0: - msg = 'can only assign array to array slice' - raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) - item = self.item_w(w_item) - self.buffer[idx] = item - - def setitem__Array_Slice_Array(space, self, w_idx, w_item): - start, stop, step, size = self.space.decode_index4(w_idx, self.len) - assert step != 0 - if w_item.len != size or self is w_item: - # XXX this is a giant slow hack - w_lst = self.descr_tolist(space) - w_item = space.call_method(w_item, 'tolist') - space.setitem(w_lst, w_idx, w_item) - self.setlen(0) - self.fromsequence(w_lst) - else: + def getitem_slice(self, space, w_idx): + start, stop, step, size = space.decode_index4(w_idx, self.len) + w_a = self.constructor(self.space) + w_a.setlen(size, overallocate=False) + assert step != 0 j = 0 for i in range(start, stop, step): - self.buffer[i] = w_item.buffer[j] + w_a.buffer[j] = self.buffer[i] j += 1 + return w_a - def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x): - space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x) + def setitem(self, space, w_idx, w_item): + idx, stop, step = space.decode_index(w_idx, self.len) + if step != 0: + msg = 'can only assign array to array slice' + raise OperationError(self.space.w_TypeError, + self.space.wrap(msg)) + item = self.item_w(w_item) + self.buffer[idx] = item - def delitem__Array_ANY(space, self, w_idx): - # XXX this is a giant slow hack - w_lst = self.descr_tolist(space) - space.delitem(w_lst, w_idx) - self.setlen(0) - self.fromsequence(w_lst) + def setitem_slice(self, space, w_idx, w_item): + if not isinstance(w_item, W_Array): + raise OperationError(space.w_TypeError, space.wrap( + "can only assign to a slice array")) + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + assert step != 0 + if w_item.len != size or self is w_item: + # XXX this is a giant slow hack + w_lst = self.descr_tolist(space) + w_item = space.call_method(w_item, 'tolist') + space.setitem(w_lst, w_idx, w_item) + self.setlen(0) + self.fromsequence(w_lst) + else: + j = 0 + for i in range(start, stop, step): + self.buffer[i] = w_item.buffer[j] + j += 1 - # We can't look into this function until ptradd works with things (in the - # JIT) other than rffi.CCHARP - @jit.dont_look_inside - def delslice__Array_ANY_ANY(space, self, w_i, w_j): - i = space.int_w(w_i) - if i < 0: - i += self.len - if i < 0: - i = 0 - j = space.int_w(w_j) - if j < 0: - j += self.len - if j < 0: - j = 0 - if j > self.len: - j = self.len - if i >= j: - return None - oldbuffer = self.buffer - self.buffer = lltype.malloc(mytype.arraytype, - max(self.len - (j - i), 0), flavor='raw', - add_memory_pressure=True) - if i: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, self.buffer), - rffi.cast(rffi.VOIDP, oldbuffer), - i * mytype.bytes - ) - if j < self.len: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), - rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), - (self.len - j) * mytype.bytes - ) - self.len -= j - i - self.allocated = self.len - if oldbuffer: - lltype.free(oldbuffer, flavor='raw') + # We can't look into this function until ptradd works with things (in the + # JIT) other than rffi.CCHARP + @jit.dont_look_inside + def delitem(self, space, i, j): + if i < 0: + i += self.len + if i < 0: + i = 0 + if j < 0: + j += self.len + if j < 0: + j = 0 + if j > self.len: + j = self.len + if i >= j: + return None + oldbuffer = self.buffer + self.buffer = lltype.malloc(mytype.arraytype, + max(self.len - (j - i), 0), flavor='raw', + add_memory_pressure=True) + if i: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, self.buffer), + rffi.cast(rffi.VOIDP, oldbuffer), + i * mytype.bytes + ) + if j < self.len: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), + rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), + (self.len - j) * mytype.bytes + ) + self.len -= j - i + self.allocated = self.len + if oldbuffer: + lltype.free(oldbuffer, flavor='raw') # Add and mul methods From noreply at buildbot.pypy.org Sun May 12 20:43:16 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 12 May 2013 20:43:16 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: completely kill multimethods from the array module Message-ID: <20130512184316.31E1D1C13CC@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64018:65b62c99bbfe Date: 2013-05-12 20:42 +0200 http://bitbucket.org/pypy/pypy/changeset/65b62c99bbfe/ Log: completely kill multimethods from the array module 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 @@ -6,13 +6,11 @@ from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object -from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.objspace.std.register_all import register_all from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.objectmodel import specialize, keepalive_until_here +from rpython.rlib.objectmodel import keepalive_until_here from rpython.rtyper.lltypesystem import lltype, rffi @@ -422,6 +420,45 @@ def descr_delslice(self, space, w_start, w_stop): self.descr_delitem(space, space.newslice(w_start, w_stop, space.w_None)) + def descr_add(self, space, w_other): + raise NotImplementedError + + def descr_inplace_add(self, space, w_other): + raise NotImplementedError + + def descr_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_inplace_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_radd(self, space, w_other): + return self.descr_add(space, w_other) + + def descr_rmul(self, space, w_repeat): + return self.descr_mul(space, w_repeat) + + # Misc methods + + def descr_buffer(self, space): + return space.wrap(ArrayBuffer(self)) + + def descr_repr(self, space): + if self.len == 0: + return space.wrap("array('%s')" % self.typecode) + elif self.typecode == "c": + r = space.repr(self.descr_tostring(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + elif self.typecode == "u": + r = space.repr(self.descr_tounicode(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + else: + r = space.repr(self.descr_tolist(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + @staticmethod def register(typeorder): typeorder[W_ArrayBase] = [] @@ -446,6 +483,16 @@ __delitem__ = interp2app(W_ArrayBase.descr_delitem), __delslice__ = interp2app(W_ArrayBase.descr_delslice), + __add__ = interpindirect2app(W_ArrayBase.descr_add), + __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add), + __mul__ = interpindirect2app(W_ArrayBase.descr_mul), + __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul), + __radd__ = interp2app(W_ArrayBase.descr_radd), + __rmul__ = interp2app(W_ArrayBase.descr_rmul), + + __buffer__ = interp2app(W_ArrayBase.descr_buffer), + __repr__ = interp2app(W_ArrayBase.descr_repr), + itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), @@ -836,40 +883,41 @@ if oldbuffer: lltype.free(oldbuffer, flavor='raw') - # Add and mul methods + # Add and mul methods - def add__Array_Array(space, self, other): - a = mytype.w_class(space) - a.setlen(self.len + other.len, overallocate=False) - for i in range(self.len): - a.buffer[i] = self.buffer[i] - for i in range(other.len): - a.buffer[i + self.len] = other.buffer[i] - return a + def descr_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + a = mytype.w_class(space) + a.setlen(self.len + w_other.len, overallocate=False) + for i in range(self.len): + a.buffer[i] = self.buffer[i] + for i in range(w_other.len): + a.buffer[i + self.len] = w_other.buffer[i] + return a - def inplace_add__Array_Array(space, self, other): - oldlen = self.len - otherlen = other.len - self.setlen(oldlen + otherlen) - for i in range(otherlen): - self.buffer[oldlen + i] = other.buffer[i] - return self + def descr_inplace_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + oldlen = self.len + otherlen = w_other.len + self.setlen(oldlen + otherlen) + for i in range(otherlen): + self.buffer[oldlen + i] = w_other.buffer[i] + return self - def mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, False) + def descr_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, False) - def mul__ANY_Array(space, w_repeat, self): - return _mul_helper(space, self, w_repeat, False) - - def inplace_mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, True) + def descr_inplace_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, True) def _mul_helper(space, self, w_repeat, is_inplace): try: repeat = space.getindex_w(w_repeat, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - raise FailedToImplement + return space.w_NotImplemented raise repeat = max(repeat, 0) try: @@ -908,47 +956,11 @@ a.buffer[r * oldlen + i] = self.buffer[i] return a - # Misc methods - - def buffer__Array(space, self): - return space.wrap(ArrayBuffer(self)) - - def repr__Array(space, self): - if self.len == 0: - return space.wrap("array('%s')" % self.typecode) - elif self.typecode == "c": - r = space.repr(self.descr_tostring(space)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - elif self.typecode == "u": - r = space.repr(self.descr_tounicode(space)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - else: - r = space.repr(self.descr_tolist(space)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - mytype.w_class = W_Array W_Array.constructor = W_Array - - # Annotator seems to mess up if the names are not unique name = 'ArrayType' + mytype.typecode W_Array.__name__ = 'W_' + name - import re - for n, f in locals().items(): - new, n = re.subn('_Array_', '_%s_' % name, n) - if n > 0: - f.__name__ = new - - from pypy.objspace.std.sliceobject import W_SliceObject - from pypy.objspace.std.listobject import W_ListObject - from pypy.objspace.std.unicodeobject import W_UnicodeObject - register_all(locals(), globals()) - for mytype in types.values(): make_array(mytype) del mytype - -register_all(locals(), globals()) From noreply at buildbot.pypy.org Sun May 12 22:10:18 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 12 May 2013 22:10:18 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: handle 'order': one of many arguments. This is going to get ugly fast Message-ID: <20130512201018.5AD2C1C009D@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r64019:e252c10cbea4 Date: 2013-05-12 23:09 +0300 http://bitbucket.org/pypy/pypy/changeset/e252c10cbea4/ Log: handle 'order': one of many arguments. This is going to get ugly fast diff --git a/pypy/module/micronumpy/interp_nditer.py b/pypy/module/micronumpy/interp_nditer.py --- a/pypy/module/micronumpy/interp_nditer.py +++ b/pypy/module/micronumpy/interp_nditer.py @@ -2,8 +2,10 @@ from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.interp_numarray import array -#from pypy.module.micronumpy.iter import W_NDIter +from pypy.module.micronumpy.base import convert_to_array +from pypy.module.micronumpy.strides import calculate_broadcast_strides +from pypy.module.micronumpy.iter import MultiDimViewIterator +from pypy.module.micronumpy import support def handle_sequence_args(space, cls, w_seq, w_op_flags, w_op_types, w_op_axes): @@ -23,10 +25,30 @@ if space.isinstance_w(w_seq, space.w_tuple) or space.isinstance_w(w_seq, space.w_list): handle_sequence_args(space, self, w_seq, w_op_flags, w_op_dtypes, w_op_axes) else: - self.seq =array(space, w_seq, copy=False) - # XXX handle args - self.iters = [self.seq.implementation.create_iter()] - pass + self.seq =[convert_to_array(space, w_seq)] + if order == 'K' or (order == 'C' and self.seq[0].get_order() == 'C'): + backward = False + elif order =='F' and self.seq[0].get_order() == 'C': + backward = True + else: + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + imp = self.seq[0].implementation + if (imp.strides[0] < imp.strides[-1] and not backward) or \ + (imp.strides[0] > imp.strides[-1] and backward): + # flip the strides. Is this always true for multidimension? + strides = [s for s in imp.strides[::-1]] + backstrides = [s for s in imp.backstrides[::-1]] + shape = [s for s in imp.shape[::-1]] + else: + strides = imp.strides + backstrides = imp.backstrides + shape = imp.shape + shape1d = [support.product(imp.shape),] + r = calculate_broadcast_strides(strides, backstrides, shape, + shape1d, backward) + self.iters = [MultiDimViewIterator(imp, imp.dtype, imp.start, r[0], r[1], + shape)] def descr_iter(self, space): return space.wrap(self) From noreply at buildbot.pypy.org Sun May 12 22:18:52 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sun, 12 May 2013 22:18:52 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: Remove unnecessary guard Message-ID: <20130512201852.58D111C009D@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r64020:945b1a989902 Date: 2013-05-12 15:17 +0100 http://bitbucket.org/pypy/pypy/changeset/945b1a989902/ Log: Remove unnecessary guard The special case in space.setitem was never actually executed, since frame.w_globals is never modified directly and other ways of accessing globals() don't return the frame.w_globals object. diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py --- a/rpython/flowspace/objspace.py +++ b/rpython/flowspace/objspace.py @@ -305,14 +305,6 @@ frame.handle_implicit_exceptions([StopIteration, RuntimeError]) return w_item - def setitem(self, w_obj, w_key, w_val): - # protect us from globals write access - if w_obj is self.frame.w_globals: - raise FlowingError(self.frame, - "Attempting to modify global variable %r." % (w_key)) - return self.frame.do_operation_with_implicit_exceptions('setitem', - w_obj, w_key, w_val) - def setitem_str(self, w_obj, key, w_value): return self.setitem(w_obj, self.wrap(key), w_value) From noreply at buildbot.pypy.org Sun May 12 22:18:53 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Sun, 12 May 2013 22:18:53 +0200 (CEST) Subject: [pypy-commit] pypy Opcode-class: kill dead code Message-ID: <20130512201853.A59C31C009D@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Opcode-class Changeset: r64021:890be79024a4 Date: 2013-05-05 19:18 +0100 http://bitbucket.org/pypy/pypy/changeset/890be79024a4/ Log: kill dead code diff --git a/rpython/flowspace/objspace.py b/rpython/flowspace/objspace.py --- a/rpython/flowspace/objspace.py +++ b/rpython/flowspace/objspace.py @@ -148,15 +148,6 @@ return val return self.unwrap(w_obj) - def uint_w(self, w_obj): - if isinstance(w_obj, Constant): - val = w_obj.value - if type(val) is not rarithmetic.r_uint: - raise TypeError("expected unsigned: " + repr(w_obj)) - return val - return self.unwrap(w_obj) - - def str_w(self, w_obj): if isinstance(w_obj, Constant): val = w_obj.value @@ -165,14 +156,6 @@ return val return self.unwrap(w_obj) - def float_w(self, w_obj): - if isinstance(w_obj, Constant): - val = w_obj.value - if type(val) is not float: - raise TypeError("expected float: " + repr(w_obj)) - return val - return self.unwrap(w_obj) - def unwrap(self, w_obj): if isinstance(w_obj, Variable): raise UnwrapException @@ -305,8 +288,6 @@ frame.handle_implicit_exceptions([StopIteration, RuntimeError]) return w_item - def setitem_str(self, w_obj, key, w_value): - return self.setitem(w_obj, self.wrap(key), w_value) def getattr(self, w_obj, w_name): # handling special things like sys From noreply at buildbot.pypy.org Mon May 13 01:19:48 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 01:19:48 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: add test_ztranslation here (that passes and translation fails, but well) Message-ID: <20130512231948.5B54C1C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64022:9c0214035486 Date: 2013-05-13 01:19 +0200 http://bitbucket.org/pypy/pypy/changeset/9c0214035486/ Log: add test_ztranslation here (that passes and translation fails, but well) diff --git a/pypy/module/array/test/test_ztranslation.py b/pypy/module/array/test/test_ztranslation.py new file mode 100644 --- /dev/null +++ b/pypy/module/array/test/test_ztranslation.py @@ -0,0 +1,6 @@ + +from pypy.objspace.fake.checkmodule import checkmodule + +def test_checkmodule(): + checkmodule('struct') + From noreply at buildbot.pypy.org Mon May 13 01:28:16 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 01:28:16 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: shuffle stuff around and remove the array registration from stdobjspace Message-ID: <20130512232816.470BE1C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64023:29b186204c71 Date: 2013-05-13 01:27 +0200 http://bitbucket.org/pypy/pypy/changeset/29b186204c71/ Log: shuffle stuff around and remove the array registration from stdobjspace 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 @@ -3,10 +3,9 @@ from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app -from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef from pypy.module._file.interp_file import W_File from pypy.objspace.std.model import W_Object -from pypy.objspace.std.stdtypedef import StdTypeDef from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen from rpython.rlib.unroll import unrolling_iterable @@ -108,6 +107,8 @@ class W_ArrayBase(W_Object): + _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer + def __init__(self, space): self.space = space self.len = 0 @@ -463,7 +464,7 @@ def register(typeorder): typeorder[W_ArrayBase] = [] -W_ArrayBase.typedef = StdTypeDef( +W_ArrayBase.typedef = TypeDef( 'array', __new__ = interp2app(w_array), __module__ = 'array', @@ -519,7 +520,6 @@ __reduce__ = interp2app(W_ArrayBase.descr_reduce), byteswap = interp2app(W_ArrayBase.descr_byteswap), ) -W_ArrayBase.typedef.registermethods(globals()) class TypeCode(object): @@ -595,9 +595,7 @@ itemsize = mytype.bytes typecode = mytype.typecode - @staticmethod - def register(typeorder): - typeorder[W_Array] = [(W_ArrayBase, None)] + _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer') def __init__(self, space): W_ArrayBase.__init__(self, space) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -80,8 +80,6 @@ import pypy.objspace.std.default # register a few catch-all multimethods import pypy.objspace.std.marshal_impl # install marshal multimethods - if config.objspace.usemodules.array: - import pypy.module.array # the set of implementation types self.typeorder = { From noreply at buildbot.pypy.org Mon May 13 02:00:59 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 13 May 2013 02:00:59 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130513000059.3F4EC1C13CC@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64024:c4d6a29c134f Date: 2013-05-12 17:00 -0700 http://bitbucket.org/pypy/pypy/changeset/c4d6a29c134f/ Log: merge default 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 @@ -119,7 +119,7 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: cflags = os.environ["CFLAGS"].split() diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -821,7 +821,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -830,11 +829,13 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = {} + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -136,18 +136,39 @@ def test_interpindirect2app(self): space = self.space + class BaseA(W_Root): def method(self, space, x): + "This is a method" + pass + + def method_with_default(self, space, x=5): + pass + + @gateway.unwrap_spec(x=int) + def method_with_unwrap_spec(self, space, x): pass class A(BaseA): def method(self, space, x): return space.wrap(x + 2) + def method_with_default(self, space, x): + return space.wrap(x + 2) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 2) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) + def method_with_default(self, space, x): + return space.wrap(x + 1) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 1) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -164,6 +185,23 @@ assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2 assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1 + doc = space.str_w(space.getattr(w_c, space.wrap('__doc__'))) + assert doc == "This is a method" + + meth_with_default = gateway.interpindirect2app( + BaseA.method_with_default, {'x': int}) + w_d = space.wrap(meth_with_default) + + assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2 + assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1 + assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2 + assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1 + + meth_with_unwrap_spec = gateway.interpindirect2app( + BaseA.method_with_unwrap_spec) + w_e = space.wrap(meth_with_unwrap_spec) + assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2 + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -553,10 +553,6 @@ def wrapper(*args): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference - # we hope that malloc removal removes the newtuple() that is - # inserted exactly here by the varargs specializer - rffi.stackcounter.stacks_counter += 1 - llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py retval = fatal_value boxed_args = () try: @@ -625,7 +621,6 @@ else: print str(e) pypy_debug_catch_fatal_exception() - rffi.stackcounter.stacks_counter -= 1 return retval callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -58,7 +58,8 @@ w_str = "str" w_unicode = "unicode" w_complex = "complex" - + w_dict = "dict" + def __init__(self): """NOT_RPYTHON""" self.fromcache = InternalSpaceCache(self).getorbuild @@ -115,9 +116,13 @@ def newcomplex(self, r, i): return ComplexObject(r, i) - def listview(self, obj): + def listview(self, obj, number=-1): assert isinstance(obj, ListObject) + if number != -1: + assert number == 2 + return [obj.items[0], obj.items[1]] return obj.items + fixedview = listview def float(self, w_obj): @@ -480,7 +485,7 @@ w_res = neg.call(interp.space, [arr]) elif self.name == "cos": cos = interp_ufuncs.get(interp.space).cos - w_res = cos.call(interp.space, [arr]) + w_res = cos.call(interp.space, [arr]) elif self.name == "flat": w_res = arr.descr_get_flatiter(interp.space) elif self.name == "argsort": diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -1005,6 +1005,19 @@ """ self.optimize_loop(ops, expected) + def test_virtual_array_of_struct_len(self): + ops = """ + [] + p0 = new_array(2, descr=complexarraydescr) + i0 = arraylen_gc(p0) + finish(i0) + """ + expected = """ + [] + finish(2) + """ + self.optimize_loop(ops, expected) + def test_nonvirtual_1(self): ops = """ [i] diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -332,6 +332,9 @@ self.arraydescr = arraydescr self._items = [{} for _ in xrange(size)] + def getlength(self): + return len(self._items) + def getinteriorfield(self, index, ofs, default): return self._items[index].get(ofs, default) diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -1,5 +1,11 @@ secondary_entrypoints = {} +import py +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.lltypesystem.lloperation import llop +from rpython.rlib.objectmodel import we_are_translated + +pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) def entrypoint(key, argtypes, c_name=None, relax=False): """ Note: entrypoint should call llop.gc_stack_bottom on it's own. @@ -10,14 +16,41 @@ from rpython.translator.tool.cbuild import ExternalCompilationInfo def deco(func): - secondary_entrypoints.setdefault(key, []).append((func, argtypes)) + source = py.code.Source(""" + def wrapper(%(args)s): + # the tuple has to be killed, but it's fine because this is + # called from C + rffi.stackcounter.stacks_counter += 1 + llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py + # this should not raise + try: + res = func(%(args)s) + except Exception, e: + if not we_are_translated(): + import traceback + traceback.print_exc() + else: + print str(e) + pypy_debug_catch_fatal_exception() + llop.debug_fatalerror(lltype.Void, "error in c callback") + assert 0 # dead code + rffi.stackcounter.stacks_counter -= 1 + return res + """ % {'args': ', '.join(['arg%d' % i for i in range(len(argtypes))])}) + d = {'rffi': rffi, 'lltype': lltype, + 'pypy_debug_catch_fatal_exception': pypy_debug_catch_fatal_exception, + 'llop': llop, 'func': func, 'we_are_translated': we_are_translated} + exec source.compile() in d + wrapper = d['wrapper'] + secondary_entrypoints.setdefault(key, []).append((wrapper, argtypes)) + wrapper.func_name = func.func_name if c_name is not None: - func.c_name = c_name + wrapper.c_name = c_name if relax: - func.relax_sig_check = True - func._compilation_info = ExternalCompilationInfo( + wrapper.relax_sig_check = True + wrapper._compilation_info = ExternalCompilationInfo( export_symbols=[c_name or func.func_name]) - return func + return wrapper return deco # the point of dance below is so the call to rpython_startup_code actually @@ -25,8 +58,6 @@ # This thing is imported by any target which has any API, so it'll get # registered -from rpython.rtyper.lltypesystem import lltype, rffi - RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void) @entrypoint('main', [], c_name='rpython_startup_code') diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -1314,7 +1314,8 @@ assert t1.sign >= 0 assert 2*shift + t1.numdigits() <= ret.numdigits() - ret._digits[2*shift : 2*shift + t1.numdigits()] = t1._digits + for i in range(t1.numdigits()): + ret._digits[2*shift + i] = t1._digits[i] # Zero-out the digits higher than the ah*bh copy. */ ## ignored, assuming that we initialize to zero @@ -1327,7 +1328,8 @@ t2 = al.mul(bl) assert t2.sign >= 0 assert t2.numdigits() <= 2*shift # no overlap with high digits - ret._digits[:t2.numdigits()] = t2._digits + for i in range(t2.numdigits()): + ret._digits[i] = t2._digits[i] # Zero out remaining digits. ## ignored, assuming that we initialize to zero diff --git a/rpython/rtyper/lltypesystem/lltype.py b/rpython/rtyper/lltypesystem/lltype.py --- a/rpython/rtyper/lltypesystem/lltype.py +++ b/rpython/rtyper/lltypesystem/lltype.py @@ -317,7 +317,7 @@ def _names_without_voids(self): names_without_voids = [name for name in self._names if self._flds[name] is not Void] return names_without_voids - + def _str_fields_without_voids(self): return ', '.join(['%s: %s' % (name, self._flds[name]) for name in self._names_without_voids(False)]) @@ -425,7 +425,7 @@ _gckind = 'raw' __name__ = 'array' _anonym_struct = False - + def __init__(self, *fields, **kwds): if len(fields) == 1 and isinstance(fields[0], LowLevelType): self.OF = fields[0] @@ -669,7 +669,7 @@ def normalized(self): return build_number(None, normalizedinttype(self._type)) - + _numbertypes = {int: Number("Signed", int, intmask)} _numbertypes[r_int] = _numbertypes[int] @@ -766,7 +766,7 @@ adtmeths=TO._adtmeths) else: R = GcStruct("Interior", ('ptr', self), ('index', Signed), - hints={'interior_ptr_type':True}) + hints={'interior_ptr_type':True}) return R class InteriorPtr(LowLevelType): @@ -911,7 +911,7 @@ return dwn OUTSIDE = getattr(OUTSIDE, first) return -1 - + def castable(PTRTYPE, CURTYPE): if CURTYPE.TO._gckind != PTRTYPE.TO._gckind: raise TypeError("cast_pointer() cannot change the gc status: %s to %s" @@ -1120,7 +1120,7 @@ # _setobj, _getobj and _obj0 are really _internal_ implementations details of _ptr, # use _obj if necessary instead ! - def _setobj(self, pointing_to, solid=False): + def _setobj(self, pointing_to, solid=False): if pointing_to is None: obj0 = None elif (solid or self._T._gckind != 'raw' or @@ -1131,7 +1131,7 @@ obj0 = weakref.ref(pointing_to) self._set_solid(solid) self._set_obj0(obj0) - + def _getobj(self, check=True): obj = self._obj0 if obj is not None: @@ -1307,7 +1307,7 @@ return result class _ptr(_abstract_ptr): - __slots__ = ('_TYPE', + __slots__ = ('_TYPE', '_weak', '_solid', '_obj0', '__weakref__') @@ -1462,9 +1462,9 @@ assert T._gckind == 'raw' val = _interior_ptr(T, self._parent, self._offsets + [offset]) return val - - - + + + assert not '__dict__' in dir(_interior_ptr) class _container(object): @@ -1581,7 +1581,7 @@ __slots__ = flds cache[tag] = _struct1 return _struct1 - + #for pickling support: def _get_empty_instance_of_struct_variety(flds): cls = _struct_variety(flds) @@ -1644,7 +1644,7 @@ return r # for FixedSizeArray kind of structs: - + def getlength(self): assert isinstance(self._TYPE, FixedSizeArray) return self._TYPE.length @@ -1891,6 +1891,8 @@ attrs.setdefault('_name', '?') attrs.setdefault('_callable', None) self.__dict__.update(attrs) + if '_callable' in attrs and hasattr(attrs['_callable'], '_compilation_info'): + self.__dict__['compilation_info'] = attrs['_callable']._compilation_info def __repr__(self): return '<%s>' % (self,) @@ -1959,7 +1961,7 @@ # if we are an opaque containing a normal Struct/GcStruct, # unwrap it if hasattr(self, 'container'): - # an integer, cast to a ptr, cast to an opaque + # an integer, cast to a ptr, cast to an opaque if type(self.container) is int: return self.container if getattr(self.container, '_carry_around_for_tests', False): @@ -2082,7 +2084,7 @@ if not isinstance(GCSTRUCT, RttiStruct): raise TypeError, "expected a RttiStruct: %s" % GCSTRUCT if GCSTRUCT._runtime_type_info is None: - raise ValueError, ("no attached runtime type info for GcStruct %s" % + raise ValueError, ("no attached runtime type info for GcStruct %s" % GCSTRUCT._name) return _ptr(Ptr(RuntimeTypeInfo), GCSTRUCT._runtime_type_info) diff --git a/rpython/rtyper/lltypesystem/rffi.py b/rpython/rtyper/lltypesystem/rffi.py --- a/rpython/rtyper/lltypesystem/rffi.py +++ b/rpython/rtyper/lltypesystem/rffi.py @@ -329,8 +329,9 @@ class StackCounter: def _cleanup_(self): - self.stacks_counter = 1 # number of "stack pieces": callbacks + self.stacks_counter = 0 # number of "stack pieces": callbacks # and threads increase it by one + stackcounter = StackCounter() stackcounter._cleanup_() diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -427,7 +427,10 @@ if sys.platform == 'win32': mk.definition('DEBUGFLAGS', '/MD /Zi') else: - mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') + if self.config.translation.shared: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g -fPIC') + else: + mk.definition('DEBUGFLAGS', '-O2 -fomit-frame-pointer -g') if self.config.translation.shared: mk.definition('PYPY_MAIN_FUNCTION', "pypy_main_startup") diff --git a/rpython/translator/c/node.py b/rpython/translator/c/node.py --- a/rpython/translator/c/node.py +++ b/rpython/translator/c/node.py @@ -492,7 +492,7 @@ class ContainerNode(Node): if USESLOTS: # keep the number of slots down! - __slots__ = """db obj + __slots__ = """db obj typename implementationtypename name _funccodegen_owner diff --git a/rpython/translator/c/src/entrypoint.c b/rpython/translator/c/src/entrypoint.c --- a/rpython/translator/c/src/entrypoint.c +++ b/rpython/translator/c/src/entrypoint.c @@ -20,12 +20,20 @@ int pypy_main_function(int argc, char *argv[]) __attribute__((__noinline__)); #endif +# ifdef PYPY_USE_ASMGCC +# include "structdef.h" +# include "forwarddecl.h" +# endif + int pypy_main_function(int argc, char *argv[]) { char *errmsg; int i, exitcode; RPyListOfString *list; +#ifdef PYPY_USE_ASMGCC + pypy_g_rpython_rtyper_lltypesystem_rffi_StackCounter.sc_inst_stacks_counter++; +#endif pypy_asm_stack_bottom(); #ifdef PYPY_X86_CHECK_SSE2_DEFINED pypy_x86_check_sse2(); 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 @@ -1,10 +1,13 @@ import py import sys, os, re +from rpython.config.translationoption import get_combined_translation_config 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.entrypoint import entrypoint, secondary_entrypoints +from rpython.rtyper.lltypesystem import lltype from rpython.translator.translator import TranslationContext from rpython.translator.backendopt import all from rpython.translator.c.genc import CStandaloneBuilder, ExternalCompilationInfo @@ -18,9 +21,16 @@ config = None def compile(self, entry_point, debug=True, shared=False, - stackcheck=False): + stackcheck=False, entrypoints=None): t = TranslationContext(self.config) - t.buildannotator().build_types(entry_point, [s_list_of_strings]) + ann = t.buildannotator() + ann.build_types(entry_point, [s_list_of_strings]) + if entrypoints is not None: + anns = {} + for func, annotation in secondary_entrypoints['test']: + anns[func] = annotation + for item in entrypoints: + ann.build_types(item, anns[item]) t.buildrtyper().specialize() if stackcheck: @@ -29,7 +39,11 @@ t.config.translation.shared = shared - cbuilder = CStandaloneBuilder(t, entry_point, t.config) + if entrypoints is not None: + kwds = {'secondary_entrypoints': [(i, None) for i in entrypoints]} + else: + kwds = {} + cbuilder = CStandaloneBuilder(t, entry_point, t.config, **kwds) if debug: cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES) else: @@ -89,7 +103,7 @@ llop.instrument_count(lltype.Void, 'test', 1) llop.instrument_count(lltype.Void, 'test', 1) llop.instrument_count(lltype.Void, 'test', 2) - llop.instrument_count(lltype.Void, 'test', 1) + llop.instrument_count(lltype.Void, 'test', 1) return 0 t = TranslationContext(self.config) t.config.translation.instrument = True @@ -277,7 +291,7 @@ def test_debug_print_start_stop(self): from rpython.rtyper.lltypesystem import rffi - + def entry_point(argv): x = "got:" debug_start ("mycat") @@ -409,7 +423,6 @@ assert 'bok' in data # # finally, check compiling with logging disabled - from rpython.config.translationoption import get_combined_translation_config config = get_combined_translation_config(translating=True) config.translation.log = False self.config = config @@ -823,7 +836,6 @@ py.test.skip("TestMaemo: tests skipped for now") from rpython.translator.platform.maemo import check_scratchbox check_scratchbox() - from rpython.config.translationoption import get_combined_translation_config config = get_combined_translation_config(translating=True) config.translation.platform = 'maemo' cls.config = config @@ -1164,3 +1176,26 @@ and result.count('c') == result.count('p') == 5 and result.count('a') == 1 and result.count('d') == 6) + + +class TestShared(StandaloneTests): + + def test_entrypoint(self): + import ctypes + + config = get_combined_translation_config(translating=True) + self.config = config + + @entrypoint('test', [lltype.Signed], relax=True, c_name='foo') + def f(a): + return a + 3 + + def entry_point(argv): + return 0 + + t, cbuilder = self.compile(entry_point, shared=True, + entrypoints=[f]) + libname = cbuilder.executable_name.join('..', 'lib' + + cbuilder.modulename + '.so') + lib = ctypes.CDLL(str(libname)) + assert lib.foo(13) == 16 From noreply at buildbot.pypy.org Mon May 13 02:05:37 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 13 May 2013 02:05:37 +0200 (CEST) Subject: [pypy-commit] pypy py3k: apply b8d3cdad4da4 and 9ffefaf25ca3 from default Message-ID: <20130513000537.0AF541C10E6@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64025:12bca02bc4d8 Date: 2013-05-12 17:04 -0700 http://bitbucket.org/pypy/pypy/changeset/12bca02bc4d8/ Log: apply b8d3cdad4da4 and 9ffefaf25ca3 from default diff --git a/lib-python/3/distutils/sysconfig_pypy.py b/lib-python/3/distutils/sysconfig_pypy.py --- a/lib-python/3/distutils/sysconfig_pypy.py +++ b/lib-python/3/distutils/sysconfig_pypy.py @@ -118,13 +118,13 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: - cflags = os.environ["CFLAGS"] - compiler.compiler.append(cflags) - compiler.compiler_so.append(cflags) - compiler.linker_so.append(cflags) + cflags = os.environ["CFLAGS"].split() + compiler.compiler.extend(cflags) + compiler.compiler_so.extend(cflags) + compiler.linker_so.extend(cflags) from .sysconfig_cpython import ( From noreply at buildbot.pypy.org Mon May 13 09:15:39 2013 From: noreply at buildbot.pypy.org (stepahn) Date: Mon, 13 May 2013 09:15:39 +0200 (CEST) Subject: [pypy-commit] lang-js default: cleaned up comparsion code Message-ID: <20130513071539.890351C026D@cobra.cs.uni-duesseldorf.de> Author: Stephan Branch: Changeset: r377:fb52d8a52d9e Date: 2013-05-13 09:11 +0200 http://bitbucket.org/pypy/lang-js/changeset/fb52d8a52d9e/ Log: cleaned up comparsion code diff --git a/js/baseop.py b/js/baseop.py --- a/js/baseop.py +++ b/js/baseop.py @@ -3,10 +3,12 @@ """ from js.jsobj import W_String, W_IntNumber, W_FloatNumber -from js.object_space import _w, isint +from js.object_space import _w, isint, isstr, isfloat from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rfloat import isnan, isinf +from rpython.rlib.objectmodel import specialize + from js.builtins.number import w_NAN, w_POSITIVE_INFINITY, w_NEGATIVE_INFINITY import math @@ -141,50 +143,56 @@ return W_FloatNumber(val) -def compare(ctx, x, y): + at specialize.argtype(0, 1) +def _compare_gt(x, y): + return x > y + + + at specialize.argtype(0, 1) +def _compare_ge(x, y): + return x >= y + + +def _base_compare(x, y, _compare): if isint(x) and isint(y): - return x.ToInteger() > y.ToInteger() - if isinstance(x, W_FloatNumber) and isinstance(y, W_FloatNumber): - if isnan(x.ToNumber()) or isnan(y.ToNumber()): - return -1 - return x.ToNumber() > y.ToNumber() - s1 = x.ToPrimitive('Number') - s2 = y.ToPrimitive('Number') - if not (isinstance(s1, W_String) and isinstance(s2, W_String)): - s4 = s1.ToNumber() - s5 = s2.ToNumber() - if isnan(s4) or isnan(s5): - return False - return s4 > s5 + return _compare(x.ToInteger(), y.ToInteger()) + + if isfloat(x) and isfloat(y): + n1 = x.ToNumber() + n2 = x.ToNumber() + return _compare(n1, n2) + + p1 = x.ToPrimitive('Number') + p2 = y.ToPrimitive('Number') + + if not (isstr(p1) and isstr(p2)): + n1 = p1.ToNumber() + n2 = p2.ToNumber() + return _compare(n1, n2) else: - s4 = s1.to_string() - s5 = s2.to_string() - return s4 > s5 + s1 = p1.to_string() + s2 = p2.to_string() + return _compare(s1, s2) -def compare_e(ctx, x, y): - if isint(x) and isint(y): - return x.ToInteger() >= y.ToInteger() - if isinstance(x, W_FloatNumber) and isinstance(y, W_FloatNumber): - if isnan(x.ToNumber()) or isnan(y.ToNumber()): - return -1 - return x.ToNumber() >= y.ToNumber() - s1 = x.ToPrimitive('Number') - s2 = y.ToPrimitive('Number') - if not (isinstance(s1, W_String) and isinstance(s2, W_String)): - s4 = s1.ToNumber() - s5 = s2.ToNumber() - if isnan(s4) or isnan(s5): - return False - return s4 >= s5 - else: - s4 = s1.to_string() - s5 = s2.to_string() - return s4 >= s5 +def compare_gt(x, y): + return _base_compare(x, y, _compare_gt) + + +def compare_ge(x, y): + return _base_compare(x, y, _compare_ge) + + +def compare_lt(x, y): + return _base_compare(y, x, _compare_gt) + + +def compare_le(x, y): + return _base_compare(y, x, _compare_ge) # 11.9.3 -def AbstractEC(ctx, x, y): +def AbstractEC(x, y): """ Implements the Abstract Equality Comparison x == y trying to be fully to the spec @@ -220,19 +228,19 @@ (type1 == "null" and type2 == "undefined"): return True if type1 == "number" and type2 == "string": - return AbstractEC(ctx, x, W_FloatNumber(y.ToNumber())) + return AbstractEC(x, W_FloatNumber(y.ToNumber())) if type1 == "string" and type2 == "number": - return AbstractEC(ctx, W_FloatNumber(x.ToNumber()), y) + return AbstractEC(W_FloatNumber(x.ToNumber()), y) if type1 == "boolean": - return AbstractEC(ctx, W_FloatNumber(x.ToNumber()), y) + return AbstractEC(W_FloatNumber(x.ToNumber()), y) if type2 == "boolean": - return AbstractEC(ctx, x, W_FloatNumber(y.ToNumber())) + return AbstractEC(x, W_FloatNumber(y.ToNumber())) if (type1 == "string" or type1 == "number") and \ type2 == "object": - return AbstractEC(ctx, x, y.ToPrimitive()) + return AbstractEC(x, y.ToPrimitive()) if (type2 == "string" or type2 == "number") and \ type1 == "object": - return AbstractEC(ctx, x.ToPrimitive(), y) + return AbstractEC(x.ToPrimitive(), y) return False objtype = x.GetValue().type() diff --git a/js/object_space.py b/js/object_space.py --- a/js/object_space.py +++ b/js/object_space.py @@ -7,6 +7,16 @@ return isinstance(w, W_IntNumber) +def isstr(w): + from js.jsobj import W_String + return isinstance(w, W_String) + + +def isfloat(w): + from js.jsobj import W_FloatNumber + return isinstance(w, W_FloatNumber) + + @enforceargs(int) def newint(i): from js.jsobj import W_IntNumber @@ -79,7 +89,7 @@ @enforceargs(bool) def newbool(val): - if val is True: + if val: return w_True return w_False diff --git a/js/opcodes.py b/js/opcodes.py --- a/js/opcodes.py +++ b/js/opcodes.py @@ -3,8 +3,7 @@ from js.object_space import _w, isint from js.exception import JsTypeError -from js.baseop import plus, sub, compare, AbstractEC, StrictEC,\ - compare_e, increment, decrement, mult, division, uminus, mod +from js.baseop import plus, sub, AbstractEC, StrictEC, increment, decrement, mult, division, uminus, mod from js.jsobj import put_property @@ -35,12 +34,10 @@ from js.object_space import newbool s4 = ctx.stack_pop() s2 = ctx.stack_pop() - res = self.decision(ctx, s2, s4) - # XXX mimik behaviour of old newbool - res_true = res is True - ctx.stack_append(newbool(res_true)) + res = self.decision(s2, s4) + ctx.stack_append(newbool(res)) - def decision(self, ctx, op1, op2): + def decision(self, op1, op2): raise NotImplementedError @@ -369,16 +366,17 @@ rnum = rval.ToUInt32() lnum = lval.ToUInt32() - from rpython.rlib.rarithmetic import ovfcheck_float_to_int + #from rpython.rlib.rarithmetic import ovfcheck_float_to_int shift_count = rnum & 0x1F res = lnum >> shift_count + w_res = _w(res) - try: - ovfcheck_float_to_int(res) - w_res = _w(res) - except OverflowError: - w_res = _w(float(res)) + #try: + #ovfcheck_float_to_int(res) + #w_res = _w(res) + #except OverflowError: + #w_res = _w(float(res)) ctx.stack_append(w_res) @@ -476,42 +474,50 @@ class GT(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare(ctx, op1, op2) + def decision(self, op1, op2): + from js.baseop import compare_gt + res = compare_gt(op1, op2) + return res class GE(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare_e(ctx, op1, op2) + def decision(self, op1, op2): + from js.baseop import compare_ge + res = compare_ge(op1, op2) + return res class LT(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare(ctx, op2, op1) + def decision(self, op1, op2): + from js.baseop import compare_lt + res = compare_lt(op1, op2) + return res class LE(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare_e(ctx, op2, op1) + def decision(self, op1, op2): + from js.baseop import compare_le + res = compare_le(op1, op2) + return res class EQ(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return AbstractEC(ctx, op1, op2) + def decision(self, op1, op2): + return AbstractEC(op1, op2) class NE(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return not AbstractEC(ctx, op1, op2) + def decision(self, op1, op2): + return not AbstractEC(op1, op2) class IS(BaseBinaryComparison): - def decision(self, ctx, op1, op2): + def decision(self, op1, op2): return StrictEC(op1, op2) class ISNOT(BaseBinaryComparison): - def decision(self, ctx, op1, op2): + def decision(self, op1, op2): return not StrictEC(op1, op2) From noreply at buildbot.pypy.org Mon May 13 09:15:41 2013 From: noreply at buildbot.pypy.org (stepahn) Date: Mon, 13 May 2013 09:15:41 +0200 (CEST) Subject: [pypy-commit] lang-js default: Merged changes Message-ID: <20130513071541.14E6C1C0281@cobra.cs.uni-duesseldorf.de> Author: Stephan Branch: Changeset: r378:cc983acc4a7f Date: 2013-05-13 09:15 +0200 http://bitbucket.org/pypy/lang-js/changeset/cc983acc4a7f/ Log: Merged changes diff --git a/README.rst b/README.rst new file mode 100644 --- /dev/null +++ b/README.rst @@ -0,0 +1,17 @@ +langjs +====== + +langjs is an implementation of javascript programming language, written in +Python using RPython. + +You will need to install some dependencies. You can do it with:: + + pip install -r requirements.txt + +And make sure you have `PyPy_` on your ``PYTHONPATH``. + +To run tests:: + + $ PYTHONPATH=. py.test + +.. _`PyPy`: https://bitbucket.org/pypy/pypy diff --git a/requirements.txt b/requirements.txt new file mode 100644 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,1 @@ +pytest From noreply at buildbot.pypy.org Mon May 13 14:22:21 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 14:22:21 +0200 (CEST) Subject: [pypy-commit] pypy default: Add #ifdefs to our generated decl files Message-ID: <20130513122221.44AA61C0281@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64026:f122c7c37700 Date: 2013-05-13 14:21 +0200 http://bitbucket.org/pypy/pypy/changeset/f122c7c37700/ Log: Add #ifdefs to our generated decl files diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -703,6 +703,8 @@ print >> f, '/***********************************************************/' print >> f, '/*** Structure definitions ***/' print >> f + print >> f, "#ifndef _PYPY_STRUCTDEF_H" + print >> f, "#define _PYPY_STRUCTDEF_H" for node in structdeflist: if hasattr(node, 'forward_decl'): if node.forward_decl: @@ -713,14 +715,18 @@ for node in structdeflist: for line in node.definition(): print >> f, line + print >> f, "#endif" def gen_forwarddecl(f, database): print >> f, '/***********************************************************/' print >> f, '/*** Forward declarations ***/' print >> f + print >> f, "#ifndef _PYPY_FORWARDDECL_H" + print >> f, "#define _PYPY_FORWARDDECL_H" for node in database.globalcontainers(): for line in node.forward_declaration(): print >> f, line + print >> f, "#endif" def gen_preimpl(f, database): if database.translator is None or database.translator.rtyper is None: From noreply at buildbot.pypy.org Mon May 13 15:33:48 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 15:33:48 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: Fight with RPython and multimethods Message-ID: <20130513133348.929A51C0281@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64027:945a8316f0a8 Date: 2013-05-13 15:33 +0200 http://bitbucket.org/pypy/pypy/changeset/945a8316f0a8/ Log: Fight with RPython and multimethods diff --git a/pypy/module/array/__init__.py b/pypy/module/array/__init__.py --- a/pypy/module/array/__init__.py +++ b/pypy/module/array/__init__.py @@ -1,12 +1,5 @@ from pypy.interpreter.mixedmodule import MixedModule -from pypy.module.array.interp_array import types -from pypy.objspace.std.model import registerimplementation - -for mytype in types.values(): - registerimplementation(mytype.w_class) - - class Module(MixedModule): interpleveldefs = { 'array': 'interp_array.W_ArrayBase', 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 @@ -4,8 +4,8 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef +from pypy.interpreter.baseobjspace import W_Root from pypy.module._file.interp_file import W_File -from pypy.objspace.std.model import W_Object from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen from rpython.rlib.unroll import unrolling_iterable @@ -105,10 +105,12 @@ return space.w_False return space.w_True +UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, + hints={'nolength': True})) -class W_ArrayBase(W_Object): +class W_ArrayBase(W_Root): _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer - + def __init__(self, space): self.space = space self.len = 0 @@ -287,7 +289,8 @@ an array of some other type. """ if self.typecode == 'u': - return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) + buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned()) + return space.wrap(rffi.wcharpsize2unicode(buf, self.len)) else: msg = "tounicode() may only be called on type 'u' arrays" raise OperationError(space.w_ValueError, space.wrap(msg)) @@ -460,10 +463,6 @@ s = "array('%s', %s)" % (self.typecode, space.str_w(r)) return space.wrap(s) - @staticmethod - def register(typeorder): - typeorder[W_ArrayBase] = [] - W_ArrayBase.typedef = TypeDef( 'array', __new__ = interp2app(w_array), @@ -807,7 +806,7 @@ def getitem_slice(self, space, w_idx): start, stop, step, size = space.decode_index4(w_idx, self.len) - w_a = self.constructor(self.space) + w_a = mytype.w_class(self.space) w_a.setlen(size, overallocate=False) assert step != 0 j = 0 From noreply at buildbot.pypy.org Mon May 13 15:52:45 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 15:52:45 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: please RPython some more Message-ID: <20130513135245.EE2FA1C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64028:07a6d73c6b9b Date: 2013-05-13 15:52 +0200 http://bitbucket.org/pypy/pypy/changeset/07a6d73c6b9b/ Log: please RPython some more 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 @@ -57,14 +57,15 @@ return space.wrap(self.typecode) arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') +EQ, NE, LT, LE, GT, GE = range(6) -def compare_arrays(space, arr1, arr2, comp_func): +def compare_arrays(space, arr1, arr2, comp_op, comp_func): if (not isinstance(arr1, W_ArrayBase) or not isinstance(arr2, W_ArrayBase)): return space.w_NotImplemented - if comp_func == space.eq and arr1.len != arr2.len: + if comp_op == EQ and arr1.len != arr2.len: return space.w_False - if comp_func == space.ne and arr1.len != arr2.len: + if comp_op == NE and arr1.len != arr2.len: return space.w_True lgt = min(arr1.len, arr2.len) for i in range(lgt): @@ -72,13 +73,13 @@ w_elem1 = arr1.w_getitem(space, i) w_elem2 = arr2.w_getitem(space, i) res = space.is_true(comp_func(w_elem1, w_elem2)) - if comp_func == space.eq: + if comp_op == EQ: if not res: return space.w_False - elif comp_func == space.ne: + elif comp_op == NE: if res: return space.w_True - elif comp_func == space.lt or comp_func == space.gt: + elif comp_op == LT or comp_op == GT: if res: return space.w_True elif not space.is_true(space.eq(w_elem1, w_elem2)): @@ -89,15 +90,15 @@ elif not space.is_true(space.eq(w_elem1, w_elem2)): return space.w_True # we have some leftovers - if comp_func == space.eq: + if comp_op == EQ: return space.w_True - elif comp_func == space.ne: + elif comp_op == NE: return space.w_False if arr1.len == arr2.len: - if comp_func == space.lt or comp_func == space.gt: + if comp_op == LT or comp_op == GT: return space.w_False return space.w_True - if comp_func == space.lt or comp_func == space.le: + if comp_op == LT or comp_op == LE: if arr1.len < arr2.len: return space.w_False return space.w_True @@ -361,27 +362,27 @@ def descr_eq(self, space, w_arr2): "x.__eq__(y) <==> x==y" - return compare_arrays(space, self, w_arr2, space.eq) + return compare_arrays(space, self, w_arr2, EQ, space.eq) def descr_ne(self, space, w_arr2): "x.__ne__(y) <==> x!=y" - return compare_arrays(space, self, w_arr2, space.ne) + return compare_arrays(space, self, w_arr2, NE, space.ne) def descr_lt(self, space, w_arr2): "x.__lt__(y) <==> x x<=y" - return compare_arrays(space, self, w_arr2, space.le) + return compare_arrays(space, self, w_arr2, LE, space.le) def descr_gt(self, space, w_arr2): "x.__gt__(y) <==> x>y" - return compare_arrays(space, self, w_arr2, space.gt) + return compare_arrays(space, self, w_arr2, GT, space.gt) def descr_ge(self, space, w_arr2): "x.__ge__(y) <==> x>=y" - return compare_arrays(space, self, w_arr2, space.ge) + return compare_arrays(space, self, w_arr2, GE, space.ge) # Basic get/set/append/extend methods From noreply at buildbot.pypy.org Mon May 13 16:17:04 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 16:17:04 +0200 (CEST) Subject: [pypy-commit] pypy default: Add more embedding API, I think this is right, but very hard to test Message-ID: <20130513141704.741951C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64029:a1b20d7f239c Date: 2013-05-13 16:16 +0200 http://bitbucket.org/pypy/pypy/changeset/a1b20d7f239c/ Log: Add more embedding API, I think this is right, but very hard to test diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -2,6 +2,7 @@ import os, sys +import pypy from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.tool.ann_override import PyPyAnnotatorPolicy @@ -80,6 +81,24 @@ from rpython.rlib.entrypoint import entrypoint from rpython.rtyper.lltypesystem import rffi + @entrypoint('main', [rffi.CCHARP], c_name='pypy_setup_home') + def pypy_setup_home(ll_home): + from pypy.module.sys.initpath import pypy_find_stdlib + if ll_home: + home = rffi.charp2str(ll_home) + else: + home = pypydir + pypy_find_stdlib(space, home) + space.startup() + # import site + try: + import_ = space.getattr(space.getbuiltinmodule('__builtin__'), + space.wrap('__import__')) + space.call_function(import_, space.wrap('site')) + return 0 + except OperationError: + return 1 + @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') def pypy_execute_source(ll_source): source = rffi.charp2str(ll_source) @@ -101,7 +120,8 @@ return 1 return 0 - return entry_point, _pypy_execute_source # for tests + return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_setup_home': pypy_setup_home} def call_finish(space): space.finish() diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py --- a/pypy/interpreter/test/test_targetpypy.py +++ b/pypy/interpreter/test/test_targetpypy.py @@ -1,5 +1,6 @@ from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point from pypy.config.pypyoption import get_pypy_config +from rpython.rtyper.lltypesystem import rffi, lltype class TestTargetPyPy(object): def test_run(self): @@ -8,11 +9,20 @@ entry_point(['pypy-c' , '-S', '-c', 'print 3']) def test_exeucte_source(space): - _, execute_source = create_entry_point(space, None) - execute_source("import sys; sys.modules['xyz'] = 3") + _, d = create_entry_point(space, None) + execute_source = d['pypy_execute_source'] + lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3") + execute_source(lls) + lltype.free(lls, flavor='raw') x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'], space.wrap('modules')), space.wrap('xyz'))) assert x == 3 - execute_source("sys") + lls = rffi.str2charp("sys") + execute_source(lls) + lltype.free(lls, flavor='raw') # did not crash - the same globals + pypy_setup_home = d['pypy_setup_home'] + lls = rffi.str2charp(__file__) + pypy_setup_home(lls) + lltype.free(lls, flavor='raw') diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -29,6 +29,7 @@ if not we_are_translated(): import traceback traceback.print_exc() + raise else: print str(e) pypy_debug_catch_fatal_exception() From noreply at buildbot.pypy.org Mon May 13 16:19:00 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Mon, 13 May 2013 16:19:00 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Start fixing test_zjit Message-ID: <20130513141900.C3BC01C009D@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64030:87e24d1ab3cc Date: 2013-05-13 16:09 +0200 http://bitbucket.org/pypy/pypy/changeset/87e24d1ab3cc/ Log: Start fixing test_zjit diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -286,12 +286,12 @@ for w_elem in lst_w: size = 1 w_shape = space.newtuple([]) - if space.len_w(w_elem) >2: - w_shape = space.getitem(w_elem, space.wrap(2)) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) if not base.issequence_w(space, w_shape): w_shape = space.newtuple([w_shape,]) - w_fldname = space.getitem(w_elem, space.wrap(0)) - w_flddesc = space.getitem(w_elem, space.wrap(1)) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1733,7 +1733,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) From noreply at buildbot.pypy.org Mon May 13 17:37:40 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 17:37:40 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: merge default Message-ID: <20130513153740.C1D191C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64031:fa05eb32023c Date: 2013-05-13 17:36 +0200 http://bitbucket.org/pypy/pypy/changeset/fa05eb32023c/ Log: merge default diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -2,6 +2,7 @@ import os, sys +import pypy from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.tool.ann_override import PyPyAnnotatorPolicy @@ -80,6 +81,24 @@ from rpython.rlib.entrypoint import entrypoint from rpython.rtyper.lltypesystem import rffi + @entrypoint('main', [rffi.CCHARP], c_name='pypy_setup_home') + def pypy_setup_home(ll_home): + from pypy.module.sys.initpath import pypy_find_stdlib + if ll_home: + home = rffi.charp2str(ll_home) + else: + home = pypydir + pypy_find_stdlib(space, home) + space.startup() + # import site + try: + import_ = space.getattr(space.getbuiltinmodule('__builtin__'), + space.wrap('__import__')) + space.call_function(import_, space.wrap('site')) + return 0 + except OperationError: + return 1 + @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') def pypy_execute_source(ll_source): source = rffi.charp2str(ll_source) @@ -101,7 +120,8 @@ return 1 return 0 - return entry_point, _pypy_execute_source # for tests + return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_setup_home': pypy_setup_home} def call_finish(space): space.finish() diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py --- a/pypy/interpreter/test/test_targetpypy.py +++ b/pypy/interpreter/test/test_targetpypy.py @@ -1,5 +1,6 @@ from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point from pypy.config.pypyoption import get_pypy_config +from rpython.rtyper.lltypesystem import rffi, lltype class TestTargetPyPy(object): def test_run(self): @@ -8,11 +9,20 @@ entry_point(['pypy-c' , '-S', '-c', 'print 3']) def test_exeucte_source(space): - _, execute_source = create_entry_point(space, None) - execute_source("import sys; sys.modules['xyz'] = 3") + _, d = create_entry_point(space, None) + execute_source = d['pypy_execute_source'] + lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3") + execute_source(lls) + lltype.free(lls, flavor='raw') x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'], space.wrap('modules')), space.wrap('xyz'))) assert x == 3 - execute_source("sys") + lls = rffi.str2charp("sys") + execute_source(lls) + lltype.free(lls, flavor='raw') # did not crash - the same globals + pypy_setup_home = d['pypy_setup_home'] + lls = rffi.str2charp(__file__) + pypy_setup_home(lls) + lltype.free(lls, flavor='raw') diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -29,6 +29,7 @@ if not we_are_translated(): import traceback traceback.print_exc() + raise else: print str(e) pypy_debug_catch_fatal_exception() diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -703,6 +703,8 @@ print >> f, '/***********************************************************/' print >> f, '/*** Structure definitions ***/' print >> f + print >> f, "#ifndef _PYPY_STRUCTDEF_H" + print >> f, "#define _PYPY_STRUCTDEF_H" for node in structdeflist: if hasattr(node, 'forward_decl'): if node.forward_decl: @@ -713,14 +715,18 @@ for node in structdeflist: for line in node.definition(): print >> f, line + print >> f, "#endif" def gen_forwarddecl(f, database): print >> f, '/***********************************************************/' print >> f, '/*** Forward declarations ***/' print >> f + print >> f, "#ifndef _PYPY_FORWARDDECL_H" + print >> f, "#define _PYPY_FORWARDDECL_H" for node in database.globalcontainers(): for line in node.forward_declaration(): print >> f, line + print >> f, "#endif" def gen_preimpl(f, database): if database.translator is None or database.translator.rtyper is None: From noreply at buildbot.pypy.org Mon May 13 17:54:49 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 17:54:49 +0200 (CEST) Subject: [pypy-commit] pypy default: fix the test - secondary callbacks now do that Message-ID: <20130513155449.D6E3B1C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64032:afb35608bfbf Date: 2013-05-13 17:54 +0200 http://bitbucket.org/pypy/pypy/changeset/afb35608bfbf/ Log: fix the test - secondary callbacks now do that diff --git a/rpython/translator/c/gcc/test/test_asmgcroot.py b/rpython/translator/c/gcc/test/test_asmgcroot.py --- a/rpython/translator/c/gcc/test/test_asmgcroot.py +++ b/rpython/translator/c/gcc/test/test_asmgcroot.py @@ -195,10 +195,7 @@ @entrypoint("x42", [lltype.Signed, lltype.Signed], c_name='callback') def mycallback(a, b): - rffi.stackcounter.stacks_counter += 1 - llop.gc_stack_bottom(lltype.Void) gc.collect() - rffi.stackcounter.stacks_counter -= 1 return a + b c_source = py.code.Source(""" From noreply at buildbot.pypy.org Mon May 13 18:55:01 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 13 May 2013 18:55:01 +0200 (CEST) Subject: [pypy-commit] pypy default: add armhf to getnightly Message-ID: <20130513165501.189281C026D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64033:97989d13642c Date: 2013-05-13 18:53 +0200 http://bitbucket.org/pypy/pypy/changeset/97989d13642c/ Log: add armhf to getnightly diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -8,7 +8,9 @@ arch = 'linux' cmd = 'wget "%s"' tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" -if sys.platform.startswith('darwin'): + if os.uname()[-1].startswith('arm'): + arch += '-armhf-raspbian' +elif sys.platform.startswith('darwin'): arch = 'osx' cmd = 'curl -O "%s"' tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" From noreply at buildbot.pypy.org Mon May 13 19:17:16 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 13 May 2013 19:17:16 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: hg merge default Message-ID: <20130513171716.70AEC1C00F4@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64034:00113e48936f Date: 2013-05-13 15:10 +0200 http://bitbucket.org/pypy/pypy/changeset/00113e48936f/ Log: hg merge default diff too long, truncating to 2000 out of 4533 lines 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 @@ -119,13 +119,13 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: - cflags = os.environ["CFLAGS"] - compiler.compiler.append(cflags) - compiler.compiler_so.append(cflags) - compiler.linker_so.append(cflags) + cflags = os.environ["CFLAGS"].split() + compiler.compiler.extend(cflags) + compiler.compiler_so.extend(cflags) + compiler.linker_so.extend(cflags) from sysconfig_cpython import ( diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -1,25 +1,21 @@ -import os +import sys, os from ctypes_configure import dumpcache -from rpython.jit.backend import detect_cpu def dumpcache2(basename, config): - model = detect_cpu.autodetect_main_model_and_size() - filename = '_%s_%s_.py' % (basename, model) + size = 32 if sys.maxint <= 2**32 else 64 + filename = '_%s_%s_.py' % (basename, size) dumpcache.dumpcache(__file__, filename, config) # filename = os.path.join(os.path.dirname(__file__), '_%s_cache.py' % (basename,)) g = open(filename, 'w') print >> g, '''\ -try: - from __pypy__ import cpumodel -except ImportError: - from rpython.jit.backend import detect_cpu - cpumodel = detect_cpu.autodetect_main_model_and_size() +import sys +_size = 32 if sys.maxint <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib -mod = __import__("_%s_%%s_" %% (cpumodel,), - globals(), locals(), ["*"]) -globals().update(mod.__dict__)\ +_mod = __import__("_%s_%%s_" %% (_size,), + globals(), locals(), ["*"]) +globals().update(_mod.__dict__)\ ''' % (basename,) g.close() diff --git a/lib_pypy/ctypes_config_cache/rebuild.py b/lib_pypy/ctypes_config_cache/rebuild.py --- a/lib_pypy/ctypes_config_cache/rebuild.py +++ b/lib_pypy/ctypes_config_cache/rebuild.py @@ -25,13 +25,12 @@ sys.path[:] = path def try_rebuild(): - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - # remove the files '_*_model_.py' + size = 32 if sys.maxint <= 2**32 else 64 + # remove the files '_*_size_.py' left = {} for p in os.listdir(_dirpath): - if p.startswith('_') and (p.endswith('_%s_.py' % model) or - p.endswith('_%s_.pyc' % model)): + if p.startswith('_') and (p.endswith('_%s_.py' % size) or + p.endswith('_%s_.pyc' % size)): os.unlink(os.path.join(_dirpath, p)) elif p.startswith('_') and (p.endswith('_.py') or p.endswith('_.pyc')): diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -91,7 +91,7 @@ # itself needs the interp-level struct module # because 'P' is missing from the app-level one "_rawffi": [("objspace.usemodules.struct", True)], - "cpyext": [("translation.secondaryentrypoints", "cpyext"), + "cpyext": [("translation.secondaryentrypoints", "cpyext,main"), ("translation.shared", sys.platform == "win32")], } diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0-beta1' +release = '2.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -100,7 +100,7 @@ $ ./pypy-c Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``RPython magically makes you rich and famous (says so on the tin)'' @@ -232,7 +232,7 @@ the ``bin/pypy`` executable. To install PyPy system wide on unix-like systems, it is recommended to put the -whole hierarchy alone (e.g. in ``/opt/pypy2.0-beta1``) and put a symlink to the +whole hierarchy alone (e.g. in ``/opt/pypy2.0``) and put a symlink to the ``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -53,10 +53,10 @@ PyPy is ready to be executed as soon as you unpack the tarball or the zip file, with no need to install it in any specific location:: - $ tar xf pypy-2.0-beta1-linux.tar.bz2 - $ ./pypy-2.0-beta1/bin/pypy + $ tar xf pypy-2.0.tar.bz2 + $ ./pypy-2.0/bin/pypy Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``PyPy is an exciting technology that lets you to write fast, portable, multi-platform interpreters with less @@ -75,14 +75,14 @@ $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.0-beta1/bin/pypy distribute_setup.py + $ ./pypy-2.0/bin/pypy distribute_setup.py - $ ./pypy-2.0-beta1/bin/pypy get-pip.py + $ ./pypy-2.0/bin/pypy get-pip.py - $ ./pypy-2.0-beta1/bin/pip install pygments # for example + $ ./pypy-2.0/bin/pip install pygments # for example -3rd party libraries will be installed in ``pypy-2.0-beta1/site-packages``, and -the scripts in ``pypy-2.0-beta1/bin``. +3rd party libraries will be installed in ``pypy-2.0/site-packages``, and +the scripts in ``pypy-2.0/bin``. Installing using virtualenv diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -43,7 +43,7 @@ * :doc:`FAQ `: some frequently asked questions. -* `Release 2.0 beta 2`_: the latest official release +* `Release 2.0`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -57,7 +57,7 @@ particularly organized .. _PyPy blog: http://morepypy.blogspot.com/ -.. _Release 2.0 beta 2: http://pypy.org/download.html +.. _Release 2.0: http://pypy.org/download.html .. _speed.pypy.org: http://speed.pypy.org .. toctree:: diff --git a/pypy/doc/releases/2.0.0.rst b/pypy/doc/releases/2.0.0.rst --- a/pypy/doc/releases/2.0.0.rst +++ b/pypy/doc/releases/2.0.0.rst @@ -4,6 +4,8 @@ We're pleased to announce PyPy 2.0. This is a stable release that brings a swath of bugfixes, small performance improvements and compatibility fixes. +PyPy 2.0 is a big step for us and we hope in the future we'll be able to +provide stable releases more often. You can download the PyPy 2.0 release here: @@ -19,6 +21,10 @@ .. _cffi: http://cffi.readthedocs.org +If you're using PyPy for anything, it would help us immensely if you fill out +the following survey: http://bit.ly/pypysurvey This is for the developers +eyes and we will not make any information public without your agreement. + What is PyPy? ============= @@ -28,8 +34,8 @@ This release supports x86 machines running Linux 32/64, Mac OS X 64 or Windows 32. Windows 64 work is still stalling, we would welcome a volunteer -to handle that. ARM support is on the way and we're expecting to release -an alpha ARM version shortly. +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. .. _pypy 2.0 and cpython 2.7.3: http://speed.pypy.org @@ -54,6 +60,10 @@ * A lot of stability issues fixed. +* Refactoring much of the numpypy array classes, which resulted in removal of + lazy expression evaluation. On the other hand, we now have more complete + dtype support and support more array attributes. + .. _pypycore: https://github.com/gevent-on-pypy/pypycore/ .. _pypy-hacks: https://github.com/schmir/gevent/tree/pypy-hacks 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 @@ -5,3 +5,5 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 +.. branch: numpy-pickle +Pickling of numpy arrays and dtypes (including record dtypes) diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -22,20 +22,22 @@ # __________ Entry point __________ + def create_entry_point(space, w_dict): - w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) - w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) - w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) - w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) - withjit = space.config.objspace.usemodules.pypyjit + if w_dict is not None: # for tests + w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) + w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) + w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) + w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) + withjit = space.config.objspace.usemodules.pypyjit def entry_point(argv): if withjit: from rpython.jit.backend.hlinfo import highleveljitinfo highleveljitinfo.sys_executable = argv[0] - #debug("entry point starting") - #for arg in argv: + #debug("entry point starting") + #for arg in argv: # debug(" argv -> " + arg) if len(argv) > 2 and argv[1] == '--heapsize': # Undocumented option, handled at interp-level. @@ -71,7 +73,35 @@ debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 return exitcode - return entry_point + + # register the minimal equivalent of running a small piece of code. This + # should be used as sparsely as possible, just to register callbacks + + from rpython.rlib.entrypoint import entrypoint + from rpython.rtyper.lltypesystem import rffi + + @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') + def pypy_execute_source(ll_source): + source = rffi.charp2str(ll_source) + return _pypy_execute_source(source) + + w_globals = space.newdict() + space.setitem(w_globals, space.wrap('__builtins__'), + space.builtin_modules['__builtin__']) + + def _pypy_execute_source(source): + try: + compiler = space.createcompiler() + stmt = compiler.compile(source, 'c callback', 'exec', 0) + stmt.exec_code(space, w_globals, w_globals) + except OperationError, e: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + return 0 + + return entry_point, _pypy_execute_source # for tests def call_finish(space): space.finish() @@ -219,7 +249,7 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy, pypy_hooks return PyPyJitPolicy(pypy_hooks) - + def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy rebuild = import_from_lib_pypy('ctypes_config_cache/rebuild') @@ -232,7 +262,7 @@ app = gateway.applevel(open(filename).read(), 'app_main.py', 'app_main') app.hidden_applevel = False w_dict = app.getwdict(space) - entry_point = create_entry_point(space, w_dict) + entry_point, _ = create_entry_point(space, w_dict) return entry_point, None, PyPyAnnotatorPolicy(single_space = space) diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -803,7 +803,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -812,11 +811,13 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = {} + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -27,7 +27,7 @@ new_inst = mod.get('generator_new') w = space.wrap if self.frame: - w_frame = w(self.frame) + w_frame = self.frame._reduce_state(space) else: w_frame = space.w_None @@ -36,7 +36,20 @@ w(self.running), ] - return space.newtuple([new_inst, space.newtuple(tup)]) + return space.newtuple([new_inst, space.newtuple([]), + space.newtuple(tup)]) + + def descr__setstate__(self, space, w_args): + from rpython.rlib.objectmodel import instantiate + args_w = space.unpackiterable(w_args) + w_framestate, w_running = args_w + if space.is_w(w_framestate, space.w_None): + self.frame = None + else: + frame = instantiate(space.FrameClass) # XXX fish + frame.descr__setstate__(space, w_framestate) + GeneratorIterator.__init__(self, frame) + self.running = self.space.is_true(w_running) def descr__iter__(self): """x.__iter__() <==> iter(x)""" diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -13,6 +13,7 @@ # imported yet, and when it has been, it is mod.__dict__.items() just # after startup(). w_initialdict = None + lazy = False def __init__(self, space, w_name): """ NOT_RPYTHON """ diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -16,10 +16,9 @@ from rpython.tool.stdlib_opcode import host_bytecode_spec # Define some opcodes used -g = globals() for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY POP_BLOCK END_FINALLY'''.split(): - g[op] = stdlib_opcode.opmap[op] + globals()[op] = stdlib_opcode.opmap[op] HAVE_ARGUMENT = stdlib_opcode.HAVE_ARGUMENT class PyFrame(eval.Frame): @@ -304,11 +303,17 @@ @jit.dont_look_inside def descr__reduce__(self, space): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('frame_new') - w = space.wrap + w_tup_state = self._reduce_state(space) + nt = space.newtuple + return nt([new_inst, nt([]), w_tup_state]) + + @jit.dont_look_inside + def _reduce_state(self, space): + from pypy.module._pickle_support import maker # helper fns + w = space.wrap nt = space.newtuple cells = self._getcells() @@ -359,8 +364,7 @@ w(self.instr_prev_plus_one), w_cells, ] - - return nt([new_inst, nt([]), nt(tup_state)]) + return nt(tup_state) @jit.dont_look_inside def descr__setstate__(self, space, w_args): diff --git a/pypy/interpreter/test2/mymodule.py b/pypy/interpreter/test/mymodule.py rename from pypy/interpreter/test2/mymodule.py rename to pypy/interpreter/test/mymodule.py diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py new file mode 100644 --- /dev/null +++ b/pypy/interpreter/test/test_app_main.py @@ -0,0 +1,966 @@ +""" +Tests for the entry point of pypy-c, app_main.py. +""" +from __future__ import with_statement +import py +import sys, os, re, runpy, subprocess +from rpython.tool.udir import udir +from contextlib import contextmanager +from pypy.conftest import pypydir + +banner = sys.version.splitlines()[0] + +app_main = os.path.join(os.path.realpath(os.path.dirname(__file__)), os.pardir, 'app_main.py') +app_main = os.path.abspath(app_main) + +_counter = 0 +def _get_next_path(ext='.py'): + global _counter + p = udir.join('demo_test_app_main_%d%s' % (_counter, ext)) + _counter += 1 + return p + +def getscript(source): + p = _get_next_path() + p.write(str(py.code.Source(source))) + return str(p) + +def getscript_pyc(space, source): + p = _get_next_path() + p.write(str(py.code.Source(source))) + w_dir = space.wrap(str(p.dirpath())) + w_modname = space.wrap(p.purebasename) + space.appexec([w_dir, w_modname], """(dir, modname): + import sys + d = sys.modules.copy() + sys.path.insert(0, dir) + __import__(modname) + sys.path.pop(0) + for key in sys.modules.keys(): + if key not in d: + del sys.modules[key] + """) + p = str(p) + 'c' + assert os.path.isfile(p) # the .pyc file should have been created above + return p + +def getscript_in_dir(source): + pdir = _get_next_path(ext='') + p = pdir.ensure(dir=1).join('__main__.py') + p.write(str(py.code.Source(source))) + # return relative path for testing purposes + return py.path.local().bestrelpath(pdir) + +demo_script = getscript(""" + print 'hello' + print 'Name:', __name__ + print 'File:', __file__ + import sys + print 'Exec:', sys.executable + print 'Argv:', sys.argv + print 'goodbye' + myvalue = 6*7 + """) + +crashing_demo_script = getscript(""" + print 'Hello2' + myvalue2 = 11 + ooups + myvalue2 = 22 + print 'Goodbye2' # should not be reached + """) + + +class TestParseCommandLine: + def check_options(self, options, sys_argv, **expected): + assert sys.argv == sys_argv + for key, value in expected.items(): + assert options[key] == value + for key, value in options.items(): + if key not in expected: + assert not value, ( + "option %r has unexpectedly the value %r" % (key, value)) + + def check(self, argv, env, **expected): + import StringIO + from pypy.interpreter import app_main + saved_env = os.environ.copy() + saved_sys_argv = sys.argv[:] + saved_sys_stdout = sys.stdout + saved_sys_stderr = sys.stdout + app_main.os = os + try: + os.environ.update(env) + sys.stdout = sys.stderr = StringIO.StringIO() + try: + options = app_main.parse_command_line(argv) + except SystemExit: + output = expected['output_contains'] + assert output in sys.stdout.getvalue() + else: + self.check_options(options, **expected) + finally: + os.environ.clear() + os.environ.update(saved_env) + sys.argv[:] = saved_sys_argv + sys.stdout = saved_sys_stdout + sys.stderr = saved_sys_stderr + + def test_all_combinations_I_can_think_of(self): + self.check([], {}, sys_argv=[''], run_stdin=True) + self.check(['-'], {}, sys_argv=['-'], run_stdin=True) + self.check(['-S'], {}, sys_argv=[''], run_stdin=True, no_site=1) + self.check(['-OO'], {}, sys_argv=[''], run_stdin=True, optimize=2) + self.check(['-O', '-O'], {}, sys_argv=[''], run_stdin=True, optimize=2) + self.check(['-Qnew'], {}, sys_argv=[''], run_stdin=True, division_new=1) + self.check(['-Qold'], {}, sys_argv=[''], run_stdin=True, division_new=0) + self.check(['-Qwarn'], {}, sys_argv=[''], run_stdin=True, division_warning=1) + self.check(['-Qwarnall'], {}, sys_argv=[''], run_stdin=True, + division_warning=2) + self.check(['-Q', 'new'], {}, sys_argv=[''], run_stdin=True, division_new=1) + self.check(['-SOQnew'], {}, sys_argv=[''], run_stdin=True, + no_site=1, optimize=1, division_new=1) + self.check(['-SOQ', 'new'], {}, sys_argv=[''], run_stdin=True, + no_site=1, optimize=1, division_new=1) + self.check(['-i'], {}, sys_argv=[''], run_stdin=True, + interactive=1, inspect=1) + self.check(['-?'], {}, output_contains='usage:') + self.check(['-h'], {}, output_contains='usage:') + self.check(['-S', '-tO', '-h'], {}, output_contains='usage:') + self.check(['-S', '-thO'], {}, output_contains='usage:') + self.check(['-S', '-tO', '--help'], {}, output_contains='usage:') + self.check(['-S', '-tO', '--info'], {}, output_contains='translation') + self.check(['-S', '-tO', '--version'], {}, output_contains='Python') + self.check(['-S', '-tOV'], {}, output_contains='Python') + self.check(['--jit', 'foobar', '-S'], {}, sys_argv=[''], + run_stdin=True, no_site=1) + self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass') + self.check(['-cpass'], {}, sys_argv=['-c'], run_command='pass') + self.check(['-cpass','x'], {}, sys_argv=['-c','x'], run_command='pass') + self.check(['-Sc', 'pass'], {}, sys_argv=['-c'], run_command='pass', + no_site=1) + self.check(['-Scpass'], {}, sys_argv=['-c'], run_command='pass', no_site=1) + self.check(['-c', '', ''], {}, sys_argv=['-c', ''], run_command='') + self.check(['-mfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True) + self.check(['-m', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True) + self.check(['-Smfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True, no_site=1) + self.check(['-Sm', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True, no_site=1) + self.check(['-', 'foo', 'bar'], {}, sys_argv=['-', 'foo', 'bar'], + run_stdin=True) + self.check(['foo', 'bar'], {}, sys_argv=['foo', 'bar']) + self.check(['foo', '-i'], {}, sys_argv=['foo', '-i']) + self.check(['-i', 'foo'], {}, sys_argv=['foo'], interactive=1, inspect=1) + self.check(['--', 'foo'], {}, sys_argv=['foo']) + self.check(['--', '-i', 'foo'], {}, sys_argv=['-i', 'foo']) + self.check(['--', '-', 'foo'], {}, sys_argv=['-', 'foo'], run_stdin=True) + self.check(['-Wbog'], {}, sys_argv=[''], warnoptions=['bog'], run_stdin=True) + self.check(['-W', 'ab', '-SWc'], {}, sys_argv=[''], warnoptions=['ab', 'c'], + run_stdin=True, no_site=1) + + self.check([], {'PYTHONDEBUG': '1'}, sys_argv=[''], run_stdin=True, debug=1) + self.check([], {'PYTHONDONTWRITEBYTECODE': '1'}, sys_argv=[''], run_stdin=True, dont_write_bytecode=1) + self.check([], {'PYTHONNOUSERSITE': '1'}, sys_argv=[''], run_stdin=True, no_user_site=1) + self.check([], {'PYTHONUNBUFFERED': '1'}, sys_argv=[''], run_stdin=True, unbuffered=1) + self.check([], {'PYTHONVERBOSE': '1'}, sys_argv=[''], run_stdin=True, verbose=1) + + def test_sysflags(self): + flags = ( + ("debug", "-d", "1"), + ("py3k_warning", "-3", "1"), + ("division_warning", "-Qwarn", "1"), + ("division_warning", "-Qwarnall", "2"), + ("division_new", "-Qnew", "1"), + (["inspect", "interactive"], "-i", "1"), + ("optimize", "-O", "1"), + ("optimize", "-OO", "2"), + ("dont_write_bytecode", "-B", "1"), + ("no_user_site", "-s", "1"), + ("no_site", "-S", "1"), + ("ignore_environment", "-E", "1"), + ("tabcheck", "-t", "1"), + ("tabcheck", "-tt", "2"), + ("verbose", "-v", "1"), + ("unicode", "-U", "1"), + ("bytes_warning", "-b", "1"), + ) + for flag, opt, value in flags: + if isinstance(flag, list): # this is for inspect&interactive + expected = {} + for flag1 in flag: + expected[flag1] = int(value) + else: + expected = {flag: int(value)} + self.check([opt, '-c', 'pass'], {}, sys_argv=['-c'], + run_command='pass', **expected) + + def test_sysflags_envvar(self, monkeypatch): + monkeypatch.setenv('PYTHONNOUSERSITE', '1') + expected = {"no_user_site": True} + self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass', **expected) + + +class TestInteraction: + """ + These tests require pexpect (UNIX-only). + http://pexpect.sourceforge.net/ + """ + def _spawn(self, *args, **kwds): + try: + import pexpect + except ImportError, e: + py.test.skip(str(e)) + else: + # Version is of the style "0.999" or "2.1". Older versions of + # pexpect try to get the fileno of stdin, which generally won't + # work with py.test (due to sys.stdin being a DontReadFromInput + # instance). + version = map(int, pexpect.__version__.split('.')) + + # I only tested 0.999 and 2.1. The former does not work, the + # latter does. Feel free to refine this measurement. + # -exarkun, 17/12/2007 + if version < [2, 1]: + py.test.skip( + "pexpect version too old, requires 2.1 or newer: %r" % ( + pexpect.__version__,)) + + kwds.setdefault('timeout', 10) + print 'SPAWN:', ' '.join([args[0]] + args[1]), kwds + child = pexpect.spawn(*args, **kwds) + child.logfile = sys.stdout + return child + + def spawn(self, argv): + return self._spawn(sys.executable, [app_main] + argv) + + def test_interactive(self): + child = self.spawn([]) + child.expect('Python ') # banner + child.expect('>>> ') # prompt + child.sendline('[6*7]') + child.expect(re.escape('[42]')) + child.sendline('def f(x):') + child.expect(re.escape('... ')) + child.sendline(' return x + 100') + child.expect(re.escape('... ')) + child.sendline('') + child.expect('>>> ') + child.sendline('f(98)') + child.expect('198') + child.expect('>>> ') + child.sendline('__name__') + child.expect("'__main__'") + child.expect('>>> ') + child.sendline('import sys') + child.expect('>>> ') + child.sendline("'' in sys.path") + child.expect("True") + + def test_help(self): + # test that -h prints the usage, including the name of the executable + # which should be /full/path/to/app_main.py in this case + child = self.spawn(['-h']) + child.expect(r'usage: .*app_main.py \[option\]') + child.expect('PyPy options and arguments:') + + def test_run_script(self): + child = self.spawn([demo_script]) + idx = child.expect(['hello', 'Python ', '>>> ']) + assert idx == 0 # no banner or prompt + child.expect(re.escape("Name: __main__")) + child.expect(re.escape('File: ' + demo_script)) + child.expect(re.escape('Exec: ' + app_main)) + child.expect(re.escape('Argv: ' + repr([demo_script]))) + child.expect('goodbye') + + def test_run_script_with_args(self): + argv = [demo_script, 'hello', 'world'] + child = self.spawn(argv) + child.expect(re.escape('Argv: ' + repr(argv))) + child.expect('goodbye') + + def test_no_such_script(self): + import errno + msg = os.strerror(errno.ENOENT) # 'No such file or directory' + child = self.spawn(['xxx-no-such-file-xxx']) + child.expect(re.escape(msg)) + + def test_option_i(self): + argv = [demo_script, 'foo', 'bar'] + child = self.spawn(['-i'] + argv) + idx = child.expect(['hello', re.escape(banner)]) + assert idx == 0 # no banner + child.expect(re.escape('File: ' + demo_script)) + child.expect(re.escape('Argv: ' + repr(argv))) + child.expect('goodbye') + idx = child.expect(['>>> ', re.escape(banner)]) + assert idx == 0 # prompt, but still no banner + child.sendline('myvalue * 102') + child.expect('4284') + child.sendline('__name__') + child.expect('__main__') + + def test_option_i_crashing(self): + argv = [crashing_demo_script, 'foo', 'bar'] + child = self.spawn(['-i'] + argv) + idx = child.expect(['Hello2', re.escape(banner)]) + assert idx == 0 # no banner + child.expect('NameError') + child.sendline('myvalue2 * 1001') + child.expect('11011') + child.sendline('import sys; sys.argv') + child.expect(re.escape(repr(argv))) + child.sendline('sys.last_type.__name__') + child.expect(re.escape(repr('NameError'))) + + def test_options_i_c(self): + child = self.spawn(['-i', '-c', 'x=555']) + idx = child.expect(['>>> ', re.escape(banner)]) + assert idx == 0 # prompt, but no banner + child.sendline('x') + child.expect('555') + child.sendline('__name__') + child.expect('__main__') + child.sendline('import sys; sys.argv') + child.expect(re.escape("['-c']")) + + def test_options_i_c_crashing(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + child = self.spawn(['-i', '-c', 'x=666;foobar']) + child.expect('NameError') + idx = child.expect(['>>> ', re.escape(banner)]) + assert idx == 0 # prompt, but no banner + child.sendline('x') + child.expect('666') + child.sendline('__name__') + child.expect('__main__') + child.sendline('import sys; sys.argv') + child.expect(re.escape("['-c']")) + child.sendline('sys.last_type.__name__') + child.expect(re.escape(repr('NameError'))) + + def test_atexit(self): + child = self.spawn([]) + child.expect('>>> ') + child.sendline('def f(): print "foobye"') + child.sendline('') + child.sendline('import atexit; atexit.register(f)') + child.sendline('6*7') + child.expect('42') + # pexpect's sendeof() is confused by py.test capturing, though + # I think that it is a bug of sendeof() + old = sys.stdin + try: + sys.stdin = child + child.sendeof() + finally: + sys.stdin = old + child.expect('foobye') + + def test_pythonstartup(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) + child = self.spawn([]) + child.expect(re.escape(banner)) + child.expect('Traceback') + child.expect('NameError') + child.expect('>>> ') + child.sendline('[myvalue2]') + child.expect(re.escape('[11]')) + child.expect('>>> ') + + child = self.spawn(['-i', demo_script]) + for line in ['hello', 'goodbye', '>>> ']: + idx = child.expect([line, 'Hello2']) + assert idx == 0 # no PYTHONSTARTUP run here + child.sendline('myvalue2') + child.expect('Traceback') + child.expect('NameError') + + def test_pythonstartup_file1(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + monkeypatch.setenv('PYTHONSTARTUP', demo_script) + child = self.spawn([]) + child.expect('File: [^\n]+\.py') + child.expect('goodbye') + child.expect('>>> ') + child.sendline('[myvalue]') + child.expect(re.escape('[42]')) + child.expect('>>> ') + child.sendline('__file__') + child.expect('Traceback') + child.expect('NameError') + + def test_pythonstartup_file2(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) + child = self.spawn([]) + child.expect('Traceback') + child.expect('>>> ') + child.sendline('__file__') + child.expect('Traceback') + child.expect('NameError') + + def test_ignore_python_startup(self): + old = os.environ.get('PYTHONSTARTUP', '') + try: + os.environ['PYTHONSTARTUP'] = crashing_demo_script + child = self.spawn(['-E']) + child.expect(re.escape(banner)) + index = child.expect(['Traceback', '>>> ']) + assert index == 1 # no traceback + finally: + os.environ['PYTHONSTARTUP'] = old + + def test_ignore_python_inspect(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + child = self.spawn(['-E', '-c', 'pass']) + from pexpect import EOF + index = child.expect(['>>> ', EOF]) + assert index == 1 # no prompt + finally: + del os.environ['PYTHONINSPECT_'] + + def test_python_path_keeps_duplicates(self): + old = os.environ.get('PYTHONPATH', '') + try: + os.environ['PYTHONPATH'] = 'foobarbaz:foobarbaz' + child = self.spawn(['-c', 'import sys; print sys.path']) + child.expect(r"\['', 'foobarbaz', 'foobarbaz', ") + finally: + os.environ['PYTHONPATH'] = old + + def test_ignore_python_path(self): + old = os.environ.get('PYTHONPATH', '') + try: + os.environ['PYTHONPATH'] = 'foobarbaz' + child = self.spawn(['-E', '-c', 'import sys; print sys.path']) + from pexpect import EOF + index = child.expect(['foobarbaz', EOF]) + assert index == 1 # no foobarbaz + finally: + os.environ['PYTHONPATH'] = old + + def test_unbuffered(self): + line = 'import os,sys;sys.stdout.write(str(789));os.read(0,1)' + child = self.spawn(['-u', '-c', line]) + child.expect('789') # expect to see it before the timeout hits + child.sendline('X') + + def test_options_i_m(self, monkeypatch): + if sys.platform == "win32": + skip("close_fds is not supported on Windows platforms") + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') + p = os.path.abspath(p) + monkeypatch.chdir(os.path.dirname(app_main)) + child = self.spawn(['-i', + '-m', 'test.mymodule', + 'extra']) + child.expect('mymodule running') + child.expect('Name: __main__') + child.expect(re.escape('File: ' + p)) + child.expect(re.escape('Argv: ' + repr([p, 'extra']))) + child.expect('>>> ') + child.sendline('somevalue') + child.expect(re.escape(repr("foobar"))) + child.expect('>>> ') + child.sendline('import sys') + child.sendline('"test" in sys.modules') + child.expect('True') + child.sendline('"test.mymodule" in sys.modules') + child.expect('False') + child.sendline('sys.path[0]') + child.expect("''") + + def test_option_i_noexit(self): + child = self.spawn(['-i', '-c', 'import sys; sys.exit(1)']) + child.expect('Traceback') + child.expect('SystemExit: 1') + + def test_options_u_i(self): + if sys.platform == "win32": + skip("close_fds is not supported on Windows platforms") + import subprocess, select, os + python = sys.executable + pipe = subprocess.Popen([python, app_main, "-u", "-i"], + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0, close_fds=True) + iwtd, owtd, ewtd = select.select([pipe.stdout], [], [], 5) + assert iwtd # else we timed out + data = os.read(pipe.stdout.fileno(), 1024) + assert data.startswith('Python') + + def test_paste_several_lines_doesnt_mess_prompt(self): + py.test.skip("this can only work if readline is enabled") + child = self.spawn([]) + child.expect('>>> ') + child.sendline('if 1:\n print 42\n') + child.expect('... print 42') + child.expect('... ') + child.expect('42') + child.expect('>>> ') + + def test_pythoninspect(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + path = getscript(""" + print 6*7 + """) + child = self.spawn([path]) + child.expect('42') + child.expect('>>> ') + finally: + del os.environ['PYTHONINSPECT_'] + + def test_set_pythoninspect(self): + path = getscript(""" + import os + os.environ['PYTHONINSPECT'] = '1' + print 6*7 + """) + child = self.spawn([path]) + child.expect('42') + child.expect('>>> ') + + def test_clear_pythoninspect(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + path = getscript(""" + import os + del os.environ['PYTHONINSPECT'] + """) + child = self.spawn([path]) + child.expect('>>> ') + finally: + del os.environ['PYTHONINSPECT_'] + + def test_stdout_flushes_before_stdin_blocks(self): + # This doesn't really test app_main.py, but a behavior that + # can only be checked on top of py.py with pexpect. + path = getscript(""" + import sys + sys.stdout.write('Are you suggesting coconuts migrate? ') + line = sys.stdin.readline() + assert line.rstrip() == 'Not at all. They could be carried.' + print 'A five ounce bird could not carry a one pound coconut.' + """) + py_py = os.path.join(pypydir, 'bin', 'pyinteractive.py') + child = self._spawn(sys.executable, [py_py, '-S', path]) + child.expect('Are you suggesting coconuts migrate?', timeout=120) + child.sendline('Not at all. They could be carried.') + child.expect('A five ounce bird could not carry a one pound coconut.') + + def test_no_space_before_argument(self, monkeypatch): + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + child = self.spawn(['-cprint "hel" + "lo"']) + child.expect('hello') + + monkeypatch.chdir(os.path.dirname(app_main)) + child = self.spawn(['-mtest.mymodule']) + child.expect('mymodule running') + + def test_ps1_only_if_interactive(self): + argv = ['-c', 'import sys; print hasattr(sys, "ps1")'] + child = self.spawn(argv) + child.expect('False') + + +class TestNonInteractive: + def run_with_status_code(self, cmdline, senddata='', expect_prompt=False, + expect_banner=False, python_flags='', env=None): + cmdline = '%s %s "%s" %s' % (sys.executable, python_flags, + app_main, cmdline) + print 'POPEN:', cmdline + process = subprocess.Popen( + cmdline, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + shell=True, env=env, + universal_newlines=True + ) + child_in, child_out_err = process.stdin, process.stdout + child_in.write(senddata) + child_in.close() + data = child_out_err.read() + child_out_err.close() + process.wait() + assert (banner in data) == expect_banner # no banner unless expected + assert ('>>> ' in data) == expect_prompt # no prompt unless expected + return data, process.returncode + + def run(self, *args, **kwargs): + data, status = self.run_with_status_code(*args, **kwargs) + return data + + def test_script_on_stdin(self): + for extraargs, expected_argv in [ + ('', ['']), + ('-', ['-']), + ('- hello world', ['-', 'hello', 'world']), + ]: + data = self.run('%s < "%s"' % (extraargs, demo_script)) + assert "hello" in data + assert "Name: __main__" in data + assert "File: " in data + assert ("Exec: " + app_main) in data + assert ("Argv: " + repr(expected_argv)) in data + assert "goodbye" in data + + def test_run_crashing_script(self): + data = self.run('"%s"' % (crashing_demo_script,)) + assert 'Hello2' in data + assert 'NameError' in data + assert 'Goodbye2' not in data + + def test_crashing_script_on_stdin(self): + data = self.run(' < "%s"' % (crashing_demo_script,)) + assert 'Hello2' in data + assert 'NameError' in data + assert 'Goodbye2' not in data + + def test_option_W(self): + data = self.run('-W d -c "print 42"') + assert '42' in data + data = self.run('-Wd -c "print 42"') + assert '42' in data + + def test_option_W_crashing(self): + data = self.run('-W') + assert "Argument expected for the '-W' option" in data + + def test_option_W_arg_ignored(self): + data = self.run('-Wc') + assert "Invalid -W option ignored: invalid action: 'c'" in data + + def test_option_W_arg_ignored2(self): + data = self.run('-W-W') + assert "Invalid -W option ignored: invalid action:" in data + + def test_option_c(self): + data = self.run('-c "print 6**5"') + assert '7776' in data + + def test_no_pythonstartup(self, monkeypatch): + monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) + data = self.run('"%s"' % (demo_script,)) + assert 'Hello2' not in data + data = self.run('-c pass') + assert 'Hello2' not in data + + def test_pythonwarnings(self, monkeypatch): + # PYTHONWARNINGS_ is special cased by app_main: we cannot directly set + # PYTHONWARNINGS because else the warnings raised from within pypy are + # turned in errors. + monkeypatch.setenv('PYTHONWARNINGS_', "once,error") + data = self.run('-W ignore -W default ' + '-c "import sys; print sys.warnoptions"') + assert "['ignore', 'default', 'once', 'error']" in data + + def test_option_m(self, monkeypatch): + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') + p = os.path.abspath(p) + monkeypatch.chdir(os.path.dirname(app_main)) + data = self.run('-m test.mymodule extra') + assert 'mymodule running' in data + assert 'Name: __main__' in data + # ignoring case for windows. abspath behaves different from autopath + # concerning drive letters right now. + assert ('File: ' + p) in data + assert ('Argv: ' + repr([p, 'extra'])) in data + + def test_pythoninspect_doesnt_override_isatty(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + data = self.run('', senddata='6*7\nprint 2+3\n') + assert data == '5\n' + finally: + del os.environ['PYTHONINSPECT_'] + + def test_i_flag_overrides_isatty(self): + data = self.run('-i', senddata='6*7\nraise SystemExit\n', + expect_prompt=True, expect_banner=True) + assert '42\n' in data + # if a file name is passed, the banner is never printed but + # we get a prompt anyway + cmdline = '-i %s' % getscript(""" + print 'hello world' + """) + data = self.run(cmdline, senddata='6*7\nraise SystemExit\n', + expect_prompt=True, expect_banner=False) + assert 'hello world\n' in data + assert '42\n' in data + + def test_option_S_copyright(self): + data = self.run('-S -i', expect_prompt=True, expect_banner=True) + assert 'copyright' not in data + + def test_non_interactive_stdout_fully_buffered(self): + path = getscript(r""" + import sys, time + sys.stdout.write('\x00(STDOUT)\n\x00') # stays in buffers + time.sleep(1) + sys.stderr.write('\x00[STDERR]\n\x00') + time.sleep(1) + # stdout flushed automatically here + """) + cmdline = '%s -u "%s" %s' % (sys.executable, app_main, path) + print 'POPEN:', cmdline + child_in, child_out_err = os.popen4(cmdline) + data = child_out_err.read(11) + assert data == '\x00[STDERR]\n\x00' # from stderr + child_in.close() + data = child_out_err.read(11) + assert data == '\x00(STDOUT)\n\x00' # from stdout + child_out_err.close() + + def test_non_interactive_stdout_unbuffered(self, monkeypatch): + monkeypatch.setenv('PYTHONUNBUFFERED', '1') + path = getscript(r""" + import sys, time + sys.stdout.write('\x00(STDOUT)\n\x00') + time.sleep(1) + sys.stderr.write('\x00[STDERR]\n\x00') + time.sleep(1) + # stdout flushed automatically here + """) + cmdline = '%s -E "%s" %s' % (sys.executable, app_main, path) + print 'POPEN:', cmdline + child_in, child_out_err = os.popen4(cmdline) + data = child_out_err.read(11) + assert data == '\x00(STDOUT)\n\x00' # from stderr + data = child_out_err.read(11) + assert data == '\x00[STDERR]\n\x00' # from stdout + child_out_err.close() + child_in.close() + + def test_proper_sys_path(self, tmpdir): + data = self.run('-c "import _ctypes"', python_flags='-S') + if data.startswith('Traceback'): + py.test.skip("'python -S' cannot import extension modules: " + "see probably http://bugs.python.org/issue586680") + + @contextmanager + def chdir_and_unset_pythonpath(new_cwd): + old_cwd = new_cwd.chdir() + old_pythonpath = os.getenv('PYTHONPATH') + os.unsetenv('PYTHONPATH') + try: + yield + finally: + old_cwd.chdir() + # Can't call putenv with a None argument. + if old_pythonpath is not None: + os.putenv('PYTHONPATH', old_pythonpath) + + tmpdir.join('site.py').write('print "SHOULD NOT RUN"') + runme_py = tmpdir.join('runme.py') + runme_py.write('print "some text"') + + cmdline = str(runme_py) + + with chdir_and_unset_pythonpath(tmpdir): + data = self.run(cmdline, python_flags='-S') + + assert data == "some text\n" + + runme2_py = tmpdir.mkdir('otherpath').join('runme2.py') + runme2_py.write('print "some new text"\n' + 'import sys\n' + 'print sys.path\n') + + cmdline2 = str(runme2_py) + + with chdir_and_unset_pythonpath(tmpdir): + data = self.run(cmdline2, python_flags='-S') + assert data.startswith("some new text\n") + assert repr(str(tmpdir.join('otherpath'))) in data + assert "''" not in data + + data = self.run('-c "import sys; print sys.path"') + assert data.startswith("[''") + + def test_pyc_commandline_argument(self): + p = getscript_pyc(self.space, "print 6*7\n") + assert os.path.isfile(p) and p.endswith('.pyc') + data = self.run(p) + assert data == 'in _run_compiled_module\n' + + def test_main_in_dir_commandline_argument(self): + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + p = getscript_in_dir('import sys; print sys.argv[0]\n') + data = self.run(p) + assert data == p + '\n' + data = self.run(p + os.sep) + assert data == p + os.sep + '\n' + + def test_getfilesystemencoding(self): + py.test.skip("encoding is only set if stdout.isatty(), test is flawed") + if sys.version_info < (2, 7): + skip("test requires Python >= 2.7") + p = getscript_in_dir(""" + import sys + sys.stdout.write(u'15\u20ac') + sys.stdout.flush() + """) + env = os.environ.copy() + env["LC_CTYPE"] = 'en_US.UTF-8' + data = self.run(p, env=env) + assert data == '15\xe2\x82\xac' + + def test_pythonioencoding(self): + if sys.version_info < (2, 7): + skip("test requires Python >= 2.7") + for encoding, expected in [ + ("iso-8859-15", "15\xa4"), + ("utf-8", '15\xe2\x82\xac'), + ("utf-16-le", '1\x005\x00\xac\x20'), + ("iso-8859-1:ignore", "15"), + ("iso-8859-1:replace", "15?"), + ("iso-8859-1:backslashreplace", "15\\u20ac"), + ]: + p = getscript_in_dir(""" + import sys + sys.stdout.write(u'15\u20ac') + sys.stdout.flush() + """) + env = os.environ.copy() + env["PYTHONIOENCODING"] = encoding + data = self.run(p, env=env) + assert data == expected + + def test_sys_exit_pythonioencoding(self): + if sys.version_info < (2, 7): + skip("test required Python >= 2.7") + p = getscript_in_dir(""" + import sys + sys.exit(u'15\u20ac') + """) + env = os.environ.copy() + env["PYTHONIOENCODING"] = "utf-8" + data, status = self.run_with_status_code(p, env=env) + assert status == 1 + assert data.startswith("15\xe2\x82\xac") + + +class TestAppMain: + def test_print_info(self): + from pypy.interpreter import app_main + import sys, cStringIO + prev_so = sys.stdout + prev_ti = getattr(sys, 'pypy_translation_info', 'missing') + sys.pypy_translation_info = { + 'translation.foo': True, + 'translation.bar': 42, + 'translation.egg.something': None, + 'objspace.x': 'hello', + } + try: + sys.stdout = f = cStringIO.StringIO() + py.test.raises(SystemExit, app_main.print_info) + finally: + sys.stdout = prev_so + if prev_ti == 'missing': + del sys.pypy_translation_info + else: + sys.pypy_translation_info = prev_ti + assert f.getvalue() == ("[objspace]\n" + " x = 'hello'\n" + "[translation]\n" + " bar = 42\n" + " [egg]\n" + " something = None\n" + " foo = True\n") + + +class AppTestAppMain: + def setup_class(self): + # ---------------------------------------- + # setup code for test_setup_bootstrap_path + # ---------------------------------------- + from pypy.module.sys.version import CPYTHON_VERSION, PYPY_VERSION + cpy_ver = '%d.%d' % CPYTHON_VERSION[:2] + + goal_dir = os.path.dirname(app_main) + # build a directory hierarchy like which contains both bin/pypy-c and + # lib/pypy1.2/* + prefix = udir.join('pathtest').ensure(dir=1) + fake_exe = 'bin/pypy-c' + if sys.platform == 'win32': + fake_exe += '.exe' + fake_exe = prefix.join(fake_exe).ensure(file=1) + expected_path = [str(prefix.join(subdir).ensure(dir=1)) + for subdir in ('lib_pypy', + 'lib-python/%s' % cpy_ver)] + + self.w_goal_dir = self.space.wrap(goal_dir) + self.w_fake_exe = self.space.wrap(str(fake_exe)) + self.w_expected_path = self.space.wrap(expected_path) + self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir)) + + foo_py = prefix.join('foo.py').write("pass") + self.w_foo_py = self.space.wrap(str(foo_py)) + + def test_setup_bootstrap_path(self): + import sys + old_sys_path = sys.path[:] + sys.path.append(self.goal_dir) + try: + import app_main + app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found + assert sys.executable == '' + assert sys.path == old_sys_path + [self.goal_dir] + + app_main.setup_bootstrap_path(self.fake_exe) + assert sys.executable == self.fake_exe + assert self.goal_dir not in sys.path + + newpath = sys.path[:] + 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 + finally: + sys.path[:] = old_sys_path + + def test_trunk_can_be_prefix(self): + import sys + import os + old_sys_path = sys.path[:] + sys.path.append(self.goal_dir) + try: + import app_main + pypy_c = os.path.join(self.trunkdir, 'pypy', 'goal', 'pypy-c') + app_main.setup_bootstrap_path(pypy_c) + newpath = sys.path[:] + # we get at least lib_pypy + # lib-python/X.Y.Z, and maybe more (e.g. plat-linux2) + assert len(newpath) >= 2 + for p in newpath: + assert p.startswith(self.trunkdir) + finally: + sys.path[:] = old_sys_path + + def test_entry_point(self): + import sys + import os + old_sys_path = sys.path[:] + sys.path.append(self.goal_dir) + try: + import app_main + pypy_c = os.path.join(self.trunkdir, 'pypy', 'goal', 'pypy-c') + app_main.entry_point(pypy_c, [self.foo_py]) + # assert it did not crash + finally: + sys.path[:] = old_sys_path diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -135,18 +135,39 @@ def test_interpindirect2app(self): space = self.space + class BaseA(W_Root): def method(self, space, x): + "This is a method" + pass + + def method_with_default(self, space, x=5): + pass + + @gateway.unwrap_spec(x=int) + def method_with_unwrap_spec(self, space, x): pass class A(BaseA): def method(self, space, x): return space.wrap(x + 2) + def method_with_default(self, space, x): + return space.wrap(x + 2) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 2) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) + def method_with_default(self, space, x): + return space.wrap(x + 1) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 1) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -163,6 +184,23 @@ assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2 assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1 + doc = space.str_w(space.getattr(w_c, space.wrap('__doc__'))) + assert doc == "This is a method" + + meth_with_default = gateway.interpindirect2app( + BaseA.method_with_default, {'x': int}) + w_d = space.wrap(meth_with_default) + + assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2 + assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1 + assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2 + assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1 + + meth_with_unwrap_spec = gateway.interpindirect2app( + BaseA.method_with_unwrap_spec) + w_e = space.wrap(meth_with_unwrap_spec) + assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2 + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py new file mode 100644 --- /dev/null +++ b/pypy/interpreter/test/test_targetpypy.py @@ -0,0 +1,18 @@ +from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point +from pypy.config.pypyoption import get_pypy_config + +class TestTargetPyPy(object): + def test_run(self): + config = get_pypy_config(translating=False) + entry_point = get_entry_point(config)[0] + entry_point(['pypy-c' , '-S', '-c', 'print 3']) + +def test_exeucte_source(space): + _, execute_source = create_entry_point(space, None) + execute_source("import sys; sys.modules['xyz'] = 3") + x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'], + space.wrap('modules')), + space.wrap('xyz'))) + assert x == 3 + execute_source("sys") + # did not crash - the same globals diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py --- a/pypy/interpreter/test/test_zzpickle_and_slow.py +++ b/pypy/interpreter/test/test_zzpickle_and_slow.py @@ -485,3 +485,68 @@ pckl = pickle.dumps(pack.mod) result = pickle.loads(pckl) assert pack.mod is result + + +class AppTestGeneratorCloning: + + def setup_class(cls): + try: + cls.space.appexec([], """(): + def f(): yield 42 + f().__reduce__() + """) + except TypeError, e: + if 'pickle generator' not in str(e): + raise + py.test.skip("Frames can't be __reduce__()-ed") + + def test_deepcopy_generator(self): + import copy + + def f(n): + for i in range(n): + yield 42 + i + g = f(4) + g2 = copy.deepcopy(g) + res = g.next() + assert res == 42 + res = g2.next() + assert res == 42 + g3 = copy.deepcopy(g) + res = g.next() + assert res == 43 + res = g2.next() + assert res == 43 + res = g3.next() + assert res == 43 + + def test_shallowcopy_generator(self): + """Note: shallow copies of generators are often confusing. + To start with, 'for' loops have an iterator that will not + be copied, and so create tons of confusion. + """ + import copy + + def f(n): + while n > 0: + yield 42 + n + n -= 1 + g = f(2) + g2 = copy.copy(g) + res = g.next() + assert res == 44 + res = g2.next() + assert res == 44 + g3 = copy.copy(g) + res = g.next() + assert res == 43 + res = g2.next() + assert res == 43 + res = g3.next() + assert res == 43 + g4 = copy.copy(g2) + for i in range(2): + raises(StopIteration, g.next) + raises(StopIteration, g2.next) + raises(StopIteration, g3.next) + raises(StopIteration, g4.next) diff --git a/pypy/interpreter/test2/__init__.py b/pypy/interpreter/test2/__init__.py deleted file mode 100644 --- a/pypy/interpreter/test2/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -#empty diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test2/test_app_main.py deleted file mode 100644 --- a/pypy/interpreter/test2/test_app_main.py +++ /dev/null @@ -1,966 +0,0 @@ -""" -Tests for the entry point of pypy-c, app_main.py. -""" -from __future__ import with_statement -import py -import sys, os, re, runpy, subprocess -from rpython.tool.udir import udir -from contextlib import contextmanager -from pypy.conftest import pypydir - -banner = sys.version.splitlines()[0] - -app_main = os.path.join(os.path.realpath(os.path.dirname(__file__)), os.pardir, 'app_main.py') -app_main = os.path.abspath(app_main) - -_counter = 0 -def _get_next_path(ext='.py'): - global _counter - p = udir.join('demo_test_app_main_%d%s' % (_counter, ext)) - _counter += 1 - return p - -def getscript(source): - p = _get_next_path() - p.write(str(py.code.Source(source))) - return str(p) - -def getscript_pyc(space, source): - p = _get_next_path() - p.write(str(py.code.Source(source))) - w_dir = space.wrap(str(p.dirpath())) - w_modname = space.wrap(p.purebasename) - space.appexec([w_dir, w_modname], """(dir, modname): - import sys - d = sys.modules.copy() - sys.path.insert(0, dir) - __import__(modname) - sys.path.pop(0) - for key in sys.modules.keys(): - if key not in d: - del sys.modules[key] - """) - p = str(p) + 'c' - assert os.path.isfile(p) # the .pyc file should have been created above - return p - -def getscript_in_dir(source): - pdir = _get_next_path(ext='') - p = pdir.ensure(dir=1).join('__main__.py') - p.write(str(py.code.Source(source))) - # return relative path for testing purposes - return py.path.local().bestrelpath(pdir) - -demo_script = getscript(""" - print 'hello' - print 'Name:', __name__ - print 'File:', __file__ - import sys - print 'Exec:', sys.executable - print 'Argv:', sys.argv - print 'goodbye' - myvalue = 6*7 - """) - -crashing_demo_script = getscript(""" - print 'Hello2' - myvalue2 = 11 - ooups - myvalue2 = 22 - print 'Goodbye2' # should not be reached - """) - - -class TestParseCommandLine: - def check_options(self, options, sys_argv, **expected): - assert sys.argv == sys_argv - for key, value in expected.items(): - assert options[key] == value - for key, value in options.items(): - if key not in expected: - assert not value, ( - "option %r has unexpectedly the value %r" % (key, value)) - - def check(self, argv, env, **expected): - import StringIO - from pypy.interpreter import app_main - saved_env = os.environ.copy() - saved_sys_argv = sys.argv[:] - saved_sys_stdout = sys.stdout - saved_sys_stderr = sys.stdout - app_main.os = os - try: - os.environ.update(env) - sys.stdout = sys.stderr = StringIO.StringIO() - try: - options = app_main.parse_command_line(argv) - except SystemExit: - output = expected['output_contains'] - assert output in sys.stdout.getvalue() - else: - self.check_options(options, **expected) - finally: - os.environ.clear() - os.environ.update(saved_env) - sys.argv[:] = saved_sys_argv - sys.stdout = saved_sys_stdout - sys.stderr = saved_sys_stderr - - def test_all_combinations_I_can_think_of(self): - self.check([], {}, sys_argv=[''], run_stdin=True) - self.check(['-'], {}, sys_argv=['-'], run_stdin=True) - self.check(['-S'], {}, sys_argv=[''], run_stdin=True, no_site=1) - self.check(['-OO'], {}, sys_argv=[''], run_stdin=True, optimize=2) - self.check(['-O', '-O'], {}, sys_argv=[''], run_stdin=True, optimize=2) - self.check(['-Qnew'], {}, sys_argv=[''], run_stdin=True, division_new=1) - self.check(['-Qold'], {}, sys_argv=[''], run_stdin=True, division_new=0) - self.check(['-Qwarn'], {}, sys_argv=[''], run_stdin=True, division_warning=1) - self.check(['-Qwarnall'], {}, sys_argv=[''], run_stdin=True, - division_warning=2) - self.check(['-Q', 'new'], {}, sys_argv=[''], run_stdin=True, division_new=1) - self.check(['-SOQnew'], {}, sys_argv=[''], run_stdin=True, - no_site=1, optimize=1, division_new=1) - self.check(['-SOQ', 'new'], {}, sys_argv=[''], run_stdin=True, - no_site=1, optimize=1, division_new=1) - self.check(['-i'], {}, sys_argv=[''], run_stdin=True, - interactive=1, inspect=1) - self.check(['-?'], {}, output_contains='usage:') - self.check(['-h'], {}, output_contains='usage:') - self.check(['-S', '-tO', '-h'], {}, output_contains='usage:') - self.check(['-S', '-thO'], {}, output_contains='usage:') - self.check(['-S', '-tO', '--help'], {}, output_contains='usage:') - self.check(['-S', '-tO', '--info'], {}, output_contains='translation') - self.check(['-S', '-tO', '--version'], {}, output_contains='Python') - self.check(['-S', '-tOV'], {}, output_contains='Python') - self.check(['--jit', 'foobar', '-S'], {}, sys_argv=[''], - run_stdin=True, no_site=1) - self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass') - self.check(['-cpass'], {}, sys_argv=['-c'], run_command='pass') - self.check(['-cpass','x'], {}, sys_argv=['-c','x'], run_command='pass') - self.check(['-Sc', 'pass'], {}, sys_argv=['-c'], run_command='pass', - no_site=1) - self.check(['-Scpass'], {}, sys_argv=['-c'], run_command='pass', no_site=1) - self.check(['-c', '', ''], {}, sys_argv=['-c', ''], run_command='') - self.check(['-mfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True) - self.check(['-m', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True) - self.check(['-Smfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True, no_site=1) - self.check(['-Sm', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True, no_site=1) - self.check(['-', 'foo', 'bar'], {}, sys_argv=['-', 'foo', 'bar'], - run_stdin=True) - self.check(['foo', 'bar'], {}, sys_argv=['foo', 'bar']) - self.check(['foo', '-i'], {}, sys_argv=['foo', '-i']) - self.check(['-i', 'foo'], {}, sys_argv=['foo'], interactive=1, inspect=1) - self.check(['--', 'foo'], {}, sys_argv=['foo']) - self.check(['--', '-i', 'foo'], {}, sys_argv=['-i', 'foo']) - self.check(['--', '-', 'foo'], {}, sys_argv=['-', 'foo'], run_stdin=True) - self.check(['-Wbog'], {}, sys_argv=[''], warnoptions=['bog'], run_stdin=True) - self.check(['-W', 'ab', '-SWc'], {}, sys_argv=[''], warnoptions=['ab', 'c'], - run_stdin=True, no_site=1) - - self.check([], {'PYTHONDEBUG': '1'}, sys_argv=[''], run_stdin=True, debug=1) - self.check([], {'PYTHONDONTWRITEBYTECODE': '1'}, sys_argv=[''], run_stdin=True, dont_write_bytecode=1) - self.check([], {'PYTHONNOUSERSITE': '1'}, sys_argv=[''], run_stdin=True, no_user_site=1) - self.check([], {'PYTHONUNBUFFERED': '1'}, sys_argv=[''], run_stdin=True, unbuffered=1) - self.check([], {'PYTHONVERBOSE': '1'}, sys_argv=[''], run_stdin=True, verbose=1) - - def test_sysflags(self): - flags = ( - ("debug", "-d", "1"), - ("py3k_warning", "-3", "1"), - ("division_warning", "-Qwarn", "1"), - ("division_warning", "-Qwarnall", "2"), - ("division_new", "-Qnew", "1"), - (["inspect", "interactive"], "-i", "1"), - ("optimize", "-O", "1"), - ("optimize", "-OO", "2"), - ("dont_write_bytecode", "-B", "1"), - ("no_user_site", "-s", "1"), - ("no_site", "-S", "1"), - ("ignore_environment", "-E", "1"), - ("tabcheck", "-t", "1"), - ("tabcheck", "-tt", "2"), - ("verbose", "-v", "1"), - ("unicode", "-U", "1"), - ("bytes_warning", "-b", "1"), - ) - for flag, opt, value in flags: - if isinstance(flag, list): # this is for inspect&interactive - expected = {} - for flag1 in flag: - expected[flag1] = int(value) - else: - expected = {flag: int(value)} - self.check([opt, '-c', 'pass'], {}, sys_argv=['-c'], - run_command='pass', **expected) - - def test_sysflags_envvar(self, monkeypatch): - monkeypatch.setenv('PYTHONNOUSERSITE', '1') - expected = {"no_user_site": True} - self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass', **expected) - - -class TestInteraction: - """ - These tests require pexpect (UNIX-only). - http://pexpect.sourceforge.net/ - """ - def _spawn(self, *args, **kwds): - try: - import pexpect - except ImportError, e: - py.test.skip(str(e)) - else: - # Version is of the style "0.999" or "2.1". Older versions of - # pexpect try to get the fileno of stdin, which generally won't - # work with py.test (due to sys.stdin being a DontReadFromInput - # instance). - version = map(int, pexpect.__version__.split('.')) - - # I only tested 0.999 and 2.1. The former does not work, the - # latter does. Feel free to refine this measurement. - # -exarkun, 17/12/2007 - if version < [2, 1]: - py.test.skip( - "pexpect version too old, requires 2.1 or newer: %r" % ( - pexpect.__version__,)) - - kwds.setdefault('timeout', 10) - print 'SPAWN:', ' '.join([args[0]] + args[1]), kwds - child = pexpect.spawn(*args, **kwds) - child.logfile = sys.stdout - return child - - def spawn(self, argv): - return self._spawn(sys.executable, [app_main] + argv) - - def test_interactive(self): - child = self.spawn([]) - child.expect('Python ') # banner - child.expect('>>> ') # prompt - child.sendline('[6*7]') - child.expect(re.escape('[42]')) - child.sendline('def f(x):') - child.expect(re.escape('... ')) - child.sendline(' return x + 100') - child.expect(re.escape('... ')) - child.sendline('') - child.expect('>>> ') - child.sendline('f(98)') - child.expect('198') - child.expect('>>> ') - child.sendline('__name__') - child.expect("'__main__'") - child.expect('>>> ') - child.sendline('import sys') - child.expect('>>> ') - child.sendline("'' in sys.path") - child.expect("True") - - def test_help(self): - # test that -h prints the usage, including the name of the executable - # which should be /full/path/to/app_main.py in this case - child = self.spawn(['-h']) - child.expect(r'usage: .*app_main.py \[option\]') - child.expect('PyPy options and arguments:') - - def test_run_script(self): - child = self.spawn([demo_script]) - idx = child.expect(['hello', 'Python ', '>>> ']) - assert idx == 0 # no banner or prompt - child.expect(re.escape("Name: __main__")) - child.expect(re.escape('File: ' + demo_script)) - child.expect(re.escape('Exec: ' + app_main)) - child.expect(re.escape('Argv: ' + repr([demo_script]))) - child.expect('goodbye') - - def test_run_script_with_args(self): - argv = [demo_script, 'hello', 'world'] - child = self.spawn(argv) - child.expect(re.escape('Argv: ' + repr(argv))) - child.expect('goodbye') - - def test_no_such_script(self): - import errno - msg = os.strerror(errno.ENOENT) # 'No such file or directory' - child = self.spawn(['xxx-no-such-file-xxx']) - child.expect(re.escape(msg)) - - def test_option_i(self): - argv = [demo_script, 'foo', 'bar'] - child = self.spawn(['-i'] + argv) - idx = child.expect(['hello', re.escape(banner)]) - assert idx == 0 # no banner - child.expect(re.escape('File: ' + demo_script)) - child.expect(re.escape('Argv: ' + repr(argv))) - child.expect('goodbye') - idx = child.expect(['>>> ', re.escape(banner)]) - assert idx == 0 # prompt, but still no banner - child.sendline('myvalue * 102') - child.expect('4284') - child.sendline('__name__') - child.expect('__main__') - - def test_option_i_crashing(self): - argv = [crashing_demo_script, 'foo', 'bar'] - child = self.spawn(['-i'] + argv) - idx = child.expect(['Hello2', re.escape(banner)]) - assert idx == 0 # no banner - child.expect('NameError') - child.sendline('myvalue2 * 1001') - child.expect('11011') - child.sendline('import sys; sys.argv') - child.expect(re.escape(repr(argv))) - child.sendline('sys.last_type.__name__') - child.expect(re.escape(repr('NameError'))) - - def test_options_i_c(self): - child = self.spawn(['-i', '-c', 'x=555']) - idx = child.expect(['>>> ', re.escape(banner)]) - assert idx == 0 # prompt, but no banner - child.sendline('x') - child.expect('555') - child.sendline('__name__') - child.expect('__main__') - child.sendline('import sys; sys.argv') - child.expect(re.escape("['-c']")) - - def test_options_i_c_crashing(self, monkeypatch): - monkeypatch.setenv('PYTHONPATH', None) - child = self.spawn(['-i', '-c', 'x=666;foobar']) - child.expect('NameError') - idx = child.expect(['>>> ', re.escape(banner)]) - assert idx == 0 # prompt, but no banner - child.sendline('x') - child.expect('666') - child.sendline('__name__') - child.expect('__main__') - child.sendline('import sys; sys.argv') - child.expect(re.escape("['-c']")) - child.sendline('sys.last_type.__name__') - child.expect(re.escape(repr('NameError'))) - - def test_atexit(self): - child = self.spawn([]) - child.expect('>>> ') - child.sendline('def f(): print "foobye"') - child.sendline('') - child.sendline('import atexit; atexit.register(f)') - child.sendline('6*7') - child.expect('42') - # pexpect's sendeof() is confused by py.test capturing, though - # I think that it is a bug of sendeof() - old = sys.stdin - try: - sys.stdin = child - child.sendeof() - finally: - sys.stdin = old - child.expect('foobye') - - def test_pythonstartup(self, monkeypatch): - monkeypatch.setenv('PYTHONPATH', None) - monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) - child = self.spawn([]) - child.expect(re.escape(banner)) - child.expect('Traceback') - child.expect('NameError') - child.expect('>>> ') - child.sendline('[myvalue2]') - child.expect(re.escape('[11]')) - child.expect('>>> ') - - child = self.spawn(['-i', demo_script]) - for line in ['hello', 'goodbye', '>>> ']: - idx = child.expect([line, 'Hello2']) - assert idx == 0 # no PYTHONSTARTUP run here - child.sendline('myvalue2') - child.expect('Traceback') - child.expect('NameError') - - def test_pythonstartup_file1(self, monkeypatch): - monkeypatch.setenv('PYTHONPATH', None) - monkeypatch.setenv('PYTHONSTARTUP', demo_script) - child = self.spawn([]) - child.expect('File: [^\n]+\.py') - child.expect('goodbye') - child.expect('>>> ') - child.sendline('[myvalue]') - child.expect(re.escape('[42]')) - child.expect('>>> ') - child.sendline('__file__') - child.expect('Traceback') - child.expect('NameError') - - def test_pythonstartup_file2(self, monkeypatch): - monkeypatch.setenv('PYTHONPATH', None) - monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) - child = self.spawn([]) - child.expect('Traceback') - child.expect('>>> ') - child.sendline('__file__') - child.expect('Traceback') - child.expect('NameError') - - def test_ignore_python_startup(self): - old = os.environ.get('PYTHONSTARTUP', '') - try: - os.environ['PYTHONSTARTUP'] = crashing_demo_script - child = self.spawn(['-E']) From noreply at buildbot.pypy.org Mon May 13 19:17:20 2013 From: noreply at buildbot.pypy.org (senyai) Date: Mon, 13 May 2013 19:17:20 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Donation sidebar fix for ie Message-ID: <20130513171720.127471C00F4@cobra.cs.uni-duesseldorf.de> Author: Arseniy Terekhin Branch: extradoc Changeset: r426:760313371d05 Date: 2013-04-21 18:32 +0400 http://bitbucket.org/pypy/pypy.org/changeset/760313371d05/ Log: Donation sidebar fix for ie diff --git a/js/script2.js b/js/script2.js --- a/js/script2.js +++ b/js/script2.js @@ -1,28 +1,21 @@ +function set_sidebar_html(html) { + $("#sidebar").html(html); +} function py3k_donate() { - $.get("don1.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don1.html", set_sidebar_html); } function stm_donate() { - $.get("don4.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don4.html", set_sidebar_html); } function general_donate() { - $.get("don2.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don2.html", set_sidebar_html); } function numpy_donate() { - $.get("don3.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don3.html", set_sidebar_html); } -$(document).ready(function() { - stm_donate(); -}); \ No newline at end of file +$(document).ready(stm_donate); From noreply at buildbot.pypy.org Mon May 13 19:17:21 2013 From: noreply at buildbot.pypy.org (senyai) Date: Mon, 13 May 2013 19:17:21 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Removed useless script (detect.js) Message-ID: <20130513171721.303DD1C00F4@cobra.cs.uni-duesseldorf.de> Author: Arseniy Terekhin Branch: extradoc Changeset: r427:3ce1961ea849 Date: 2013-04-21 18:42 +0400 http://bitbucket.org/pypy/pypy.org/changeset/3ce1961ea849/ Log: Removed useless script (detect.js) diff --git a/js/detect.js b/js/detect.js deleted file mode 100644 --- a/js/detect.js +++ /dev/null @@ -1,25 +0,0 @@ - -$(document).ready(function() { - var download_url, download_text; - var base = 'https://bitbucket.org/pypy/pypy/downloads/'; - if (navigator.platform.indexOf('Linux') != -1) { - if (navigator.platform.indexOf('64') != -1) { - download_url = base + 'pypy-1.7-linux64.tar.bz2'; - download_text = 'Download linux x86-64 bin'; - } else { - download_url = base + 'pypy-1.7-linux.tar.bz2'; - download_text = 'Download linux x86 bin (32 bit)'; - } - } else if (navigator.platform.indexOf('Win') != -1) { - download_url = base + 'pypy-1.7-win32.zip'; - download_text = 'Download Windows x86 bin (BETA)'; - } else if (navigator.platform.indexOf('Mac') != 1) { - download_url = base + 'pypy-1.7-osx64.tar.bz2'; - download_text = 'Download Mac OS X 10.6 bin (64 bit)'; - } else { - download_url = "download.html"; - download_text = "Download page"; - } - $("#main_download").attr('href', download_url); - $("#main_download").text(download_text); -}); diff --git a/source/_layouts/site.genshi b/source/_layouts/site.genshi --- a/source/_layouts/site.genshi +++ b/source/_layouts/site.genshi @@ -46,7 +46,6 @@ From noreply at buildbot.pypy.org Mon May 13 19:17:22 2013 From: noreply at buildbot.pypy.org (senyai) Date: Mon, 13 May 2013 19:17:22 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Menu padding (as logo) Message-ID: <20130513171722.5125E1C00F4@cobra.cs.uni-duesseldorf.de> Author: Arseniy Terekhin Branch: extradoc Changeset: r428:e0901e09d0c9 Date: 2013-04-21 20:29 +0400 http://bitbucket.org/pypy/pypy.org/changeset/e0901e09d0c9/ Log: Menu padding (as logo) diff --git a/css/site.css b/css/site.css --- a/css/site.css +++ b/css/site.css @@ -353,6 +353,7 @@ #menu-follow { float: right; + margin-top: 17px; } #menu-follow div { From noreply at buildbot.pypy.org Mon May 13 19:17:23 2013 From: noreply at buildbot.pypy.org (senyai) Date: Mon, 13 May 2013 19:17:23 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Do not wrap menu items, space between menu lines. Message-ID: <20130513171723.7F2141C00F4@cobra.cs.uni-duesseldorf.de> Author: Arseniy Terekhin Branch: extradoc Changeset: r429:a7aa0843cf10 Date: 2013-04-21 20:51 +0400 http://bitbucket.org/pypy/pypy.org/changeset/a7aa0843cf10/ Log: Do not wrap menu items, space between menu lines. diff --git a/css/site.css b/css/site.css --- a/css/site.css +++ b/css/site.css @@ -380,6 +380,11 @@ font-size: 1em; padding-bottom: 10px; text-align: center; + line-height:1.75em; +} + +#menu-sub a{ + white-space: nowrap; } .menu-sub-sep { From noreply at buildbot.pypy.org Mon May 13 19:17:24 2013 From: noreply at buildbot.pypy.org (senyai) Date: Mon, 13 May 2013 19:17:24 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: html output Message-ID: <20130513171724.7EB661C00F4@cobra.cs.uni-duesseldorf.de> Author: Arseniy Terekhin Branch: extradoc Changeset: r430:a0d457ed3d19 Date: 2013-04-21 20:53 +0400 http://bitbucket.org/pypy/pypy.org/changeset/a0d457ed3d19/ Log: html output diff --git a/archive.html b/archive.html --- a/archive.html +++ b/archive.html @@ -15,7 +15,6 @@ - diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -15,7 +15,6 @@ - diff --git a/contact.html b/contact.html --- a/contact.html +++ b/contact.html @@ -15,7 +15,6 @@ - diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -15,7 +15,6 @@ - diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -15,7 +15,6 @@ - diff --git a/howtohelp.html b/howtohelp.html --- a/howtohelp.html +++ b/howtohelp.html @@ -15,7 +15,6 @@ - diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -15,7 +15,6 @@ - diff --git a/numpydonate.html b/numpydonate.html --- a/numpydonate.html +++ b/numpydonate.html @@ -15,7 +15,6 @@ - diff --git a/people.html b/people.html --- a/people.html +++ b/people.html @@ -15,7 +15,6 @@ - diff --git a/performance.html b/performance.html --- a/performance.html +++ b/performance.html @@ -15,7 +15,6 @@ - diff --git a/py3donate.html b/py3donate.html --- a/py3donate.html +++ b/py3donate.html @@ -15,7 +15,6 @@ - diff --git a/sponsor.html b/sponsor.html --- a/sponsor.html +++ b/sponsor.html @@ -15,7 +15,6 @@ - diff --git a/success.html b/success.html --- a/success.html +++ b/success.html @@ -15,7 +15,6 @@ - diff --git a/tmdonate.html b/tmdonate.html --- a/tmdonate.html +++ b/tmdonate.html @@ -15,7 +15,6 @@ - From noreply at buildbot.pypy.org Mon May 13 19:17:25 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 13 May 2013 19:17:25 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Merged in senyai/pypy.org (pull request #7) Message-ID: <20130513171725.852431C00F4@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: extradoc Changeset: r431:31ccaaf58db0 Date: 2013-05-13 10:16 -0700 http://bitbucket.org/pypy/pypy.org/changeset/31ccaaf58db0/ Log: Merged in senyai/pypy.org (pull request #7) IE fix, better looking menu diff --git a/archive.html b/archive.html --- a/archive.html +++ b/archive.html @@ -15,7 +15,6 @@ - diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -15,7 +15,6 @@ - diff --git a/contact.html b/contact.html --- a/contact.html +++ b/contact.html @@ -15,7 +15,6 @@ - diff --git a/css/site.css b/css/site.css --- a/css/site.css +++ b/css/site.css @@ -353,6 +353,7 @@ #menu-follow { float: right; + margin-top: 17px; } #menu-follow div { @@ -379,6 +380,11 @@ font-size: 1em; padding-bottom: 10px; text-align: center; + line-height:1.75em; +} + +#menu-sub a{ + white-space: nowrap; } .menu-sub-sep { diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -15,7 +15,6 @@ - diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -15,7 +15,6 @@ - diff --git a/howtohelp.html b/howtohelp.html --- a/howtohelp.html +++ b/howtohelp.html @@ -15,7 +15,6 @@ - diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -15,7 +15,6 @@ - diff --git a/js/detect.js b/js/detect.js deleted file mode 100644 --- a/js/detect.js +++ /dev/null @@ -1,25 +0,0 @@ - -$(document).ready(function() { - var download_url, download_text; - var base = 'https://bitbucket.org/pypy/pypy/downloads/'; - if (navigator.platform.indexOf('Linux') != -1) { - if (navigator.platform.indexOf('64') != -1) { - download_url = base + 'pypy-1.7-linux64.tar.bz2'; - download_text = 'Download linux x86-64 bin'; - } else { - download_url = base + 'pypy-1.7-linux.tar.bz2'; - download_text = 'Download linux x86 bin (32 bit)'; - } - } else if (navigator.platform.indexOf('Win') != -1) { - download_url = base + 'pypy-1.7-win32.zip'; - download_text = 'Download Windows x86 bin (BETA)'; - } else if (navigator.platform.indexOf('Mac') != 1) { - download_url = base + 'pypy-1.7-osx64.tar.bz2'; - download_text = 'Download Mac OS X 10.6 bin (64 bit)'; - } else { - download_url = "download.html"; - download_text = "Download page"; - } - $("#main_download").attr('href', download_url); - $("#main_download").text(download_text); -}); diff --git a/js/script2.js b/js/script2.js --- a/js/script2.js +++ b/js/script2.js @@ -1,28 +1,21 @@ +function set_sidebar_html(html) { + $("#sidebar").html(html); +} function py3k_donate() { - $.get("don1.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don1.html", set_sidebar_html); } function stm_donate() { - $.get("don4.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don4.html", set_sidebar_html); } function general_donate() { - $.get("don2.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don2.html", set_sidebar_html); } function numpy_donate() { - $.get("don3.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don3.html", set_sidebar_html); } -$(document).ready(function() { - stm_donate(); -}); \ No newline at end of file +$(document).ready(stm_donate); diff --git a/numpydonate.html b/numpydonate.html --- a/numpydonate.html +++ b/numpydonate.html @@ -15,7 +15,6 @@ - diff --git a/people.html b/people.html --- a/people.html +++ b/people.html @@ -15,7 +15,6 @@ - diff --git a/performance.html b/performance.html --- a/performance.html +++ b/performance.html @@ -15,7 +15,6 @@ - diff --git a/py3donate.html b/py3donate.html --- a/py3donate.html +++ b/py3donate.html @@ -15,7 +15,6 @@ - diff --git a/source/_layouts/site.genshi b/source/_layouts/site.genshi --- a/source/_layouts/site.genshi +++ b/source/_layouts/site.genshi @@ -46,7 +46,6 @@ diff --git a/sponsor.html b/sponsor.html --- a/sponsor.html +++ b/sponsor.html @@ -15,7 +15,6 @@ - diff --git a/success.html b/success.html --- a/success.html +++ b/success.html @@ -15,7 +15,6 @@ - diff --git a/tmdonate.html b/tmdonate.html --- a/tmdonate.html +++ b/tmdonate.html @@ -15,7 +15,6 @@ - From noreply at buildbot.pypy.org Mon May 13 19:51:20 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 13 May 2013 19:51:20 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix translation Message-ID: <20130513175120.769491C009D@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64038:111b6f1d63f4 Date: 2013-05-13 10:50 -0700 http://bitbucket.org/pypy/pypy/changeset/111b6f1d63f4/ Log: fix translation diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1395,7 +1395,8 @@ return space.newtuple([w_new_inst, w_args, w_state]) def descr_setstate(self, space, w_state): - self.operr = OperationError(*space.fixedview(w_state, 3)) + w_type, w_value, w_tb = space.fixedview(w_state, 3) + self.operr = OperationError(w_type, w_value, w_tb) def source_as_str(space, w_source, funcname, what, flags): """Return source code as str0 with adjusted compiler flags From noreply at buildbot.pypy.org Mon May 13 19:51:58 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Mon, 13 May 2013 19:51:58 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Add a numarray test for subarrays. Message-ID: <20130513175158.0B7D91C009D@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64039:41899867e728 Date: 2013-05-13 19:50 +0200 http://bitbucket.org/pypy/pypy/changeset/41899867e728/ Log: Add a numarray test for subarrays. diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2699,6 +2699,15 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5])], dtype=d) + + assert a[0]["x"] == [1, 2, 3].all() + assert a[1]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5].all() + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): From noreply at buildbot.pypy.org Mon May 13 19:51:59 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Mon, 13 May 2013 19:51:59 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Start to make VoidType subarray friendly Message-ID: <20130513175159.40BFD1C009D@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64040:3acd856274de Date: 2013-05-13 19:51 +0200 http://bitbucket.org/pypy/pypy/changeset/3acd856274de/ Log: Start to make VoidType subarray friendly diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1700,6 +1700,24 @@ class VoidType(BaseType, BaseStringType): T = lltype.Char + def coerce(self, space, dtype, w_items): + items_w = space.fixedview(w_items) + arr = VoidBoxStorage(self.size, dtype) + ofs = 0 + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + NonNativeVoidType = VoidType NonNativeStringType = StringType From noreply at buildbot.pypy.org Mon May 13 19:56:04 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 19:56:04 +0200 (CEST) Subject: [pypy-commit] pypy default: improve error reporting Message-ID: <20130513175604.0F6331C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64041:082d3fee772a Date: 2013-05-13 19:54 +0200 http://bitbucket.org/pypy/pypy/changeset/082d3fee772a/ Log: improve error reporting diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -79,16 +79,19 @@ # should be used as sparsely as possible, just to register callbacks from rpython.rlib.entrypoint import entrypoint - from rpython.rtyper.lltypesystem import rffi + from rpython.rtyper.lltypesystem import rffi, lltype - @entrypoint('main', [rffi.CCHARP], c_name='pypy_setup_home') - def pypy_setup_home(ll_home): + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') + def pypy_setup_home(ll_home, verbose): from pypy.module.sys.initpath import pypy_find_stdlib if ll_home: home = rffi.charp2str(ll_home) else: home = pypydir - pypy_find_stdlib(space, home) + if space.is_none(pypy_find_stdlib(space, home)): + if verbose: + debug("Failed to find library based on pypy_find_stdlib") + return 1 space.startup() # import site try: @@ -96,7 +99,11 @@ space.wrap('__import__')) space.call_function(import_, space.wrap('site')) return 0 - except OperationError: + except OperationError, e: + if verbose: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py --- a/pypy/interpreter/test/test_targetpypy.py +++ b/pypy/interpreter/test/test_targetpypy.py @@ -24,5 +24,5 @@ # did not crash - the same globals pypy_setup_home = d['pypy_setup_home'] lls = rffi.str2charp(__file__) - pypy_setup_home(lls) + pypy_setup_home(lls, 1) lltype.free(lls, flavor='raw') From noreply at buildbot.pypy.org Mon May 13 19:56:05 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 19:56:05 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130513175605.449391C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64042:259bdfb96071 Date: 2013-05-13 19:55 +0200 http://bitbucket.org/pypy/pypy/changeset/259bdfb96071/ Log: merge diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -8,7 +8,9 @@ arch = 'linux' cmd = 'wget "%s"' tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" -if sys.platform.startswith('darwin'): + if os.uname()[-1].startswith('arm'): + arch += '-armhf-raspbian' +elif sys.platform.startswith('darwin'): arch = 'osx' cmd = 'curl -O "%s"' tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" From noreply at buildbot.pypy.org Mon May 13 21:23:55 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 21:23:55 +0200 (CEST) Subject: [pypy-commit] pypy default: kill the specialization here Message-ID: <20130513192355.E5D0F1C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64043:5aeca6395228 Date: 2013-05-13 21:23 +0200 http://bitbucket.org/pypy/pypy/changeset/5aeca6395228/ Log: kill the specialization here diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -548,7 +548,6 @@ [name.startswith("w_") for name in names]))) fatal_value = callable.api_func.restype._defl() - @specialize.ll() def wrapper(*args): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference From noreply at buildbot.pypy.org Mon May 13 21:56:39 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 21:56:39 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: Oops (thanks amaury) Message-ID: <20130513195639.522AC1C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64044:ead38baf8c3e Date: 2013-05-13 21:56 +0200 http://bitbucket.org/pypy/pypy/changeset/ead38baf8c3e/ Log: Oops (thanks amaury) diff --git a/pypy/module/array/test/test_ztranslation.py b/pypy/module/array/test/test_ztranslation.py --- a/pypy/module/array/test/test_ztranslation.py +++ b/pypy/module/array/test/test_ztranslation.py @@ -2,5 +2,5 @@ from pypy.objspace.fake.checkmodule import checkmodule def test_checkmodule(): - checkmodule('struct') + checkmodule('array') From noreply at buildbot.pypy.org Mon May 13 22:05:37 2013 From: noreply at buildbot.pypy.org (gutworth) Date: Mon, 13 May 2013 22:05:37 +0200 (CEST) Subject: [pypy-commit] pypy default: move JitException subclasses to jitexc module Message-ID: <20130513200537.DFFE51C009D@cobra.cs.uni-duesseldorf.de> Author: Benjamin Peterson Branch: Changeset: r64045:71b42a2d862d Date: 2013-05-13 15:04 -0500 http://bitbucket.org/pypy/pypy/changeset/71b42a2d862d/ Log: move JitException subclasses to jitexc module diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -1,7 +1,8 @@ from rpython.jit.codewriter import heaptracker, longlong from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr from rpython.jit.metainterp.compile import ResumeAtPositionDescr -from rpython.jit.metainterp.jitexc import JitException, get_llexception, reraise +from rpython.jit.metainterp.jitexc import get_llexception, reraise +from rpython.jit.metainterp import jitexc from rpython.rlib import longlong2float from rpython.rlib.debug import ll_assert, make_sure_not_resized from rpython.rlib.objectmodel import we_are_translated @@ -25,7 +26,7 @@ LONGLONG_TYPECODE = 'i' if longlong.is_64_bit else 'f' -class LeaveFrame(JitException): +class LeaveFrame(jitexc.JitException): pass class MissingValue(object): @@ -306,7 +307,7 @@ self.dispatch_loop(self, self.jitcode.code, self.position) except LeaveFrame: break - except JitException: + except jitexc.JitException: raise # go through except Exception, e: lle = get_llexception(self.cpu, e) @@ -902,8 +903,7 @@ @arguments("self", "i", "I", "R", "F", "I", "R", "F") def bhimpl_jit_merge_point(self, jdindex, *args): if self.nextblackholeinterp is None: # we are the last level - CRN = self.builder.metainterp_sd.ContinueRunningNormally - raise CRN(*args) + raise jitexc.ContinueRunningNormally(*args) # Note that the case above is an optimization: the case # below would work too. But it keeps unnecessary stuff on # the stack; the solution above first gets rid of the blackhole @@ -1400,7 +1400,7 @@ # we now proceed to interpret the bytecode in this frame self.run() # - except JitException, e: + except jitexc.JitException, e: raise # go through except Exception, e: # if we get an exception, return it to the caller frame @@ -1495,20 +1495,20 @@ sd = self.builder.metainterp_sd kind = self._return_type if kind == 'v': - raise sd.DoneWithThisFrameVoid() + raise jitexc.DoneWithThisFrameVoid() elif kind == 'i': - raise sd.DoneWithThisFrameInt(self.get_tmpreg_i()) + raise jitexc.DoneWithThisFrameInt(self.get_tmpreg_i()) elif kind == 'r': - raise sd.DoneWithThisFrameRef(self.cpu, self.get_tmpreg_r()) + raise jitexc.DoneWithThisFrameRef(self.cpu, self.get_tmpreg_r()) elif kind == 'f': - raise sd.DoneWithThisFrameFloat(self.get_tmpreg_f()) + raise jitexc.DoneWithThisFrameFloat(self.get_tmpreg_f()) else: assert False def _exit_frame_with_exception(self, e): sd = self.builder.metainterp_sd e = lltype.cast_opaque_ptr(llmemory.GCREF, e) - raise sd.ExitFrameWithExceptionRef(self.cpu, e) + raise jitexc.ExitFrameWithExceptionRef(self.cpu, e) def _handle_jitexception_in_portal(self, e): # This case is really rare, but can occur if @@ -1558,23 +1558,23 @@ while True: try: current_exc = blackholeinterp._resume_mainloop(current_exc) - except JitException, e: + except jitexc.JitException as e: blackholeinterp, current_exc = _handle_jitexception( blackholeinterp, e) blackholeinterp.builder.release_interp(blackholeinterp) blackholeinterp = blackholeinterp.nextblackholeinterp -def _handle_jitexception(blackholeinterp, jitexc): +def _handle_jitexception(blackholeinterp, exc): # See comments in _handle_jitexception_in_portal(). while not blackholeinterp.jitcode.is_portal: blackholeinterp.builder.release_interp(blackholeinterp) blackholeinterp = blackholeinterp.nextblackholeinterp if blackholeinterp.nextblackholeinterp is None: blackholeinterp.builder.release_interp(blackholeinterp) - raise jitexc # bottommost entry: go through + raise exc # bottommost entry: go through # We have reached a recursive portal level. try: - blackholeinterp._handle_jitexception_in_portal(jitexc) + blackholeinterp._handle_jitexception_in_portal(exc) except Exception, e: # It raised a general exception (it should not be a JitException here). lle = get_llexception(blackholeinterp.cpu, e) diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -12,7 +12,7 @@ from rpython.jit.metainterp.history import TreeLoop, Box, JitCellToken, TargetToken from rpython.jit.metainterp.history import AbstractFailDescr, BoxInt from rpython.jit.metainterp.history import BoxPtr, BoxFloat, ConstInt -from rpython.jit.metainterp import history, resume +from rpython.jit.metainterp import history, resume, jitexc from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp.inliner import Inliner from rpython.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP, ResumeDataDirectReader @@ -415,32 +415,32 @@ class DoneWithThisFrameDescrVoid(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.VOID - raise metainterp_sd.DoneWithThisFrameVoid() + raise jitexc.DoneWithThisFrameVoid() class DoneWithThisFrameDescrInt(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.INT result = metainterp_sd.cpu.get_int_value(deadframe, 0) - raise metainterp_sd.DoneWithThisFrameInt(result) + raise jitexc.DoneWithThisFrameInt(result) class DoneWithThisFrameDescrRef(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.REF cpu = metainterp_sd.cpu result = cpu.get_ref_value(deadframe, 0) - raise metainterp_sd.DoneWithThisFrameRef(cpu, result) + raise jitexc.DoneWithThisFrameRef(cpu, result) class DoneWithThisFrameDescrFloat(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.FLOAT result = metainterp_sd.cpu.get_float_value(deadframe, 0) - raise metainterp_sd.DoneWithThisFrameFloat(result) + raise jitexc.DoneWithThisFrameFloat(result) class ExitFrameWithExceptionDescrRef(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): cpu = metainterp_sd.cpu value = cpu.get_ref_value(deadframe, 0) - raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value) + raise jitexc.ExitFrameWithExceptionRef(cpu, value) class TerminatingLoopToken(JitCellToken): # FIXME: kill? @@ -865,7 +865,7 @@ if not exception: exception = cast_instance_to_gcref(memory_error) assert exception, "PropagateExceptionDescr: no exception??" - raise metainterp_sd.ExitFrameWithExceptionRef(cpu, exception) + raise jitexc.ExitFrameWithExceptionRef(cpu, exception) def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes, memory_manager=None): diff --git a/rpython/jit/metainterp/jitexc.py b/rpython/jit/metainterp/jitexc.py --- a/rpython/jit/metainterp/jitexc.py +++ b/rpython/jit/metainterp/jitexc.py @@ -1,8 +1,9 @@ from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance -from rpython.rtyper.lltypesystem import rclass +from rpython.rtyper.lltypesystem import lltype, rclass from rpython.rtyper.llinterp import LLException from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.codewriter import longlong class JitException(Exception): @@ -12,6 +13,54 @@ """ _go_through_llinterp_uncaught_ = True # ugh +class DoneWithThisFrameVoid(JitException): + def __str__(self): + return 'DoneWithThisFrameVoid()' + +class DoneWithThisFrameInt(JitException): + def __init__(self, result): + assert lltype.typeOf(result) is lltype.Signed + self.result = result + def __str__(self): + return 'DoneWithThisFrameInt(%s)' % (self.result,) + +class DoneWithThisFrameRef(JitException): + def __init__(self, cpu, result): + assert lltype.typeOf(result) == cpu.ts.BASETYPE + self.result = result + def __str__(self): + return 'DoneWithThisFrameRef(%s)' % (self.result,) + +class DoneWithThisFrameFloat(JitException): + def __init__(self, result): + assert lltype.typeOf(result) is longlong.FLOATSTORAGE + self.result = result + def __str__(self): + return 'DoneWithThisFrameFloat(%s)' % (self.result,) + +class ExitFrameWithExceptionRef(JitException): + def __init__(self, cpu, value): + assert lltype.typeOf(value) == cpu.ts.BASETYPE + self.value = value + def __str__(self): + return 'ExitFrameWithExceptionRef(%s)' % (self.value,) + +class ContinueRunningNormally(JitException): + def __init__(self, gi, gr, gf, ri, rr, rf): + # the six arguments are: lists of green ints, greens refs, + # green floats, red ints, red refs, and red floats. + self.green_int = gi + self.green_ref = gr + self.green_float = gf + self.red_int = ri + self.red_ref = rr + self.red_float = rf + def __str__(self): + return 'ContinueRunningNormally(%s, %s, %s, %s, %s, %s)' % ( + self.green_int, self.green_ref, self.green_float, + self.red_int, self.red_ref, self.red_float) + + def _get_standard_error(rtyper, Class): exdata = rtyper.getexceptiondata() clsdef = rtyper.annotator.bookkeeper.getuniqueclassdef(Class) diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -5,11 +5,10 @@ from rpython.jit.codewriter import heaptracker from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr -from rpython.jit.metainterp import history, compile, resume, executor +from rpython.jit.metainterp import history, compile, resume, executor, jitexc from rpython.jit.metainterp.heapcache import HeapCache from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr, ConstFloat, Box, TargetToken) -from rpython.jit.metainterp.jitexc import JitException, get_llexception from rpython.jit.metainterp.jitprof import EmptyProfiler from rpython.jit.metainterp.logger import Logger from rpython.jit.metainterp.optimizeopt.util import args_dict_box @@ -1705,13 +1704,13 @@ result_type = self.jitdriver_sd.result_type if result_type == history.VOID: assert resultbox is None - raise sd.DoneWithThisFrameVoid() + raise jitexc.DoneWithThisFrameVoid() elif result_type == history.INT: - raise sd.DoneWithThisFrameInt(resultbox.getint()) + raise jitexc.DoneWithThisFrameInt(resultbox.getint()) elif result_type == history.REF: - raise sd.DoneWithThisFrameRef(self.cpu, resultbox.getref_base()) + raise jitexc.DoneWithThisFrameRef(self.cpu, resultbox.getref_base()) elif result_type == history.FLOAT: - raise sd.DoneWithThisFrameFloat(resultbox.getfloatstorage()) + raise jitexc.DoneWithThisFrameFloat(resultbox.getfloatstorage()) else: assert False @@ -1734,7 +1733,7 @@ self.compile_exit_frame_with_exception(excvaluebox) except SwitchToBlackhole, stb: self.aborted_tracing(stb.reason) - raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base()) + raise jitexc.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base()) def check_recursion_invariant(self): portal_call_depth = -1 @@ -1842,9 +1841,9 @@ op.name = self.framestack[-1].jitcode.name def execute_raised(self, exception, constant=False): - if isinstance(exception, JitException): - raise JitException, exception # go through - llexception = get_llexception(self.cpu, exception) + if isinstance(exception, jitexc.JitException): + raise jitexc.JitException, exception # go through + llexception = jitexc.get_llexception(self.cpu, exception) self.execute_ll_raised(llexception, constant) def execute_ll_raised(self, llexception, constant=False): @@ -2089,7 +2088,7 @@ gi, gr, gf = self._unpack_boxes(live_arg_boxes, 0, num_green_args) ri, rr, rf = self._unpack_boxes(live_arg_boxes, num_green_args, len(live_arg_boxes)) - CRN = self.staticdata.ContinueRunningNormally + CRN = jitexc.ContinueRunningNormally raise CRN(gi, gr, gf, ri, rr, rf) else: # However, in order to keep the existing tests working @@ -2671,11 +2670,11 @@ # ____________________________________________________________ -class ChangeFrame(JitException): +class ChangeFrame(jitexc.JitException): """Raised after we mutated metainterp.framestack, in order to force it to reload the current top-of-stack frame that gets interpreted.""" -class SwitchToBlackhole(JitException): +class SwitchToBlackhole(jitexc.JitException): def __init__(self, reason, raising_exception=False): self.reason = reason self.raising_exception = raising_exception diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -6,7 +6,7 @@ from rpython.jit.metainterp.warmspot import ll_meta_interp, get_stats from rpython.jit.metainterp.warmstate import unspecialize_value from rpython.jit.metainterp.optimizeopt import ALL_OPTS_DICT -from rpython.jit.metainterp import pyjitpl, history +from rpython.jit.metainterp import pyjitpl, history, jitexc from rpython.jit.codewriter.policy import JitPolicy from rpython.jit.codewriter import codewriter, longlong from rpython.rlib.rfloat import isnan @@ -118,30 +118,19 @@ return blackholeinterp._final_result_anytype() def _run_with_pyjitpl(testself, args): - - class DoneWithThisFrame(Exception): - pass - - class DoneWithThisFrameRef(DoneWithThisFrame): - def __init__(self, cpu, *args): - DoneWithThisFrame.__init__(self, *args) - cw = testself.cw opt = history.Options(listops=True) metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt) metainterp_sd.finish_setup(cw) [jitdriver_sd] = metainterp_sd.jitdrivers_sd metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd) - metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame - metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef - metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame testself.metainterp = metainterp try: metainterp.compile_and_run_once(jitdriver_sd, *args) - except DoneWithThisFrame, e: - #if option.view: - # metainterp.stats.view() - return e.args[0] + except (jitexc.DoneWithThisFrameInt, + jitexc.DoneWithThisFrameRef, + jitexc.DoneWithThisFrameFloat) as e: + return e.result else: raise Exception("FAILED") diff --git a/rpython/jit/metainterp/test/test_blackhole.py b/rpython/jit/metainterp/test/test_blackhole.py --- a/rpython/jit/metainterp/test/test_blackhole.py +++ b/rpython/jit/metainterp/test/test_blackhole.py @@ -4,7 +4,7 @@ from rpython.jit.metainterp.blackhole import BlackholeInterpBuilder from rpython.jit.metainterp.blackhole import BlackholeInterpreter from rpython.jit.metainterp.blackhole import convert_and_run_from_pyjitpl -from rpython.jit.metainterp import history, pyjitpl +from rpython.jit.metainterp import history, pyjitpl, jitexc from rpython.jit.codewriter.assembler import JitCode from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.llinterp import LLException @@ -119,6 +119,7 @@ "\x01\x02", # int_return/i [], num_regs_i=3, num_regs_r=0, num_regs_f=0) + jitcode.is_portal = True pc = 1 registers_i = [history.BoxInt(40), history.ConstInt(2), None] class MyMetaInterp: @@ -129,8 +130,6 @@ def start_blackhole(): pass @staticmethod def end_blackhole(): pass - class DoneWithThisFrameInt(Exception): - pass last_exc_value_box = None framestack = [MyMIFrame()] MyMetaInterp.staticdata.blackholeinterpbuilder = getblackholeinterp( @@ -138,9 +137,9 @@ MyMetaInterp.staticdata.blackholeinterpbuilder.metainterp_sd = \ MyMetaInterp.staticdata # - d = py.test.raises(MyMetaInterp.staticdata.DoneWithThisFrameInt, + d = py.test.raises(jitexc.DoneWithThisFrameInt, convert_and_run_from_pyjitpl, MyMetaInterp()) - assert d.value.args == (42,) + assert d.value.result == 42 class TestBlackhole(LLJitMixin): diff --git a/rpython/jit/metainterp/test/test_warmspot.py b/rpython/jit/metainterp/test/test_warmspot.py --- a/rpython/jit/metainterp/test/test_warmspot.py +++ b/rpython/jit/metainterp/test/test_warmspot.py @@ -1,4 +1,5 @@ import py +from rpython.jit.metainterp import jitexc from rpython.jit.metainterp.warmspot import get_stats from rpython.rlib.jit import JitDriver, set_param, unroll_safe, jit_callback from rpython.jit.backend.llgraph import runner @@ -583,14 +584,14 @@ no = self.no assert deadframe._no == no if no == 0: - raise metainterp_sd.warmrunnerdesc.DoneWithThisFrameInt(3) + raise jitexc.DoneWithThisFrameInt(3) if no == 1: - raise metainterp_sd.warmrunnerdesc.ContinueRunningNormally( + raise jitexc.ContinueRunningNormally( [0], [], [], [1], [], []) if no == 3: exc = lltype.malloc(OBJECT) exc.typeptr = exc_vtable - raise metainterp_sd.warmrunnerdesc.ExitFrameWithExceptionRef( + raise jitexc.ExitFrameWithExceptionRef( metainterp_sd.cpu, lltype.cast_opaque_ptr(llmemory.GCREF, exc)) assert 0 diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -16,10 +16,9 @@ from rpython.translator.backendopt import removenoops from rpython.translator.unsimplify import call_final_function -from rpython.jit.metainterp import history, pyjitpl, gc, memmgr +from rpython.jit.metainterp import history, pyjitpl, gc, memmgr, jitexc from rpython.jit.metainterp.pyjitpl import MetaInterpStaticData from rpython.jit.metainterp.jitprof import Profiler, EmptyProfiler -from rpython.jit.metainterp.jitexc import JitException from rpython.jit.metainterp.jitdriver import JitDriverStaticData from rpython.jit.codewriter import support, codewriter, longlong from rpython.jit.codewriter.policy import JitPolicy @@ -172,9 +171,6 @@ stats.maybe_view() stats.check_consistency() -class ContinueRunningNormallyBase(JitException): - pass - # ____________________________________________________________ class WarmRunnerDesc(object): @@ -210,7 +206,6 @@ # self.hooks = policy.jithookiface self.make_virtualizable_infos() - self.make_exception_classes() self.make_driverhook_graphs() self.make_enter_functions() self.rewrite_jit_merge_points(policy) @@ -466,70 +461,6 @@ vinfos[VTYPEPTR] = VirtualizableInfo(self, VTYPEPTR) jd.virtualizable_info = vinfos[VTYPEPTR] - def make_exception_classes(self): - - class DoneWithThisFrameVoid(JitException): - def __str__(self): - return 'DoneWithThisFrameVoid()' - - class DoneWithThisFrameInt(JitException): - def __init__(self, result): - assert lltype.typeOf(result) is lltype.Signed - self.result = result - def __str__(self): - return 'DoneWithThisFrameInt(%s)' % (self.result,) - - class DoneWithThisFrameRef(JitException): - def __init__(self, cpu, result): - assert lltype.typeOf(result) == cpu.ts.BASETYPE - self.result = result - def __str__(self): - return 'DoneWithThisFrameRef(%s)' % (self.result,) - - class DoneWithThisFrameFloat(JitException): - def __init__(self, result): - assert lltype.typeOf(result) is longlong.FLOATSTORAGE - self.result = result - def __str__(self): - return 'DoneWithThisFrameFloat(%s)' % (self.result,) - - class ExitFrameWithExceptionRef(JitException): - def __init__(self, cpu, value): - assert lltype.typeOf(value) == cpu.ts.BASETYPE - self.value = value - def __str__(self): - return 'ExitFrameWithExceptionRef(%s)' % (self.value,) - - class ContinueRunningNormally(ContinueRunningNormallyBase): - def __init__(self, gi, gr, gf, ri, rr, rf): - # the six arguments are: lists of green ints, greens refs, - # green floats, red ints, red refs, and red floats. - self.green_int = gi - self.green_ref = gr - self.green_float = gf - self.red_int = ri - self.red_ref = rr - self.red_float = rf - def __str__(self): - return 'ContinueRunningNormally(%s, %s, %s, %s, %s, %s)' % ( - self.green_int, self.green_ref, self.green_float, - self.red_int, self.red_ref, self.red_float) - - # XXX there is no point any more to not just have the exceptions - # as globals - self.DoneWithThisFrameVoid = DoneWithThisFrameVoid - self.DoneWithThisFrameInt = DoneWithThisFrameInt - self.DoneWithThisFrameRef = DoneWithThisFrameRef - self.DoneWithThisFrameFloat = DoneWithThisFrameFloat - self.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef - self.ContinueRunningNormally = ContinueRunningNormally - self.metainterp_sd.DoneWithThisFrameVoid = DoneWithThisFrameVoid - self.metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrameInt - self.metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef - self.metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrameFloat - self.metainterp_sd.ExitFrameWithExceptionRef = ExitFrameWithExceptionRef - self.metainterp_sd.ContinueRunningNormally = ContinueRunningNormally - def make_enter_functions(self): for jd in self.jitdrivers_sd: self.make_enter_function(jd) @@ -544,7 +475,7 @@ tb = not we_are_translated() and sys.exc_info()[2] try: raise e - except JitException: + except jitexc.JitException: raise # go through except MemoryError: raise # go through @@ -850,7 +781,7 @@ # want to interrupt the whole interpreter loop. return support.maybe_on_top_of_llinterp(rtyper, portal_ptr)(*args) - except self.ContinueRunningNormally, e: + except jitexc.ContinueRunningNormally, e: args = () for ARGTYPE, attrname, count in portalfunc_ARGS: x = getattr(e, attrname)[count] @@ -858,19 +789,19 @@ args = args + (x,) start = False continue - except self.DoneWithThisFrameVoid: + except jitexc.DoneWithThisFrameVoid: assert result_kind == 'void' return - except self.DoneWithThisFrameInt, e: + except jitexc.DoneWithThisFrameInt, e: assert result_kind == 'int' return specialize_value(RESULT, e.result) - except self.DoneWithThisFrameRef, e: + except jitexc.DoneWithThisFrameRef, e: assert result_kind == 'ref' return specialize_value(RESULT, e.result) - except self.DoneWithThisFrameFloat, e: + except jitexc.DoneWithThisFrameFloat, e: assert result_kind == 'float' return specialize_value(RESULT, e.result) - except self.ExitFrameWithExceptionRef, e: + except jitexc.ExitFrameWithExceptionRef, e: value = ts.cast_to_baseclass(e.value) if not we_are_translated(): raise LLException(ts.get_typeptr(value), value) @@ -882,7 +813,7 @@ # XXX the bulk of this function is mostly a copy-paste from above try: raise e - except self.ContinueRunningNormally, e: + except jitexc.ContinueRunningNormally, e: args = () for ARGTYPE, attrname, count in portalfunc_ARGS: x = getattr(e, attrname)[count] @@ -892,19 +823,19 @@ if result_kind != 'void': result = unspecialize_value(result) return result - except self.DoneWithThisFrameVoid: + except jitexc.DoneWithThisFrameVoid: assert result_kind == 'void' return - except self.DoneWithThisFrameInt, e: + except jitexc.DoneWithThisFrameInt, e: assert result_kind == 'int' return e.result - except self.DoneWithThisFrameRef, e: + except jitexc.DoneWithThisFrameRef, e: assert result_kind == 'ref' return e.result - except self.DoneWithThisFrameFloat, e: + except jitexc.DoneWithThisFrameFloat, e: assert result_kind == 'float' return e.result - except self.ExitFrameWithExceptionRef, e: + except jitexc.ExitFrameWithExceptionRef, e: value = ts.cast_to_baseclass(e.value) if not we_are_translated(): raise LLException(ts.get_typeptr(value), value) @@ -932,7 +863,7 @@ vinfo.reset_vable_token(virtualizable) try: fail_descr.handle_fail(deadframe, self.metainterp_sd, jd) - except JitException, e: + except jitexc.JitException, e: return handle_jitexception(e) else: assert 0, "should have raised" From noreply at buildbot.pypy.org Mon May 13 22:45:23 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 22:45:23 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: close to-be-merged branch Message-ID: <20130513204523.EE57E1C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-array-smm Changeset: r64046:9913b5d0c7d3 Date: 2013-05-13 22:44 +0200 http://bitbucket.org/pypy/pypy/changeset/9913b5d0c7d3/ Log: close to-be-merged branch From noreply at buildbot.pypy.org Mon May 13 22:45:25 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 22:45:25 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge remove-array-smm branch that kills multimethods from the array module Message-ID: <20130513204525.7361B1C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64047:d1459869ce85 Date: 2013-05-13 22:44 +0200 http://bitbucket.org/pypy/pypy/changeset/d1459869ce85/ Log: Merge remove-array-smm branch that kills multimethods from the array module diff --git a/pypy/module/array/__init__.py b/pypy/module/array/__init__.py --- a/pypy/module/array/__init__.py +++ b/pypy/module/array/__init__.py @@ -1,12 +1,5 @@ from pypy.interpreter.mixedmodule import MixedModule -from pypy.module.array.interp_array import types -from pypy.objspace.std.model import registerimplementation - -for mytype in types.values(): - registerimplementation(mytype.w_class) - - class Module(MixedModule): interpleveldefs = { 'array': 'interp_array.W_ArrayBase', 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 @@ -2,17 +2,14 @@ from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr +from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef +from pypy.interpreter.baseobjspace import W_Root from pypy.module._file.interp_file import W_File -from pypy.objspace.std.model import W_Object -from pypy.objspace.std.multimethod import FailedToImplement -from pypy.objspace.std.stdtypedef import SMM, StdTypeDef -from pypy.objspace.std.register_all import register_all from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.objectmodel import specialize, keepalive_until_here +from rpython.rlib.objectmodel import keepalive_until_here from rpython.rtyper.lltypesystem import lltype, rffi @@ -39,9 +36,9 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(space.str_w(w_initializer)) + a.descr_fromstring(space, space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_list: - a.fromlist(w_initializer) + a.descr_fromlist(space, w_initializer) else: a.extend(w_initializer, True) break @@ -52,31 +49,6 @@ return a -array_append = SMM('append', 2) -array_extend = SMM('extend', 2) - -array_count = SMM('count', 2) -array_index = SMM('index', 2) -array_reverse = SMM('reverse', 1) -array_remove = SMM('remove', 2) -array_pop = SMM('pop', 2, defaults=(-1,)) -array_insert = SMM('insert', 3) - -array_tolist = SMM('tolist', 1) -array_fromlist = SMM('fromlist', 2) -array_tostring = SMM('tostring', 1) -array_fromstring = SMM('fromstring', 2) -array_tounicode = SMM('tounicode', 1) -array_fromunicode = SMM('fromunicode', 2) -array_tofile = SMM('tofile', 2) -array_fromfile = SMM('fromfile', 3) - -array_buffer_info = SMM('buffer_info', 1) -array_reduce = SMM('__reduce__', 1) -array_copy = SMM('__copy__', 1) -array_byteswap = SMM('byteswap', 1) - - def descr_itemsize(space, self): return space.wrap(self.itemsize) @@ -84,28 +56,476 @@ def descr_typecode(space, self): return space.wrap(self.typecode) +arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') +EQ, NE, LT, LE, GT, GE = range(6) -class W_ArrayBase(W_Object): - @staticmethod - def register(typeorder): - typeorder[W_ArrayBase] = [] +def compare_arrays(space, arr1, arr2, comp_op, comp_func): + if (not isinstance(arr1, W_ArrayBase) or + not isinstance(arr2, W_ArrayBase)): + return space.w_NotImplemented + if comp_op == EQ and arr1.len != arr2.len: + return space.w_False + if comp_op == NE and arr1.len != arr2.len: + return space.w_True + lgt = min(arr1.len, arr2.len) + for i in range(lgt): + arr_eq_driver.jit_merge_point(comp_func=comp_func) + w_elem1 = arr1.w_getitem(space, i) + w_elem2 = arr2.w_getitem(space, i) + res = space.is_true(comp_func(w_elem1, w_elem2)) + if comp_op == EQ: + if not res: + return space.w_False + elif comp_op == NE: + if res: + return space.w_True + elif comp_op == LT or comp_op == GT: + if res: + return space.w_True + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_False + else: + if not res: + return space.w_False + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_True + # we have some leftovers + if comp_op == EQ: + return space.w_True + elif comp_op == NE: + return space.w_False + if arr1.len == arr2.len: + if comp_op == LT or comp_op == GT: + return space.w_False + return space.w_True + if comp_op == LT or comp_op == LE: + if arr1.len < arr2.len: + return space.w_False + return space.w_True + if arr1.len > arr2.len: + return space.w_False + return space.w_True -W_ArrayBase.typedef = StdTypeDef( +UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, + hints={'nolength': True})) + +class W_ArrayBase(W_Root): + _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer + + def __init__(self, space): + self.space = space + self.len = 0 + self.allocated = 0 + + def descr_append(self, space, w_x): + """ append(x) + + Append new value x to the end of the array. + """ + raise NotImplementedError + + def descr_extend(self, space, w_x): + """ extend(array or iterable) + + Append items to the end of the array. + """ + self.extend(w_x) + + def descr_count(self, space, w_val): + """ count(x) + + Return number of occurrences of x in the array. + """ + raise NotImplementedError + + def descr_index(self, space, w_x): + """ index(x) + + Return index of first occurrence of x in the array. + """ + raise NotImplementedError + + def descr_reverse(self, space): + """ reverse() + + Reverse the order of the items in the array. + """ + raise NotImplementedError + + def descr_remove(self, space, w_val): + """ remove(x) + + Remove the first occurrence of x in the array. + """ + raise NotImplementedError + + @unwrap_spec(i=int) + def descr_pop(self, space, i=-1): + """ pop([i]) + + Return the i-th element and delete it from the array. i defaults to -1. + """ + raise NotImplementedError + + @unwrap_spec(idx=int) + def descr_insert(self, space, idx, w_val): + """ insert(i,x) + + Insert a new item x into the array before position i. + """ + raise NotImplementedError + + def descr_tolist(self, space): + """ tolist() -> list + + Convert array to an ordinary list with the same items. + """ + w_l = space.newlist([]) + for i in range(self.len): + w_l.append(self.w_getitem(space, i)) + return w_l + + def descr_fromlist(self, space, w_lst): + """ fromlist(list) + + Append items to array from list. + """ + if not space.isinstance_w(w_lst, space.w_list): + raise OperationError(space.w_TypeError, + space.wrap("arg must be list")) + s = self.len + try: + self.fromsequence(w_lst) + except OperationError: + self.setlen(s) + raise + + def descr_tostring(self, space): + """ tostring() -> string + + Convert the array to an array of machine values and return the string + representation. + """ + cbuf = self._charbuf_start() + s = rffi.charpsize2str(cbuf, self.len * self.itemsize) + self._charbuf_stop() + return self.space.wrap(s) + + @unwrap_spec(s=str) + def descr_fromstring(self, space, s): + """ fromstring(string) + + Appends items from the string, interpreting it as an array of machine + values,as if it had been read from a file using the fromfile() method). + """ + if len(s) % self.itemsize != 0: + msg = 'string length not a multiple of item size' + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) + oldlen = self.len + new = len(s) / self.itemsize + self.setlen(oldlen + new) + cbuf = self._charbuf_start() + for i in range(len(s)): + cbuf[oldlen * self.itemsize + i] = s[i] + self._charbuf_stop() + + @unwrap_spec(w_f=W_File, n=int) + def descr_fromfile(self, space, w_f, n): + """ fromfile(f, n) + + Read n objects from the file object f and append them to the end of the + array. Also called as read. + """ + try: + size = ovfcheck(self.itemsize * n) + except OverflowError: + raise MemoryError + w_item = space.call_method(w_f, 'read', space.wrap(size)) + item = space.str_w(w_item) + if len(item) < size: + n = len(item) % self.itemsize + elems = max(0, len(item) - (len(item) % self.itemsize)) + if n != 0: + item = item[0:elems] + self.descr_fromstring(space, item) + msg = "not enough items in file" + raise OperationError(space.w_EOFError, space.wrap(msg)) + self.descr_fromstring(space, item) + + @unwrap_spec(w_f=W_File) + def descr_tofile(self, space, w_f): + """ tofile(f) + + Write all items (as machine values) to the file object f. Also called as + write. + """ + w_s = self.descr_tostring(space) + space.call_method(w_f, 'write', w_s) + + def descr_fromunicode(self, space, w_ustr): + """ fromunicode(ustr) + + Extends this array with data from the unicode string ustr. + The array must be a type 'u' array; otherwise a ValueError + is raised. Use array.fromstring(ustr.decode(...)) to + append Unicode data to an array of some other type. + """ + # XXX the following probable bug is not emulated: + # CPython accepts a non-unicode string or a buffer, and then + # behaves just like fromstring(), except that it strangely truncate + # string arguments at multiples of the unicode byte size. + # Let's only accept unicode arguments for now. + if self.typecode == 'u': + self.fromsequence(w_ustr) + else: + msg = "fromunicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_tounicode(self, space): + """ tounicode() -> unicode + + Convert the array to a unicode string. The array must be + a type 'u' array; otherwise a ValueError is raised. Use + array.tostring().decode() to obtain a unicode string from + an array of some other type. + """ + if self.typecode == 'u': + buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned()) + return space.wrap(rffi.wcharpsize2unicode(buf, self.len)) + else: + msg = "tounicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_buffer_info(self, space): + """ buffer_info() -> (address, length) + + Return a tuple (address, length) giving the current memory address and + the length in items of the buffer used to hold array's contents + The length should be multiplied by the itemsize attribute to calculate + the buffer length in bytes. + """ + w_ptr = space.wrap(self._buffer_as_unsigned()) + w_len = space.wrap(self.len) + return space.newtuple([w_ptr, w_len]) + + def descr_reduce(self, space): + """ Return state information for pickling. + """ + if self.len > 0: + w_s = self.descr_tostring(space) + args = [space.wrap(self.typecode), w_s] + else: + args = [space.wrap(self.typecode)] + try: + dct = space.getattr(self, space.wrap('__dict__')) + except OperationError: + dct = space.w_None + return space.newtuple([space.type(self), space.newtuple(args), dct]) + + def descr_copy(self, space): + """ copy(array) + + Return a copy of the array. + """ + w_a = self.constructor(self.space) + w_a.setlen(self.len, overallocate=False) + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()), + rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()), + self.len * self.itemsize + ) + return w_a + + def descr_byteswap(self, space): + """ byteswap() + + Byteswap all items of the array. If the items in the array are not 1, 2, + 4, or 8 bytes in size, RuntimeError is raised. + """ + if self.itemsize not in [1, 2, 4, 8]: + msg = "byteswap not supported for this array" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + if self.len == 0: + return + bytes = self._charbuf_start() + tmp = [bytes[0]] * self.itemsize + for start in range(0, self.len * self.itemsize, self.itemsize): + stop = start + self.itemsize - 1 + for i in range(self.itemsize): + tmp[i] = bytes[start + i] + for i in range(self.itemsize): + bytes[stop - i] = tmp[i] + self._charbuf_stop() + + def descr_len(self, space): + return space.wrap(self.len) + + def descr_eq(self, space, w_arr2): + "x.__eq__(y) <==> x==y" + return compare_arrays(space, self, w_arr2, EQ, space.eq) + + def descr_ne(self, space, w_arr2): + "x.__ne__(y) <==> x!=y" + return compare_arrays(space, self, w_arr2, NE, space.ne) + + def descr_lt(self, space, w_arr2): + "x.__lt__(y) <==> x x<=y" + return compare_arrays(space, self, w_arr2, LE, space.le) + + def descr_gt(self, space, w_arr2): + "x.__gt__(y) <==> x>y" + return compare_arrays(space, self, w_arr2, GT, space.gt) + + def descr_ge(self, space, w_arr2): + "x.__ge__(y) <==> x>=y" + return compare_arrays(space, self, w_arr2, GE, space.ge) + + # Basic get/set/append/extend methods + + def descr_getitem(self, space, w_idx): + "x.__getitem__(y) <==> x[y]" + if not space.isinstance_w(w_idx, space.w_slice): + idx, stop, step = space.decode_index(w_idx, self.len) + assert step == 0 + return self.w_getitem(space, idx) + else: + return self.getitem_slice(space, w_idx) + + def descr_getslice(self, space, w_i, w_j): + return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) + + + def descr_setitem(self, space, w_idx, w_item): + "x.__setitem__(i, y) <==> x[i]=y" + if space.isinstance_w(w_idx, space.w_slice): + self.setitem_slice(space, w_idx, w_item) + else: + self.setitem(space, w_idx, w_item) + + def descr_setslice(self, space, w_start, w_stop, w_item): + self.setitem_slice(space, + space.newslice(w_start, w_stop, space.w_None), + w_item) + + def descr_delitem(self, space, w_idx): + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + if step != 1: + # I don't care about efficiency of that so far + w_lst = self.descr_tolist(space) + space.delitem(w_lst, w_idx) + self.setlen(0) + self.fromsequence(w_lst) + return + return self.delitem(space, start, stop) + + def descr_delslice(self, space, w_start, w_stop): + self.descr_delitem(space, space.newslice(w_start, w_stop, space.w_None)) + + def descr_add(self, space, w_other): + raise NotImplementedError + + def descr_inplace_add(self, space, w_other): + raise NotImplementedError + + def descr_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_inplace_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_radd(self, space, w_other): + return self.descr_add(space, w_other) + + def descr_rmul(self, space, w_repeat): + return self.descr_mul(space, w_repeat) + + # Misc methods + + def descr_buffer(self, space): + return space.wrap(ArrayBuffer(self)) + + def descr_repr(self, space): + if self.len == 0: + return space.wrap("array('%s')" % self.typecode) + elif self.typecode == "c": + r = space.repr(self.descr_tostring(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + elif self.typecode == "u": + r = space.repr(self.descr_tounicode(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + else: + r = space.repr(self.descr_tolist(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + +W_ArrayBase.typedef = TypeDef( 'array', __new__ = interp2app(w_array), __module__ = 'array', + + __len__ = interp2app(W_ArrayBase.descr_len), + __eq__ = interp2app(W_ArrayBase.descr_eq), + __ne__ = interp2app(W_ArrayBase.descr_ne), + __lt__ = interp2app(W_ArrayBase.descr_lt), + __le__ = interp2app(W_ArrayBase.descr_le), + __gt__ = interp2app(W_ArrayBase.descr_gt), + __ge__ = interp2app(W_ArrayBase.descr_ge), + + __getitem__ = interp2app(W_ArrayBase.descr_getitem), + __getslice__ = interp2app(W_ArrayBase.descr_getslice), + __setitem__ = interp2app(W_ArrayBase.descr_setitem), + __setslice__ = interp2app(W_ArrayBase.descr_setslice), + __delitem__ = interp2app(W_ArrayBase.descr_delitem), + __delslice__ = interp2app(W_ArrayBase.descr_delslice), + + __add__ = interpindirect2app(W_ArrayBase.descr_add), + __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add), + __mul__ = interpindirect2app(W_ArrayBase.descr_mul), + __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul), + __radd__ = interp2app(W_ArrayBase.descr_radd), + __rmul__ = interp2app(W_ArrayBase.descr_rmul), + + __buffer__ = interp2app(W_ArrayBase.descr_buffer), + __repr__ = interp2app(W_ArrayBase.descr_repr), + itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), + append = interpindirect2app(W_ArrayBase.descr_append), + extend = interp2app(W_ArrayBase.descr_extend), + count = interpindirect2app(W_ArrayBase.descr_count), + index = interpindirect2app(W_ArrayBase.descr_index), + reverse = interpindirect2app(W_ArrayBase.descr_reverse), + remove = interpindirect2app(W_ArrayBase.descr_remove), + pop = interpindirect2app(W_ArrayBase.descr_pop), + insert = interpindirect2app(W_ArrayBase.descr_insert), + + tolist = interp2app(W_ArrayBase.descr_tolist), + fromlist = interp2app(W_ArrayBase.descr_fromlist), + tostring = interp2app(W_ArrayBase.descr_tostring), + fromstring = interp2app(W_ArrayBase.descr_fromstring), + tofile = interp2app(W_ArrayBase.descr_tofile), + fromfile = interp2app(W_ArrayBase.descr_fromfile), + fromunicode = interp2app(W_ArrayBase.descr_fromunicode), + tounicode = interp2app(W_ArrayBase.descr_tounicode), + + buffer_info = interp2app(W_ArrayBase.descr_buffer_info), + __copy__ = interp2app(W_ArrayBase.descr_copy), + __reduce__ = interp2app(W_ArrayBase.descr_reduce), + byteswap = interp2app(W_ArrayBase.descr_byteswap), ) -W_ArrayBase.typedef.registermethods(globals()) class TypeCode(object): def __init__(self, itemtype, unwrap, canoverflow=False, signed=False): self.itemtype = itemtype self.bytes = rffi.sizeof(itemtype) - #self.arraytype = lltype.GcArray(itemtype) self.arraytype = lltype.Array(itemtype, hints={'nolength': True}) self.unwrap = unwrap self.signed = signed @@ -175,14 +595,10 @@ itemsize = mytype.bytes typecode = mytype.typecode - @staticmethod - def register(typeorder): - typeorder[W_Array] = [(W_ArrayBase, None)] + _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer') def __init__(self, space): - self.space = space - self.len = 0 - self.allocated = 0 + W_ArrayBase.__init__(self, space) self.buffer = lltype.nullptr(mytype.arraytype) def item_w(self, w_item): @@ -289,26 +705,6 @@ raise self.setlen(oldlen + i) - def fromstring(self, s): - if len(s) % self.itemsize != 0: - msg = 'string length not a multiple of item size' - raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) - oldlen = self.len - new = len(s) / mytype.bytes - self.setlen(oldlen + new) - cbuf = self._charbuf_start() - for i in range(len(s)): - cbuf[oldlen * mytype.bytes + i] = s[i] - self._charbuf_stop() - - def fromlist(self, w_lst): - s = self.len - try: - self.fromsequence(w_lst) - except OperationError: - self.setlen(s) - raise - def extend(self, w_iterable, accept_different_array=False): space = self.space if isinstance(w_iterable, W_Array): @@ -332,6 +728,9 @@ def _charbuf_start(self): return rffi.cast(rffi.CCHARP, self.buffer) + def _buffer_as_unsigned(self): + return rffi.cast(lltype.Unsigned, self.buffer) + def _charbuf_stop(self): keepalive_until_here(self) @@ -343,202 +742,180 @@ item = float(item) return space.wrap(item) - # Basic get/set/append/extend methods + # interface - def len__Array(space, self): - return space.wrap(self.len) + def descr_append(self, space, w_x): + x = self.item_w(w_x) + self.setlen(self.len + 1) + self.buffer[self.len - 1] = x - def getitem__Array_ANY(space, self, w_idx): - idx, stop, step = space.decode_index(w_idx, self.len) - assert step == 0 - return self.w_getitem(space, idx) + # List interface + def descr_count(self, space, w_val): + cnt = 0 + for i in range(self.len): + # XXX jitdriver + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + cnt += 1 + return space.wrap(cnt) - def getitem__Array_Slice(space, self, w_slice): - start, stop, step, size = space.decode_index4(w_slice, self.len) - w_a = mytype.w_class(self.space) - w_a.setlen(size, overallocate=False) - assert step != 0 - j = 0 - for i in range(start, stop, step): - w_a.buffer[j] = self.buffer[i] - j += 1 - return w_a + def descr_index(self, space, w_val): + for i in range(self.len): + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + return space.wrap(i) + msg = 'array.index(x): x not in list' + raise OperationError(space.w_ValueError, space.wrap(msg)) - def getslice__Array_ANY_ANY(space, self, w_i, w_j): - return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) + def descr_reverse(self, space): + b = self.buffer + for i in range(self.len / 2): + b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] - def setitem__Array_ANY_ANY(space, self, w_idx, w_item): - idx, stop, step = space.decode_index(w_idx, self.len) - if step != 0: - msg = 'can only assign array to array slice' - raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) - item = self.item_w(w_item) - self.buffer[idx] = item + def descr_pop(self, space, i): + if i < 0: + i += self.len + if i < 0 or i >= self.len: + msg = 'pop index out of range' + raise OperationError(space.w_IndexError, space.wrap(msg)) + w_val = self.w_getitem(space, i) + while i < self.len - 1: + self.buffer[i] = self.buffer[i + 1] + i += 1 + self.setlen(self.len - 1) + return w_val - def setitem__Array_Slice_Array(space, self, w_idx, w_item): - start, stop, step, size = self.space.decode_index4(w_idx, self.len) - assert step != 0 - if w_item.len != size or self is w_item: - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - w_item = space.call_method(w_item, 'tolist') - space.setitem(w_lst, w_idx, w_item) - self.setlen(0) - self.fromsequence(w_lst) - else: + def descr_remove(self, space, w_val): + w_idx = self.descr_index(space, w_val) + self.descr_pop(space, space.int_w(w_idx)) + + def descr_insert(self, space, idx, w_val): + if idx < 0: + idx += self.len + if idx < 0: + idx = 0 + if idx > self.len: + idx = self.len + + val = self.item_w(w_val) + self.setlen(self.len + 1) + i = self.len - 1 + while i > idx: + self.buffer[i] = self.buffer[i - 1] + i -= 1 + self.buffer[i] = val + + def getitem_slice(self, space, w_idx): + start, stop, step, size = space.decode_index4(w_idx, self.len) + w_a = mytype.w_class(self.space) + w_a.setlen(size, overallocate=False) + assert step != 0 j = 0 for i in range(start, stop, step): - self.buffer[i] = w_item.buffer[j] + w_a.buffer[j] = self.buffer[i] j += 1 + return w_a - def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x): - space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x) + def setitem(self, space, w_idx, w_item): + idx, stop, step = space.decode_index(w_idx, self.len) + if step != 0: + msg = 'can only assign array to array slice' + raise OperationError(self.space.w_TypeError, + self.space.wrap(msg)) + item = self.item_w(w_item) + self.buffer[idx] = item - def array_append__Array_ANY(space, self, w_x): - x = self.item_w(w_x) - self.setlen(self.len + 1) - self.buffer[self.len - 1] = x + def setitem_slice(self, space, w_idx, w_item): + if not isinstance(w_item, W_Array): + raise OperationError(space.w_TypeError, space.wrap( + "can only assign to a slice array")) + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + assert step != 0 + if w_item.len != size or self is w_item: + # XXX this is a giant slow hack + w_lst = self.descr_tolist(space) + w_item = space.call_method(w_item, 'tolist') + space.setitem(w_lst, w_idx, w_item) + self.setlen(0) + self.fromsequence(w_lst) + else: + j = 0 + for i in range(start, stop, step): + self.buffer[i] = w_item.buffer[j] + j += 1 - def array_extend__Array_ANY(space, self, w_iterable): - self.extend(w_iterable) + # We can't look into this function until ptradd works with things (in the + # JIT) other than rffi.CCHARP + @jit.dont_look_inside + def delitem(self, space, i, j): + if i < 0: + i += self.len + if i < 0: + i = 0 + if j < 0: + j += self.len + if j < 0: + j = 0 + if j > self.len: + j = self.len + if i >= j: + return None + oldbuffer = self.buffer + self.buffer = lltype.malloc(mytype.arraytype, + max(self.len - (j - i), 0), flavor='raw', + add_memory_pressure=True) + if i: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, self.buffer), + rffi.cast(rffi.VOIDP, oldbuffer), + i * mytype.bytes + ) + if j < self.len: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), + rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), + (self.len - j) * mytype.bytes + ) + self.len -= j - i + self.allocated = self.len + if oldbuffer: + lltype.free(oldbuffer, flavor='raw') - # List interface - def array_count__Array_ANY(space, self, w_val): - cnt = 0 - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - cnt += 1 - return space.wrap(cnt) + # Add and mul methods - def array_index__Array_ANY(space, self, w_val): - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - return space.wrap(i) - msg = 'array.index(x): x not in list' - raise OperationError(space.w_ValueError, space.wrap(msg)) + def descr_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + a = mytype.w_class(space) + a.setlen(self.len + w_other.len, overallocate=False) + for i in range(self.len): + a.buffer[i] = self.buffer[i] + for i in range(w_other.len): + a.buffer[i + self.len] = w_other.buffer[i] + return a - def array_reverse__Array(space, self): - b = self.buffer - for i in range(self.len / 2): - b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] + def descr_inplace_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + oldlen = self.len + otherlen = w_other.len + self.setlen(oldlen + otherlen) + for i in range(otherlen): + self.buffer[oldlen + i] = w_other.buffer[i] + return self - def array_pop__Array_ANY(space, self, w_idx): - i = space.int_w(w_idx) - if i < 0: - i += self.len - if i < 0 or i >= self.len: - msg = 'pop index out of range' - raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = self.w_getitem(space, i) - while i < self.len - 1: - self.buffer[i] = self.buffer[i + 1] - i += 1 - self.setlen(self.len - 1) - return w_val + def descr_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, False) - def array_remove__Array_ANY(space, self, w_val): - w_idx = array_index__Array_ANY(space, self, w_val) - array_pop__Array_ANY(space, self, w_idx) - - def array_insert__Array_ANY_ANY(space, self, w_idx, w_val): - idx = space.int_w(w_idx) - if idx < 0: - idx += self.len - if idx < 0: - idx = 0 - if idx > self.len: - idx = self.len - - val = self.item_w(w_val) - self.setlen(self.len + 1) - i = self.len - 1 - while i > idx: - self.buffer[i] = self.buffer[i - 1] - i -= 1 - self.buffer[i] = val - - def delitem__Array_ANY(space, self, w_idx): - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - space.delitem(w_lst, w_idx) - self.setlen(0) - self.fromsequence(w_lst) - - # We can't look into this function until ptradd works with things (in the - # JIT) other than rffi.CCHARP - @jit.dont_look_inside - def delslice__Array_ANY_ANY(space, self, w_i, w_j): - i = space.int_w(w_i) - if i < 0: - i += self.len - if i < 0: - i = 0 - j = space.int_w(w_j) - if j < 0: - j += self.len - if j < 0: - j = 0 - if j > self.len: - j = self.len - if i >= j: - return None - oldbuffer = self.buffer - self.buffer = lltype.malloc(mytype.arraytype, - max(self.len - (j - i), 0), flavor='raw', - add_memory_pressure=True) - if i: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, self.buffer), - rffi.cast(rffi.VOIDP, oldbuffer), - i * mytype.bytes - ) - if j < self.len: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), - rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), - (self.len - j) * mytype.bytes - ) - self.len -= j - i - self.allocated = self.len - if oldbuffer: - lltype.free(oldbuffer, flavor='raw') - - # Add and mul methods - - def add__Array_Array(space, self, other): - a = mytype.w_class(space) - a.setlen(self.len + other.len, overallocate=False) - for i in range(self.len): - a.buffer[i] = self.buffer[i] - for i in range(other.len): - a.buffer[i + self.len] = other.buffer[i] - return a - - def inplace_add__Array_Array(space, self, other): - oldlen = self.len - otherlen = other.len - self.setlen(oldlen + otherlen) - for i in range(otherlen): - self.buffer[oldlen + i] = other.buffer[i] - return self - - def mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, False) - - def mul__ANY_Array(space, w_repeat, self): - return _mul_helper(space, self, w_repeat, False) - - def inplace_mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, True) + def descr_inplace_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, True) def _mul_helper(space, self, w_repeat, is_inplace): try: repeat = space.getindex_w(w_repeat, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - raise FailedToImplement + return space.w_NotImplemented raise repeat = max(repeat, 0) try: @@ -577,186 +954,11 @@ a.buffer[r * oldlen + i] = self.buffer[i] return a - # Convertions - - def array_tolist__Array(space, self): - w_l = space.newlist([]) - for i in range(self.len): - w_l.append(self.w_getitem(space, i)) - return w_l - - def array_fromlist__Array_List(space, self, w_lst): - self.fromlist(w_lst) - - def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(space.str_w(w_s)) - - def array_tostring__Array(space, self): - cbuf = self._charbuf_start() - s = rffi.charpsize2str(cbuf, self.len * mytype.bytes) - self._charbuf_stop() - return self.space.wrap(s) - - def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - n = space.int_w(w_n) - - try: - size = ovfcheck(self.itemsize * n) - except OverflowError: - raise MemoryError - w_item = space.call_method(w_f, 'read', space.wrap(size)) - item = space.str_w(w_item) - if len(item) < size: - n = len(item) % self.itemsize - elems = max(0, len(item) - (len(item) % self.itemsize)) - if n != 0: - item = item[0:elems] - w_item = space.wrap(item) - array_fromstring__Array_ANY(space, self, w_item) - msg = "not enough items in file" - raise OperationError(space.w_EOFError, space.wrap(msg)) - array_fromstring__Array_ANY(space, self, w_item) - - def array_tofile__Array_ANY(space, self, w_f): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_s = array_tostring__Array(space, self) - space.call_method(w_f, 'write', w_s) - - if mytype.typecode == 'u': - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - # XXX the following probable bug is not emulated: - # CPython accepts a non-unicode string or a buffer, and then - # behaves just like fromstring(), except that it strangely truncate - # string arguments at multiples of the unicode byte size. - # Let's only accept unicode arguments for now. - self.fromsequence(w_ustr) - - def array_tounicode__Array(space, self): - return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) - else: - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - msg = "fromunicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - def array_tounicode__Array(space, self): - msg = "tounicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - # Compare methods - @specialize.arg(3) - def _cmp_impl(space, self, other, space_fn): - # XXX this is a giant slow hack - w_lst1 = array_tolist__Array(space, self) - w_lst2 = space.call_method(other, 'tolist') - return space_fn(w_lst1, w_lst2) - - def eq__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.eq) - - def ne__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ne) - - def lt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.lt) - - def le__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.le) - - def gt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.gt) - - def ge__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ge) - - # Misc methods - - def buffer__Array(space, self): - return space.wrap(ArrayBuffer(self)) - - def array_buffer_info__Array(space, self): - w_ptr = space.wrap(rffi.cast(lltype.Unsigned, self.buffer)) - w_len = space.wrap(self.len) - return space.newtuple([w_ptr, w_len]) - - def array_reduce__Array(space, self): - if self.len > 0: - w_s = array_tostring__Array(space, self) - args = [space.wrap(mytype.typecode), w_s] - else: - args = [space.wrap(mytype.typecode)] - try: - dct = space.getattr(self, space.wrap('__dict__')) - except OperationError: - dct = space.w_None - return space.newtuple([space.type(self), space.newtuple(args), dct]) - - def array_copy__Array(space, self): - w_a = mytype.w_class(self.space) - w_a.setlen(self.len, overallocate=False) - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, w_a.buffer), - rffi.cast(rffi.VOIDP, self.buffer), - self.len * mytype.bytes - ) - return w_a - - def array_byteswap__Array(space, self): - if mytype.bytes not in [1, 2, 4, 8]: - msg = "byteswap not supported for this array" - raise OperationError(space.w_RuntimeError, space.wrap(msg)) - if self.len == 0: - return - bytes = self._charbuf_start() - tmp = [bytes[0]] * mytype.bytes - for start in range(0, self.len * mytype.bytes, mytype.bytes): - stop = start + mytype.bytes - 1 - for i in range(mytype.bytes): - tmp[i] = bytes[start + i] - for i in range(mytype.bytes): - bytes[stop - i] = tmp[i] - self._charbuf_stop() - - def repr__Array(space, self): - if self.len == 0: - return space.wrap("array('%s')" % self.typecode) - elif self.typecode == "c": - r = space.repr(array_tostring__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - elif self.typecode == "u": - r = space.repr(array_tounicode__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - else: - r = space.repr(array_tolist__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - mytype.w_class = W_Array - - # Annotator seems to mess up if the names are not unique + W_Array.constructor = W_Array name = 'ArrayType' + mytype.typecode W_Array.__name__ = 'W_' + name - import re - for n, f in locals().items(): - new, n = re.subn('_Array_', '_%s_' % name, n) - if n > 0: - f.__name__ = new - - from pypy.objspace.std.sliceobject import W_SliceObject - from pypy.objspace.std.listobject import W_ListObject - from pypy.objspace.std.unicodeobject import W_UnicodeObject - register_all(locals(), globals()) - for mytype in types.values(): make_array(mytype) - -register_all(locals(), globals()) +del mytype diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -19,7 +19,7 @@ class BaseArrayTests: - + def test_ctor(self): assert len(self.array('c')) == 0 assert len(self.array('i')) == 0 @@ -390,7 +390,6 @@ assert self.array('c', ('h', 'i')).tostring() == 'hi' a = self.array('i', [0, 0, 0]) assert a.tostring() == '\x00' * 3 * a.itemsize - s = self.array('i', [1, 2, 3]).tostring() assert '\x00' in s assert '\x01' in s @@ -502,7 +501,7 @@ return 0 class incomparable(object): pass - + for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'), ('abc', 'acb', 'c'), (unicode('abc'), unicode('acb'), 'u')): @@ -653,14 +652,14 @@ raises(TypeError, "a * 'hi'") raises(TypeError, "'hi' * a") raises(TypeError, "a *= 'hi'") - + class mulable(object): def __mul__(self, other): return "mul" def __rmul__(self, other): return "rmul" - + assert mulable() * self.array('i') == 'mul' assert self.array('i') * mulable() == 'rmul' @@ -769,7 +768,7 @@ def __getitem__(self, i): return array.__getitem__(self, self._index(i)) - + def __setitem__(self, i, val): return array.__setitem__(self, self._index(i), val) @@ -783,7 +782,7 @@ assert img[3, 25] == 3 * 9 - + def test_override_from(self): class mya(self.array): def fromlist(self, lst): @@ -854,7 +853,7 @@ def test_subclass_del(self): import array, gc, weakref l = [] - + class A(array.array): pass diff --git a/pypy/module/array/test/test_ztranslation.py b/pypy/module/array/test/test_ztranslation.py new file mode 100644 --- /dev/null +++ b/pypy/module/array/test/test_ztranslation.py @@ -0,0 +1,6 @@ + +from pypy.objspace.fake.checkmodule import checkmodule + +def test_checkmodule(): + checkmodule('array') + diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -80,8 +80,6 @@ import pypy.objspace.std.default # register a few catch-all multimethods import pypy.objspace.std.marshal_impl # install marshal multimethods - if config.objspace.usemodules.array: - import pypy.module.array # the set of implementation types self.typeorder = { From noreply at buildbot.pypy.org Mon May 13 22:55:19 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Mon, 13 May 2013 22:55:19 +0200 (CEST) Subject: [pypy-commit] pypy default: Use modern version of @unwrap_spec Message-ID: <20130513205519.18D621C026D@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r64048:84ff58711a5d Date: 2013-05-13 22:53 +0200 http://bitbucket.org/pypy/pypy/changeset/84ff58711a5d/ Log: Use modern version of @unwrap_spec diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,4 +1,3 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import unwrap_spec from rpython.rlib.objectmodel import we_are_translated @@ -56,7 +55,7 @@ bltn = BuiltinFunction(func) return space.wrap(bltn) - at unwrap_spec(ObjSpace, W_Root, str) + at unwrap_spec(meth=str) def lookup_special(space, w_obj, meth): """Lookup up a special method on an object.""" if space.is_oldstyle_instance(w_obj): From noreply at buildbot.pypy.org Mon May 13 23:11:39 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 23:11:39 +0200 (CEST) Subject: [pypy-commit] pypy default: actually set the path Message-ID: <20130513211139.747611C00F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64049:0139e1989670 Date: 2013-05-13 23:10 +0200 http://bitbucket.org/pypy/pypy/changeset/0139e1989670/ Log: actually set the path diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -81,6 +81,13 @@ from rpython.rlib.entrypoint import entrypoint from rpython.rtyper.lltypesystem import rffi, lltype + w_pathsetter = space.appexec([], """(): + def f(path): + import sys + sys.path[:] = path + return f + """) + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') def pypy_setup_home(ll_home, verbose): from pypy.module.sys.initpath import pypy_find_stdlib @@ -88,11 +95,13 @@ home = rffi.charp2str(ll_home) else: home = pypydir - if space.is_none(pypy_find_stdlib(space, home)): + w_path = pypy_find_stdlib(space, home) + if space.is_none(w_path): if verbose: debug("Failed to find library based on pypy_find_stdlib") return 1 space.startup() + space.call_function(w_pathsetter, w_path) # import site try: import_ = space.getattr(space.getbuiltinmodule('__builtin__'), From noreply at buildbot.pypy.org Mon May 13 23:11:40 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 13 May 2013 23:11:40 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130513211140.A470D1C00F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64050:bcf984fdbff0 Date: 2013-05-13 23:11 +0200 http://bitbucket.org/pypy/pypy/changeset/bcf984fdbff0/ Log: merge diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,4 +1,3 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import unwrap_spec from rpython.rlib.objectmodel import we_are_translated @@ -56,7 +55,7 @@ bltn = BuiltinFunction(func) return space.wrap(bltn) - at unwrap_spec(ObjSpace, W_Root, str) + at unwrap_spec(meth=str) def lookup_special(space, w_obj, meth): """Lookup up a special method on an object.""" if space.is_oldstyle_instance(w_obj): From noreply at buildbot.pypy.org Mon May 13 23:39:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 13 May 2013 23:39:41 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Move index.rst to index_old.rst. Message-ID: <20130513213941.2987A1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64051:4c410b98dea5 Date: 2013-05-13 23:18 +0200 http://bitbucket.org/pypy/pypy/changeset/4c410b98dea5/ Log: Move index.rst to index_old.rst. diff --git a/pypy/doc/index.rst b/pypy/doc/index-old.rst rename from pypy/doc/index.rst rename to pypy/doc/index-old.rst From noreply at buildbot.pypy.org Mon May 13 23:39:42 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 13 May 2013 23:39:42 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add skeleton for new index.rst. Message-ID: <20130513213942.6420E1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64052:1c45dad848d0 Date: 2013-05-13 23:19 +0200 http://bitbucket.org/pypy/pypy/changeset/1c45dad848d0/ Log: Add skeleton for new index.rst. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/index.rst @@ -0,0 +1,40 @@ +Welcome to PyPy's documentation! +================================ + +.. TODO write introduction + + +User documentation +------------------ + +.. toctree:: + :maxdepth: 2 + + +Development documentation +------------------------- + +.. toctree:: + :maxdepth: 2 + + +Academical stuff +---------------- + +.. toctree:: + :maxdepth: 2 + + +Contact +------- + +.. TODO add contact information + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + From noreply at buildbot.pypy.org Mon May 13 23:39:43 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 13 May 2013 23:39:43 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add skeletons for install.rst and build.rst. Message-ID: <20130513213943.8CAA91C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64053:614e85af2364 Date: 2013-05-13 23:38 +0200 http://bitbucket.org/pypy/pypy/changeset/614e85af2364/ Log: Add skeletons for install.rst and build.rst. diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/build.rst @@ -0,0 +1,2 @@ +Building PyPy from Source +========================= diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -10,6 +10,9 @@ .. toctree:: :maxdepth: 2 + install + build + Development documentation ------------------------- diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/install.rst @@ -0,0 +1,2 @@ +Downloading and Installing PyPy +=============================== From noreply at buildbot.pypy.org Tue May 14 03:20:36 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 14 May 2013 03:20:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove an obscure feature that's more than a bit broken by design, the ability Message-ID: <20130514012036.AD62E1C141B@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64054:fa194dcff6e6 Date: 2013-05-14 03:19 +0200 http://bitbucket.org/pypy/pypy/changeset/fa194dcff6e6/ Log: Remove an obscure feature that's more than a bit broken by design, the ability to relax the check of signatures. Rationale is that if we have a non-standard graph, we should really not be able to store it anywhere. Replace a bit of unroll iterable magic with code concatanetion - ugly but works and it's actually more understandable (IMO) diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -544,11 +544,27 @@ def make_wrapper(space, callable): "NOT_RPYTHON" names = callable.api_func.argnames - argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes, - [name.startswith("w_") for name in names]))) + argtypes = callable.api_func.argtypes + is_wrapped_list = [name.startswith("w_") for name in names] fatal_value = callable.api_func.restype._defl() - def wrapper(*args): + lines = [] + for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)): + if is_PyObject(argtype) and is_wrapped: + new_lines = [ + 'if %(arg)s:', + ' %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))', + 'else:', + ' %(arg)s = None', + ] + for j in range(len(new_lines)): + new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i} + lines += new_lines + middle = '\n '.join(lines) + arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))]) + + source = py.code.Source(""" + def wrapper(%(args)s): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference retval = fatal_value @@ -556,20 +572,10 @@ try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, - assert len(args) == len(callable.api_func.argtypes) - for i, (typ, is_wrapped) in argtypes_enum_ui: - arg = args[i] - if is_PyObject(typ) and is_wrapped: - if arg: - arg_conv = from_ref(space, rffi.cast(PyObject, arg)) - else: - arg_conv = None - else: - arg_conv = arg - boxed_args += (arg_conv, ) state = space.fromcache(State) + %(middle)s try: - result = callable(space, *boxed_args) + result = callable(space, %(args)s) if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, " DONE" except OperationError, e: @@ -591,8 +597,8 @@ if failed: error_value = callable.api_func.error_value if error_value is CANNOT_FAIL: - raise SystemError("The function '%s' was not supposed to fail" - % (callable.__name__,)) + raise SystemError("The function '%%s' was not supposed to fail" + %% (callable.__name__,)) retval = error_value elif is_PyObject(callable.api_func.restype): @@ -620,6 +626,12 @@ print str(e) pypy_debug_catch_fatal_exception() return retval + """ % {"middle": middle, "args": arg_spec}) + d = {} + d.update(locals()) + d.update(globals()) + exec source.compile() in d + wrapper = d['wrapper'] callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -1017,7 +1029,7 @@ export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): - deco = entrypoint("cpyext", func.argtypes, name, relax=True) + deco = entrypoint("cpyext", func.argtypes, name) deco(func.get_wrapper(space)) setup_init_functions(eci, translating=True) diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py --- a/rpython/annotator/description.py +++ b/rpython/annotator/description.py @@ -215,9 +215,8 @@ if len(self._cache) != 1: raise NoStandardGraph(self) [graph] = self._cache.values() - relax_sig_check = getattr(self.pyobj, "relax_sig_check", False) if (graph.signature != self.signature or - graph.defaults != self.defaults) and not relax_sig_check: + graph.defaults != self.defaults): raise NoStandardGraph(self) return graph diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -3542,16 +3542,6 @@ s = a.build_types(f, [int]) assert s.knowntype is int - def test_relax(self): - def f(*args): - return args[0] + args[1] - f.relax_sig_check = True - def g(x): - return f(x, x - x) - a = self.RPythonAnnotator() - s = a.build_types(g, [int]) - assert a.bookkeeper.getdesc(f).getuniquegraph() - def test_cannot_raise_ll_exception(self): from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr # diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -7,7 +7,7 @@ pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) -def entrypoint(key, argtypes, c_name=None, relax=False): +def entrypoint(key, argtypes, c_name=None): """ Note: entrypoint should call llop.gc_stack_bottom on it's own. That's necessary for making it work with asmgcc and hence JIT @@ -47,8 +47,6 @@ wrapper.func_name = func.func_name if c_name is not None: wrapper.c_name = c_name - if relax: - wrapper.relax_sig_check = True wrapper._compilation_info = ExternalCompilationInfo( export_symbols=[c_name or func.func_name]) return wrapper diff --git a/rpython/translator/c/test/test_genc.py b/rpython/translator/c/test/test_genc.py --- a/rpython/translator/c/test/test_genc.py +++ b/rpython/translator/c/test/test_genc.py @@ -522,9 +522,8 @@ f = getattr(self, "_f", None) if f is not None: return f - f = lambda *args: self.func(*args) + f = lambda arg: self.func(arg) f.c_name = self.name - f.relax_sig_check = True f.__name__ = "WRAP%s" % (self.name, ) self._f = f return f From noreply at buildbot.pypy.org Tue May 14 10:05:01 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 10:05:01 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add more documents to the user TOC. Message-ID: <20130514080501.CD43E1C141B@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64056:7235543590b4 Date: 2013-05-14 10:03 +0200 http://bitbucket.org/pypy/pypy/changeset/7235543590b4/ Log: Add more documents to the user TOC. diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -349,7 +349,7 @@ Features -======== +-------- The following is not meant to be an exhaustive list, since cppyy is still under active development. @@ -652,7 +652,7 @@ Templates -========= +--------- A bit of special care needs to be taken for the use of templates. For a templated class to be completely available, it must be guaranteed that @@ -761,7 +761,7 @@ The fast lane -============= +------------- The following is an experimental feature of cppyy. It mostly works, but there are some known issues (e.g. with return-by-value). @@ -791,7 +791,7 @@ .. _genreflex-methptrgetter.patch: https://bitbucket.org/pypy/pypy/src/default/pypy/module/cppyy/genreflex-methptrgetter.patch CPython -======= +------- Most of the ideas in cppyy come originally from the `PyROOT`_ project. Although PyROOT does not support Reflex directly, it has an alter ego called @@ -845,7 +845,7 @@ Python3 -======= +------- To change versions of CPython (to Python3, another version of Python, or later to the `Py3k`_ version of PyPy), the only part that requires recompilation is diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -12,6 +12,14 @@ install build + cpython_differences + gc_info + jit-hooks + stackless + cppyy + objspace-proxies + sandbox + clr-module Development documentation From noreply at buildbot.pypy.org Tue May 14 10:05:00 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 10:05:00 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Write build.rst, using some paragraphs from getting-started-python.rst. Message-ID: <20130514080500.AB75B1C1406@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64055:c2b77291dab6 Date: 2013-05-14 09:54 +0200 http://bitbucket.org/pypy/pypy/changeset/c2b77291dab6/ Log: Write build.rst, using some paragraphs from getting-started- python.rst. diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst --- a/pypy/doc/build.rst +++ b/pypy/doc/build.rst @@ -1,2 +1,101 @@ Building PyPy from Source ========================= + +For building PyPy, it is recommended to install a pre-build PyPy first (see +:doc:`install`). It is possible to build PyPy with CPython, but it will take a +lot longer to run -- depending on your architecture, between two and three +times as long. + +Even when using PyPy to build PyPy, translation is time-consuming -- 30 +minutes on a fast machine -- and RAM-hungry. You will need **at least** 2 GB +of memory on a 32-bit machine and 4GB on a 64-bit machine. + + +Install build-time dependencies +------------------------------- + +To build PyPy on Unix using the C translation backend, you need at least a C +compiler and ``make`` installed. Further, some optional modules have additional +dependencies: + +cffi, ctypes + libffi, pkg-config + +zlib + libz + +bz2 + libbz2 + +sqlite3 + libsqlite3 + +curses + libncurses + cffi dependencies from above + +pyexpat + libexpat1 + +_ssl + libssl + +Make sure to have these libraries (with development headers) installed before +building PyPy, otherwise the resulting binary will not contain these modules. + +On Debian, this is the command to install all build-time dependencies:: + + apt-get install gcc make libffi-dev pkg-config libz-dev libbz2-dev \ + libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev + +On Fedora:: + + yum install gcc make libffi-devel pkgconfig zlib-devel bzip2-devel \ + lib-sqlite3-devel ncurses-devel expat-devel openssl-devel + + +Run the translation +------------------- + +Translate with JIT:: + + pypy rpython/bin/rpython --opt=jit pypy/goal/targetpypystandalone.py + +Translate without JIT:: + + pypy rpython/bin/rpython --opt=2 pypy/goal/targetpypystandalone.py + +If everything works correctly this will create an executable ``pypy-c`` in the +current directory. The executable behaves mostly like a normal Python +interpreter (see :doc:`cpython differences`). + + +Installation +------------ + +PyPy dynamically finds the location of its libraries depending on the location +of the executable. The directory hierarchy of a typical PyPy installation +looks like this:: + + ./bin/pypy + ./include/ + ./lib_pypy/ + ./lib-python/2.7 + ./site-packages/ + +The hierarchy shown above is relative to a PREFIX directory. PREFIX is +computed by starting from the directory where the executable resides, and +"walking up" the filesystem until we find a directory containing ``lib_pypy`` +and ``lib-python/2.7``. + +To install PyPy system wide on unix-like systems, it is recommended to put the +whole hierarchy alone (e.g. in ``/opt/pypy``) and put a symlink to the +``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin``. + +If the executable fails to find suitable libraries, it will report ``debug: +WARNING: library path not found, using compiled-in sys.path`` and then attempt +to continue normally. If the default path is usable, most code will be fine. +However, the ``sys.prefix`` will be unset and some existing libraries assume +that this is never the case. + + +.. TODO windows From noreply at buildbot.pypy.org Tue May 14 10:17:54 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:17:54 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: shuffle things around to handle op_flags, readwrite almost works Message-ID: <20130514081754.A5C6D1C0498@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r64057:cc555ec312e2 Date: 2013-05-13 22:55 +0300 http://bitbucket.org/pypy/pypy/changeset/cc555ec312e2/ Log: shuffle things around to handle op_flags, readwrite almost works diff --git a/pypy/module/micronumpy/interp_nditer.py b/pypy/module/micronumpy/interp_nditer.py --- a/pypy/module/micronumpy/interp_nditer.py +++ b/pypy/module/micronumpy/interp_nditer.py @@ -2,19 +2,118 @@ from pypy.interpreter.typedef import TypeDef, GetSetProperty, make_weakref_descr from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.error import OperationError -from pypy.module.micronumpy.base import convert_to_array +from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy.strides import calculate_broadcast_strides from pypy.module.micronumpy.iter import MultiDimViewIterator from pypy.module.micronumpy import support +def parse_op_arg(space, name, w_op_flags, n, parse_one_arg): + ret = [] + if space.is_w(w_op_flags, space.w_None): + for i in range(n): + ret.append(OpFlag()) + elif not space.isinstance_w(w_op_flags, space.w_tuple) and not \ + space.isinstance_w(w_op_flags, space.w_list): + raise OperationError(space.w_ValueError, space.wrap( + '%s must be a tuple or array of per-op flag-tuples' % name)) + else: + w_lst = space.listview(w_op_flags) + if space.isinstance_w(w_lst[0], space.w_tuple) or \ + space.isinstance_w(w_lst[0], space.w_list): + if len(w_lst) != n: + raise OperationError(space.w_ValueError, space.wrap( + '%s must be a tuple or array of per-op flag-tuples' % name)) + for item in space.listview(w_lst): + ret.append(parse_one_arg(space, item)) + else: + op_flag = parse_one_arg(space, w_lst) + for i in range(n): + ret.append(op_flag) + return ret -def handle_sequence_args(space, cls, w_seq, w_op_flags, w_op_types, w_op_axes): - ''' - Make sure that len(args) == 1 or len(w_seq) - and set attribs on cls appropriately - ''' - raise OperationError(space.w_NotImplementedError, space.wrap( - 'not implemented yet')) +class OpFlag(object): + def __init__(self): + self.rw = 'r' + self.broadcast = True + self.force_contig = False + self.force_align = False + self.native_byte_order = False + self.tmp_copy = '' + self.allocate = False + self.get_it_item = get_readonly_item + +def get_readonly_item(space, it): + return space.wrap(it.getitem()) + +def get_readwrite_item(space, it): + res = W_NDimArray.from_shape([1], it.dtype, it.array.order) + it.dtype.setitem(res.implementation, 0, it.getitem()) + return res + +def parse_op_flag(space, lst): + op_flag = OpFlag() + for w_item in lst: + item = space.str_w(w_item) + if item == 'readonly': + op_flag.rw = 'r' + elif item == 'readwrite': + op_flag.rw = 'rw' + elif item == 'writeonly': + op_flag.rw = 'w' + elif item == 'no_broadcast': + op_flag.broadcast = False + elif item == 'contig': + op_flag.force_contig = True + elif item == 'aligned': + op_flag.force_align = True + elif item == 'nbo': + op_flag.native_byte_order = True + elif item == 'copy': + op_flag.tmp_copy = 'r' + elif item == 'updateifcopy': + op_flag.tmp_copy = 'rw' + elif item == 'allocate': + op_flag.allocate = True + elif item == 'no_subtype': + raise OperationError(space.w_NotImplementedError, space.wrap( + '"no_subtype" op_flag not implemented yet')) + elif item == 'arraymask': + raise OperationError(space.w_NotImplementedError, space.wrap( + '"arraymask" op_flag not implemented yet')) + elif item == 'writemask': + raise OperationError(space.w_NotImplementedError, space.wrap( + '"writemask" op_flag not implemented yet')) + else: + raise OperationError(space.w_ValueError, space.wrap( + 'op_flags must be a tuple or array of per-op flag-tuples')) + if op_flag.rw == 'r': + op_flag.get_it_item = get_readonly_item + elif op_flag.rw == 'rw': + op_flag.get_it_item = get_readwrite_item + return op_flag + +def get_iter(space, order, imp, backward): + if order == 'K' or (order == 'C' and imp.order == 'C'): + backward = False + elif order =='F' and imp.order == 'C': + backward = True + else: + raise OperationError(space.w_NotImplementedError, space.wrap( + 'not implemented yet')) + if (imp.strides[0] < imp.strides[-1] and not backward) or \ + (imp.strides[0] > imp.strides[-1] and backward): + # flip the strides. Is this always true for multidimension? + strides = [s for s in imp.strides[::-1]] + backstrides = [s for s in imp.backstrides[::-1]] + shape = [s for s in imp.shape[::-1]] + else: + strides = imp.strides + backstrides = imp.backstrides + shape = imp.shape + shape1d = [support.product(imp.shape),] + r = calculate_broadcast_strides(strides, backstrides, shape, + shape1d, backward) + return MultiDimViewIterator(imp, imp.dtype, imp.start, r[0], r[1], shape) class W_NDIter(W_Root): @@ -22,33 +121,18 @@ def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, w_itershape, w_buffersize, order): self.order = order - if space.isinstance_w(w_seq, space.w_tuple) or space.isinstance_w(w_seq, space.w_list): - handle_sequence_args(space, self, w_seq, w_op_flags, w_op_dtypes, w_op_axes) + if space.isinstance_w(w_seq, space.w_tuple) or \ + space.isinstance_w(w_seq, space.w_list): + w_seq_as_list = space.listview(w_seq) + self.seq = [convert_to_array(space, w_elem) for w_elem in w_seq_as_list] else: self.seq =[convert_to_array(space, w_seq)] - if order == 'K' or (order == 'C' and self.seq[0].get_order() == 'C'): - backward = False - elif order =='F' and self.seq[0].get_order() == 'C': - backward = True - else: - raise OperationError(space.w_NotImplementedError, space.wrap( - 'not implemented yet')) - imp = self.seq[0].implementation - if (imp.strides[0] < imp.strides[-1] and not backward) or \ - (imp.strides[0] > imp.strides[-1] and backward): - # flip the strides. Is this always true for multidimension? - strides = [s for s in imp.strides[::-1]] - backstrides = [s for s in imp.backstrides[::-1]] - shape = [s for s in imp.shape[::-1]] - else: - strides = imp.strides - backstrides = imp.backstrides - shape = imp.shape - shape1d = [support.product(imp.shape),] - r = calculate_broadcast_strides(strides, backstrides, shape, - shape1d, backward) - self.iters = [MultiDimViewIterator(imp, imp.dtype, imp.start, r[0], r[1], - shape)] + self.op_flags = parse_op_arg(space, 'op_flags', w_op_flags, + len(self.seq), parse_op_flag) + self.iters=[] + for i in range(len(self.seq)): + self.iters.append(get_iter(space, self.order, + self.seq[i].implementation, self.op_flags[i])) def descr_iter(self, space): return space.wrap(self) @@ -72,9 +156,9 @@ else: raise OperationError(space.w_StopIteration, space.w_None) res = [] - for it in self.iters: - res.append(space.wrap(it.getitem())) - it.next() + for i in range(len(self.iters)): + res.append(self.op_flags[i].get_it_item(space, self.iters[i])) + self.iters[i].next() if len(res) <2: return res[0] return space.newtuple(res) diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py --- a/pypy/module/micronumpy/test/test_nditer.py +++ b/pypy/module/micronumpy/test/test_nditer.py @@ -39,6 +39,7 @@ from numpypy import arange, nditer a = arange(6).reshape(2,3) for x in nditer(a, op_flags=['readwrite']): + print x,x.shape x[...] = 2 * x assert (a == [[0, 2, 4], [6, 8, 10]]).all() From noreply at buildbot.pypy.org Tue May 14 10:17:55 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:17:55 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-ellipse-indexing: allow [...] indexes Message-ID: <20130514081755.B921F1C0498@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-ellipse-indexing Changeset: r64058:9dc626904e11 Date: 2013-05-13 23:34 +0300 http://bitbucket.org/pypy/pypy/changeset/9dc626904e11/ Log: allow [...] indexes From noreply at buildbot.pypy.org Tue May 14 10:17:56 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:17:56 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-ellipse-indexing: a failing test Message-ID: <20130514081756.F16411C0498@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-ellipse-indexing Changeset: r64059:8f5b4f1c5864 Date: 2013-05-13 23:45 +0300 http://bitbucket.org/pypy/pypy/changeset/8f5b4f1c5864/ Log: a failing test diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1634,7 +1634,7 @@ assert (zeros(1)[[]] == []).all() def test_int_array_index_setitem(self): - from numpypy import arange, zeros, array + from numpypy import arange, zeros a = arange(10) a[[3, 2, 1, 5]] = zeros(4, dtype=int) assert (a == [0, 0, 0, 0, 4, 0, 6, 7, 8, 9]).all() @@ -1661,6 +1661,12 @@ assert (b == [20, 1, 21, 3, 4]).all() raises(ValueError, "array([1, 2])[array([True, False, True])] = [1, 2, 3]") + def test_ellipse_index_setitem(self): + from numpypy import arange + b = arange(5) + b[...] = 100 + assert (b == 100).all() + def test_weakref(self): import _weakref from numpypy import array From noreply at buildbot.pypy.org Tue May 14 10:17:58 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:17:58 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-ellipse-indexing: wip, passes test_ztranslation Message-ID: <20130514081758.811351C0498@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-ellipse-indexing Changeset: r64060:583a3ab54db6 Date: 2013-05-14 00:59 +0300 http://bitbucket.org/pypy/pypy/changeset/583a3ab54db6/ Log: wip, passes test_ztranslation diff --git a/pypy/interpreter/special.py b/pypy/interpreter/special.py --- a/pypy/interpreter/special.py +++ b/pypy/interpreter/special.py @@ -5,13 +5,13 @@ def __init__(self, space): self.space = space - def descr__repr__(self): - return self.space.wrap('Ellipsis') + def descr__repr__(self, space): + return space.wrap('Ellipsis') class NotImplemented(W_Root): def __init__(self, space): self.space = space - def descr__repr__(self): - return self.space.wrap('NotImplemented') + def descr__repr__(self, space): + return space.wrap('NotImplemented') diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -13,6 +13,7 @@ raw_storage_setitem, RAW_STORAGE from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized +from pypy.interpreter.special import Ellipsis class BaseConcreteArray(base.BaseArrayImplementation): @@ -157,6 +158,7 @@ """ if (space.isinstance_w(w_idx, space.w_str) or space.isinstance_w(w_idx, space.w_slice) or + isinstance(w_idx, Ellipsis) or space.is_w(w_idx, space.w_None)): raise IndexError if isinstance(w_idx, W_NDimArray) and not isinstance(w_idx.implementation, scalar.Scalar): From noreply at buildbot.pypy.org Tue May 14 10:17:59 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:17:59 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-ellipse-indexing: implement, tests pass Message-ID: <20130514081759.D55F61C0498@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-ellipse-indexing Changeset: r64061:6d277aa40577 Date: 2013-05-14 09:15 +0300 http://bitbucket.org/pypy/pypy/changeset/6d277aa40577/ Log: implement, tests pass diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -205,7 +205,7 @@ if (space.isinstance_w(w_idx, space.w_int) or space.isinstance_w(w_idx, space.w_slice)): return Chunks([Chunk(*space.decode_index4(w_idx, self.get_shape()[0]))]) - elif space.is_w(w_idx, space.w_None): + elif space.is_w(w_idx, space.w_None) or isinstance(w_idx, Ellipsis): return Chunks([NewAxisChunk()]) result = [] i = 0 diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -20,6 +20,7 @@ from rpython.rlib import jit from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation +from pypy.interpreter.special import Ellipsis def _find_shape(space, w_size): if space.is_none(w_size): @@ -167,6 +168,8 @@ prefix) def descr_getitem(self, space, w_idx): + if isinstance(w_idx, Ellipsis): + return self if (isinstance(w_idx, W_NDimArray) and w_idx.get_dtype().is_bool_type()): return self.getitem_filter(space, w_idx) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1661,11 +1661,17 @@ assert (b == [20, 1, 21, 3, 4]).all() raises(ValueError, "array([1, 2])[array([True, False, True])] = [1, 2, 3]") - def test_ellipse_index_setitem(self): + def test_ellipse_index(self): from numpypy import arange - b = arange(5) + b = arange(24).reshape(2,3,4) b[...] = 100 assert (b == 100).all() + assert b.shape == (2, 3, 4) + b[...] = [10, 20, 30, 40] + assert (b[:,:,0] == 10).all() + assert (b[0,0,:] == [10, 20, 30, 40]).all() + assert b.shape == b[...].shape + assert (b == b[...]).all() def test_weakref(self): import _weakref From noreply at buildbot.pypy.org Tue May 14 10:18:01 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:18:01 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-ellipse-indexing: merge default into branch Message-ID: <20130514081801.A0CBE1C009D@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-ellipse-indexing Changeset: r64062:217b2f17b5c6 Date: 2013-05-14 09:15 +0300 http://bitbucket.org/pypy/pypy/changeset/217b2f17b5c6/ Log: merge default into branch diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -81,6 +81,13 @@ from rpython.rlib.entrypoint import entrypoint from rpython.rtyper.lltypesystem import rffi, lltype + w_pathsetter = space.appexec([], """(): + def f(path): + import sys + sys.path[:] = path + return f + """) + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') def pypy_setup_home(ll_home, verbose): from pypy.module.sys.initpath import pypy_find_stdlib @@ -88,11 +95,13 @@ home = rffi.charp2str(ll_home) else: home = pypydir - if space.is_none(pypy_find_stdlib(space, home)): + w_path = pypy_find_stdlib(space, home) + if space.is_none(w_path): if verbose: debug("Failed to find library based on pypy_find_stdlib") return 1 space.startup() + space.call_function(w_pathsetter, w_path) # import site try: import_ = space.getattr(space.getbuiltinmodule('__builtin__'), diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,4 +1,3 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import unwrap_spec from rpython.rlib.objectmodel import we_are_translated @@ -56,7 +55,7 @@ bltn = BuiltinFunction(func) return space.wrap(bltn) - at unwrap_spec(ObjSpace, W_Root, str) + at unwrap_spec(meth=str) def lookup_special(space, w_obj, meth): """Lookup up a special method on an object.""" if space.is_oldstyle_instance(w_obj): diff --git a/pypy/module/array/__init__.py b/pypy/module/array/__init__.py --- a/pypy/module/array/__init__.py +++ b/pypy/module/array/__init__.py @@ -1,12 +1,5 @@ from pypy.interpreter.mixedmodule import MixedModule -from pypy.module.array.interp_array import types -from pypy.objspace.std.model import registerimplementation - -for mytype in types.values(): - registerimplementation(mytype.w_class) - - class Module(MixedModule): interpleveldefs = { 'array': 'interp_array.W_ArrayBase', 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 @@ -2,17 +2,14 @@ from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr +from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef +from pypy.interpreter.baseobjspace import W_Root from pypy.module._file.interp_file import W_File -from pypy.objspace.std.model import W_Object -from pypy.objspace.std.multimethod import FailedToImplement -from pypy.objspace.std.stdtypedef import SMM, StdTypeDef -from pypy.objspace.std.register_all import register_all from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.objectmodel import specialize, keepalive_until_here +from rpython.rlib.objectmodel import keepalive_until_here from rpython.rtyper.lltypesystem import lltype, rffi @@ -39,9 +36,9 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(space.str_w(w_initializer)) + a.descr_fromstring(space, space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_list: - a.fromlist(w_initializer) + a.descr_fromlist(space, w_initializer) else: a.extend(w_initializer, True) break @@ -52,31 +49,6 @@ return a -array_append = SMM('append', 2) -array_extend = SMM('extend', 2) - -array_count = SMM('count', 2) -array_index = SMM('index', 2) -array_reverse = SMM('reverse', 1) -array_remove = SMM('remove', 2) -array_pop = SMM('pop', 2, defaults=(-1,)) -array_insert = SMM('insert', 3) - -array_tolist = SMM('tolist', 1) -array_fromlist = SMM('fromlist', 2) -array_tostring = SMM('tostring', 1) -array_fromstring = SMM('fromstring', 2) -array_tounicode = SMM('tounicode', 1) -array_fromunicode = SMM('fromunicode', 2) -array_tofile = SMM('tofile', 2) -array_fromfile = SMM('fromfile', 3) - -array_buffer_info = SMM('buffer_info', 1) -array_reduce = SMM('__reduce__', 1) -array_copy = SMM('__copy__', 1) -array_byteswap = SMM('byteswap', 1) - - def descr_itemsize(space, self): return space.wrap(self.itemsize) @@ -84,28 +56,476 @@ def descr_typecode(space, self): return space.wrap(self.typecode) +arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') +EQ, NE, LT, LE, GT, GE = range(6) -class W_ArrayBase(W_Object): - @staticmethod - def register(typeorder): - typeorder[W_ArrayBase] = [] +def compare_arrays(space, arr1, arr2, comp_op, comp_func): + if (not isinstance(arr1, W_ArrayBase) or + not isinstance(arr2, W_ArrayBase)): + return space.w_NotImplemented + if comp_op == EQ and arr1.len != arr2.len: + return space.w_False + if comp_op == NE and arr1.len != arr2.len: + return space.w_True + lgt = min(arr1.len, arr2.len) + for i in range(lgt): + arr_eq_driver.jit_merge_point(comp_func=comp_func) + w_elem1 = arr1.w_getitem(space, i) + w_elem2 = arr2.w_getitem(space, i) + res = space.is_true(comp_func(w_elem1, w_elem2)) + if comp_op == EQ: + if not res: + return space.w_False + elif comp_op == NE: + if res: + return space.w_True + elif comp_op == LT or comp_op == GT: + if res: + return space.w_True + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_False + else: + if not res: + return space.w_False + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_True + # we have some leftovers + if comp_op == EQ: + return space.w_True + elif comp_op == NE: + return space.w_False + if arr1.len == arr2.len: + if comp_op == LT or comp_op == GT: + return space.w_False + return space.w_True + if comp_op == LT or comp_op == LE: + if arr1.len < arr2.len: + return space.w_False + return space.w_True + if arr1.len > arr2.len: + return space.w_False + return space.w_True -W_ArrayBase.typedef = StdTypeDef( +UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, + hints={'nolength': True})) + +class W_ArrayBase(W_Root): + _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer + + def __init__(self, space): + self.space = space + self.len = 0 + self.allocated = 0 + + def descr_append(self, space, w_x): + """ append(x) + + Append new value x to the end of the array. + """ + raise NotImplementedError + + def descr_extend(self, space, w_x): + """ extend(array or iterable) + + Append items to the end of the array. + """ + self.extend(w_x) + + def descr_count(self, space, w_val): + """ count(x) + + Return number of occurrences of x in the array. + """ + raise NotImplementedError + + def descr_index(self, space, w_x): + """ index(x) + + Return index of first occurrence of x in the array. + """ + raise NotImplementedError + + def descr_reverse(self, space): + """ reverse() + + Reverse the order of the items in the array. + """ + raise NotImplementedError + + def descr_remove(self, space, w_val): + """ remove(x) + + Remove the first occurrence of x in the array. + """ + raise NotImplementedError + + @unwrap_spec(i=int) + def descr_pop(self, space, i=-1): + """ pop([i]) + + Return the i-th element and delete it from the array. i defaults to -1. + """ + raise NotImplementedError + + @unwrap_spec(idx=int) + def descr_insert(self, space, idx, w_val): + """ insert(i,x) + + Insert a new item x into the array before position i. + """ + raise NotImplementedError + + def descr_tolist(self, space): + """ tolist() -> list + + Convert array to an ordinary list with the same items. + """ + w_l = space.newlist([]) + for i in range(self.len): + w_l.append(self.w_getitem(space, i)) + return w_l + + def descr_fromlist(self, space, w_lst): + """ fromlist(list) + + Append items to array from list. + """ + if not space.isinstance_w(w_lst, space.w_list): + raise OperationError(space.w_TypeError, + space.wrap("arg must be list")) + s = self.len + try: + self.fromsequence(w_lst) + except OperationError: + self.setlen(s) + raise + + def descr_tostring(self, space): + """ tostring() -> string + + Convert the array to an array of machine values and return the string + representation. + """ + cbuf = self._charbuf_start() + s = rffi.charpsize2str(cbuf, self.len * self.itemsize) + self._charbuf_stop() + return self.space.wrap(s) + + @unwrap_spec(s=str) + def descr_fromstring(self, space, s): + """ fromstring(string) + + Appends items from the string, interpreting it as an array of machine + values,as if it had been read from a file using the fromfile() method). + """ + if len(s) % self.itemsize != 0: + msg = 'string length not a multiple of item size' + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) + oldlen = self.len + new = len(s) / self.itemsize + self.setlen(oldlen + new) + cbuf = self._charbuf_start() + for i in range(len(s)): + cbuf[oldlen * self.itemsize + i] = s[i] + self._charbuf_stop() + + @unwrap_spec(w_f=W_File, n=int) + def descr_fromfile(self, space, w_f, n): + """ fromfile(f, n) + + Read n objects from the file object f and append them to the end of the + array. Also called as read. + """ + try: + size = ovfcheck(self.itemsize * n) + except OverflowError: + raise MemoryError + w_item = space.call_method(w_f, 'read', space.wrap(size)) + item = space.str_w(w_item) + if len(item) < size: + n = len(item) % self.itemsize + elems = max(0, len(item) - (len(item) % self.itemsize)) + if n != 0: + item = item[0:elems] + self.descr_fromstring(space, item) + msg = "not enough items in file" + raise OperationError(space.w_EOFError, space.wrap(msg)) + self.descr_fromstring(space, item) + + @unwrap_spec(w_f=W_File) + def descr_tofile(self, space, w_f): + """ tofile(f) + + Write all items (as machine values) to the file object f. Also called as + write. + """ + w_s = self.descr_tostring(space) + space.call_method(w_f, 'write', w_s) + + def descr_fromunicode(self, space, w_ustr): + """ fromunicode(ustr) + + Extends this array with data from the unicode string ustr. + The array must be a type 'u' array; otherwise a ValueError + is raised. Use array.fromstring(ustr.decode(...)) to + append Unicode data to an array of some other type. + """ + # XXX the following probable bug is not emulated: + # CPython accepts a non-unicode string or a buffer, and then + # behaves just like fromstring(), except that it strangely truncate + # string arguments at multiples of the unicode byte size. + # Let's only accept unicode arguments for now. + if self.typecode == 'u': + self.fromsequence(w_ustr) + else: + msg = "fromunicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_tounicode(self, space): + """ tounicode() -> unicode + + Convert the array to a unicode string. The array must be + a type 'u' array; otherwise a ValueError is raised. Use + array.tostring().decode() to obtain a unicode string from + an array of some other type. + """ + if self.typecode == 'u': + buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned()) + return space.wrap(rffi.wcharpsize2unicode(buf, self.len)) + else: + msg = "tounicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_buffer_info(self, space): + """ buffer_info() -> (address, length) + + Return a tuple (address, length) giving the current memory address and + the length in items of the buffer used to hold array's contents + The length should be multiplied by the itemsize attribute to calculate + the buffer length in bytes. + """ + w_ptr = space.wrap(self._buffer_as_unsigned()) + w_len = space.wrap(self.len) + return space.newtuple([w_ptr, w_len]) + + def descr_reduce(self, space): + """ Return state information for pickling. + """ + if self.len > 0: + w_s = self.descr_tostring(space) + args = [space.wrap(self.typecode), w_s] + else: + args = [space.wrap(self.typecode)] + try: + dct = space.getattr(self, space.wrap('__dict__')) + except OperationError: + dct = space.w_None + return space.newtuple([space.type(self), space.newtuple(args), dct]) + + def descr_copy(self, space): + """ copy(array) + + Return a copy of the array. + """ + w_a = self.constructor(self.space) + w_a.setlen(self.len, overallocate=False) + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()), + rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()), + self.len * self.itemsize + ) + return w_a + + def descr_byteswap(self, space): + """ byteswap() + + Byteswap all items of the array. If the items in the array are not 1, 2, + 4, or 8 bytes in size, RuntimeError is raised. + """ + if self.itemsize not in [1, 2, 4, 8]: + msg = "byteswap not supported for this array" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + if self.len == 0: + return + bytes = self._charbuf_start() + tmp = [bytes[0]] * self.itemsize + for start in range(0, self.len * self.itemsize, self.itemsize): + stop = start + self.itemsize - 1 + for i in range(self.itemsize): + tmp[i] = bytes[start + i] + for i in range(self.itemsize): + bytes[stop - i] = tmp[i] + self._charbuf_stop() + + def descr_len(self, space): + return space.wrap(self.len) + + def descr_eq(self, space, w_arr2): + "x.__eq__(y) <==> x==y" + return compare_arrays(space, self, w_arr2, EQ, space.eq) + + def descr_ne(self, space, w_arr2): + "x.__ne__(y) <==> x!=y" + return compare_arrays(space, self, w_arr2, NE, space.ne) + + def descr_lt(self, space, w_arr2): + "x.__lt__(y) <==> x x<=y" + return compare_arrays(space, self, w_arr2, LE, space.le) + + def descr_gt(self, space, w_arr2): + "x.__gt__(y) <==> x>y" + return compare_arrays(space, self, w_arr2, GT, space.gt) + + def descr_ge(self, space, w_arr2): + "x.__ge__(y) <==> x>=y" + return compare_arrays(space, self, w_arr2, GE, space.ge) + + # Basic get/set/append/extend methods + + def descr_getitem(self, space, w_idx): + "x.__getitem__(y) <==> x[y]" + if not space.isinstance_w(w_idx, space.w_slice): + idx, stop, step = space.decode_index(w_idx, self.len) + assert step == 0 + return self.w_getitem(space, idx) + else: + return self.getitem_slice(space, w_idx) + + def descr_getslice(self, space, w_i, w_j): + return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) + + + def descr_setitem(self, space, w_idx, w_item): + "x.__setitem__(i, y) <==> x[i]=y" + if space.isinstance_w(w_idx, space.w_slice): + self.setitem_slice(space, w_idx, w_item) + else: + self.setitem(space, w_idx, w_item) + + def descr_setslice(self, space, w_start, w_stop, w_item): + self.setitem_slice(space, + space.newslice(w_start, w_stop, space.w_None), + w_item) + + def descr_delitem(self, space, w_idx): + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + if step != 1: + # I don't care about efficiency of that so far + w_lst = self.descr_tolist(space) + space.delitem(w_lst, w_idx) + self.setlen(0) + self.fromsequence(w_lst) + return + return self.delitem(space, start, stop) + + def descr_delslice(self, space, w_start, w_stop): + self.descr_delitem(space, space.newslice(w_start, w_stop, space.w_None)) + + def descr_add(self, space, w_other): + raise NotImplementedError + + def descr_inplace_add(self, space, w_other): + raise NotImplementedError + + def descr_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_inplace_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_radd(self, space, w_other): + return self.descr_add(space, w_other) + + def descr_rmul(self, space, w_repeat): + return self.descr_mul(space, w_repeat) + + # Misc methods + + def descr_buffer(self, space): + return space.wrap(ArrayBuffer(self)) + + def descr_repr(self, space): + if self.len == 0: + return space.wrap("array('%s')" % self.typecode) + elif self.typecode == "c": + r = space.repr(self.descr_tostring(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + elif self.typecode == "u": + r = space.repr(self.descr_tounicode(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + else: + r = space.repr(self.descr_tolist(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + +W_ArrayBase.typedef = TypeDef( 'array', __new__ = interp2app(w_array), __module__ = 'array', + + __len__ = interp2app(W_ArrayBase.descr_len), + __eq__ = interp2app(W_ArrayBase.descr_eq), + __ne__ = interp2app(W_ArrayBase.descr_ne), + __lt__ = interp2app(W_ArrayBase.descr_lt), + __le__ = interp2app(W_ArrayBase.descr_le), + __gt__ = interp2app(W_ArrayBase.descr_gt), + __ge__ = interp2app(W_ArrayBase.descr_ge), + + __getitem__ = interp2app(W_ArrayBase.descr_getitem), + __getslice__ = interp2app(W_ArrayBase.descr_getslice), + __setitem__ = interp2app(W_ArrayBase.descr_setitem), + __setslice__ = interp2app(W_ArrayBase.descr_setslice), + __delitem__ = interp2app(W_ArrayBase.descr_delitem), + __delslice__ = interp2app(W_ArrayBase.descr_delslice), + + __add__ = interpindirect2app(W_ArrayBase.descr_add), + __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add), + __mul__ = interpindirect2app(W_ArrayBase.descr_mul), + __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul), + __radd__ = interp2app(W_ArrayBase.descr_radd), + __rmul__ = interp2app(W_ArrayBase.descr_rmul), + + __buffer__ = interp2app(W_ArrayBase.descr_buffer), + __repr__ = interp2app(W_ArrayBase.descr_repr), + itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), + append = interpindirect2app(W_ArrayBase.descr_append), + extend = interp2app(W_ArrayBase.descr_extend), + count = interpindirect2app(W_ArrayBase.descr_count), + index = interpindirect2app(W_ArrayBase.descr_index), + reverse = interpindirect2app(W_ArrayBase.descr_reverse), + remove = interpindirect2app(W_ArrayBase.descr_remove), + pop = interpindirect2app(W_ArrayBase.descr_pop), + insert = interpindirect2app(W_ArrayBase.descr_insert), + + tolist = interp2app(W_ArrayBase.descr_tolist), + fromlist = interp2app(W_ArrayBase.descr_fromlist), + tostring = interp2app(W_ArrayBase.descr_tostring), + fromstring = interp2app(W_ArrayBase.descr_fromstring), + tofile = interp2app(W_ArrayBase.descr_tofile), + fromfile = interp2app(W_ArrayBase.descr_fromfile), + fromunicode = interp2app(W_ArrayBase.descr_fromunicode), + tounicode = interp2app(W_ArrayBase.descr_tounicode), + + buffer_info = interp2app(W_ArrayBase.descr_buffer_info), + __copy__ = interp2app(W_ArrayBase.descr_copy), + __reduce__ = interp2app(W_ArrayBase.descr_reduce), + byteswap = interp2app(W_ArrayBase.descr_byteswap), ) -W_ArrayBase.typedef.registermethods(globals()) class TypeCode(object): def __init__(self, itemtype, unwrap, canoverflow=False, signed=False): self.itemtype = itemtype self.bytes = rffi.sizeof(itemtype) - #self.arraytype = lltype.GcArray(itemtype) self.arraytype = lltype.Array(itemtype, hints={'nolength': True}) self.unwrap = unwrap self.signed = signed @@ -175,14 +595,10 @@ itemsize = mytype.bytes typecode = mytype.typecode - @staticmethod - def register(typeorder): - typeorder[W_Array] = [(W_ArrayBase, None)] + _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer') def __init__(self, space): - self.space = space - self.len = 0 - self.allocated = 0 + W_ArrayBase.__init__(self, space) self.buffer = lltype.nullptr(mytype.arraytype) def item_w(self, w_item): @@ -289,26 +705,6 @@ raise self.setlen(oldlen + i) - def fromstring(self, s): - if len(s) % self.itemsize != 0: - msg = 'string length not a multiple of item size' - raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) - oldlen = self.len - new = len(s) / mytype.bytes - self.setlen(oldlen + new) - cbuf = self._charbuf_start() - for i in range(len(s)): - cbuf[oldlen * mytype.bytes + i] = s[i] - self._charbuf_stop() - - def fromlist(self, w_lst): - s = self.len - try: - self.fromsequence(w_lst) - except OperationError: - self.setlen(s) - raise - def extend(self, w_iterable, accept_different_array=False): space = self.space if isinstance(w_iterable, W_Array): @@ -332,6 +728,9 @@ def _charbuf_start(self): return rffi.cast(rffi.CCHARP, self.buffer) + def _buffer_as_unsigned(self): + return rffi.cast(lltype.Unsigned, self.buffer) + def _charbuf_stop(self): keepalive_until_here(self) @@ -343,202 +742,180 @@ item = float(item) return space.wrap(item) - # Basic get/set/append/extend methods + # interface - def len__Array(space, self): - return space.wrap(self.len) + def descr_append(self, space, w_x): + x = self.item_w(w_x) + self.setlen(self.len + 1) + self.buffer[self.len - 1] = x - def getitem__Array_ANY(space, self, w_idx): - idx, stop, step = space.decode_index(w_idx, self.len) - assert step == 0 - return self.w_getitem(space, idx) + # List interface + def descr_count(self, space, w_val): + cnt = 0 + for i in range(self.len): + # XXX jitdriver + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + cnt += 1 + return space.wrap(cnt) - def getitem__Array_Slice(space, self, w_slice): - start, stop, step, size = space.decode_index4(w_slice, self.len) - w_a = mytype.w_class(self.space) - w_a.setlen(size, overallocate=False) - assert step != 0 - j = 0 - for i in range(start, stop, step): - w_a.buffer[j] = self.buffer[i] - j += 1 - return w_a + def descr_index(self, space, w_val): + for i in range(self.len): + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + return space.wrap(i) + msg = 'array.index(x): x not in list' + raise OperationError(space.w_ValueError, space.wrap(msg)) - def getslice__Array_ANY_ANY(space, self, w_i, w_j): - return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) + def descr_reverse(self, space): + b = self.buffer + for i in range(self.len / 2): + b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] - def setitem__Array_ANY_ANY(space, self, w_idx, w_item): - idx, stop, step = space.decode_index(w_idx, self.len) - if step != 0: - msg = 'can only assign array to array slice' - raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) - item = self.item_w(w_item) - self.buffer[idx] = item + def descr_pop(self, space, i): + if i < 0: + i += self.len + if i < 0 or i >= self.len: + msg = 'pop index out of range' + raise OperationError(space.w_IndexError, space.wrap(msg)) + w_val = self.w_getitem(space, i) + while i < self.len - 1: + self.buffer[i] = self.buffer[i + 1] + i += 1 + self.setlen(self.len - 1) + return w_val - def setitem__Array_Slice_Array(space, self, w_idx, w_item): - start, stop, step, size = self.space.decode_index4(w_idx, self.len) - assert step != 0 - if w_item.len != size or self is w_item: - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - w_item = space.call_method(w_item, 'tolist') - space.setitem(w_lst, w_idx, w_item) - self.setlen(0) - self.fromsequence(w_lst) - else: + def descr_remove(self, space, w_val): + w_idx = self.descr_index(space, w_val) + self.descr_pop(space, space.int_w(w_idx)) + + def descr_insert(self, space, idx, w_val): + if idx < 0: + idx += self.len + if idx < 0: + idx = 0 + if idx > self.len: + idx = self.len + + val = self.item_w(w_val) + self.setlen(self.len + 1) + i = self.len - 1 + while i > idx: + self.buffer[i] = self.buffer[i - 1] + i -= 1 + self.buffer[i] = val + + def getitem_slice(self, space, w_idx): + start, stop, step, size = space.decode_index4(w_idx, self.len) + w_a = mytype.w_class(self.space) + w_a.setlen(size, overallocate=False) + assert step != 0 j = 0 for i in range(start, stop, step): - self.buffer[i] = w_item.buffer[j] + w_a.buffer[j] = self.buffer[i] j += 1 + return w_a - def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x): - space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x) + def setitem(self, space, w_idx, w_item): + idx, stop, step = space.decode_index(w_idx, self.len) + if step != 0: + msg = 'can only assign array to array slice' + raise OperationError(self.space.w_TypeError, + self.space.wrap(msg)) + item = self.item_w(w_item) + self.buffer[idx] = item - def array_append__Array_ANY(space, self, w_x): - x = self.item_w(w_x) - self.setlen(self.len + 1) - self.buffer[self.len - 1] = x + def setitem_slice(self, space, w_idx, w_item): + if not isinstance(w_item, W_Array): + raise OperationError(space.w_TypeError, space.wrap( + "can only assign to a slice array")) + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + assert step != 0 + if w_item.len != size or self is w_item: + # XXX this is a giant slow hack + w_lst = self.descr_tolist(space) + w_item = space.call_method(w_item, 'tolist') + space.setitem(w_lst, w_idx, w_item) + self.setlen(0) + self.fromsequence(w_lst) + else: + j = 0 + for i in range(start, stop, step): + self.buffer[i] = w_item.buffer[j] + j += 1 - def array_extend__Array_ANY(space, self, w_iterable): - self.extend(w_iterable) + # We can't look into this function until ptradd works with things (in the + # JIT) other than rffi.CCHARP + @jit.dont_look_inside + def delitem(self, space, i, j): + if i < 0: + i += self.len + if i < 0: + i = 0 + if j < 0: + j += self.len + if j < 0: + j = 0 + if j > self.len: + j = self.len + if i >= j: + return None + oldbuffer = self.buffer + self.buffer = lltype.malloc(mytype.arraytype, + max(self.len - (j - i), 0), flavor='raw', + add_memory_pressure=True) + if i: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, self.buffer), + rffi.cast(rffi.VOIDP, oldbuffer), + i * mytype.bytes + ) + if j < self.len: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), + rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), + (self.len - j) * mytype.bytes + ) + self.len -= j - i + self.allocated = self.len + if oldbuffer: + lltype.free(oldbuffer, flavor='raw') - # List interface - def array_count__Array_ANY(space, self, w_val): - cnt = 0 - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - cnt += 1 - return space.wrap(cnt) + # Add and mul methods - def array_index__Array_ANY(space, self, w_val): - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - return space.wrap(i) - msg = 'array.index(x): x not in list' - raise OperationError(space.w_ValueError, space.wrap(msg)) + def descr_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + a = mytype.w_class(space) + a.setlen(self.len + w_other.len, overallocate=False) + for i in range(self.len): + a.buffer[i] = self.buffer[i] + for i in range(w_other.len): + a.buffer[i + self.len] = w_other.buffer[i] + return a - def array_reverse__Array(space, self): - b = self.buffer - for i in range(self.len / 2): - b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] + def descr_inplace_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + oldlen = self.len + otherlen = w_other.len + self.setlen(oldlen + otherlen) + for i in range(otherlen): + self.buffer[oldlen + i] = w_other.buffer[i] + return self - def array_pop__Array_ANY(space, self, w_idx): - i = space.int_w(w_idx) - if i < 0: - i += self.len - if i < 0 or i >= self.len: - msg = 'pop index out of range' - raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = self.w_getitem(space, i) - while i < self.len - 1: - self.buffer[i] = self.buffer[i + 1] - i += 1 - self.setlen(self.len - 1) - return w_val + def descr_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, False) - def array_remove__Array_ANY(space, self, w_val): - w_idx = array_index__Array_ANY(space, self, w_val) - array_pop__Array_ANY(space, self, w_idx) - - def array_insert__Array_ANY_ANY(space, self, w_idx, w_val): - idx = space.int_w(w_idx) - if idx < 0: - idx += self.len - if idx < 0: - idx = 0 - if idx > self.len: - idx = self.len - - val = self.item_w(w_val) - self.setlen(self.len + 1) - i = self.len - 1 - while i > idx: - self.buffer[i] = self.buffer[i - 1] - i -= 1 - self.buffer[i] = val - - def delitem__Array_ANY(space, self, w_idx): - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - space.delitem(w_lst, w_idx) - self.setlen(0) - self.fromsequence(w_lst) - - # We can't look into this function until ptradd works with things (in the - # JIT) other than rffi.CCHARP - @jit.dont_look_inside - def delslice__Array_ANY_ANY(space, self, w_i, w_j): - i = space.int_w(w_i) - if i < 0: - i += self.len - if i < 0: - i = 0 - j = space.int_w(w_j) - if j < 0: - j += self.len - if j < 0: - j = 0 - if j > self.len: - j = self.len - if i >= j: - return None - oldbuffer = self.buffer - self.buffer = lltype.malloc(mytype.arraytype, - max(self.len - (j - i), 0), flavor='raw', - add_memory_pressure=True) - if i: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, self.buffer), - rffi.cast(rffi.VOIDP, oldbuffer), - i * mytype.bytes - ) - if j < self.len: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), - rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), - (self.len - j) * mytype.bytes - ) - self.len -= j - i - self.allocated = self.len - if oldbuffer: - lltype.free(oldbuffer, flavor='raw') - - # Add and mul methods - - def add__Array_Array(space, self, other): - a = mytype.w_class(space) - a.setlen(self.len + other.len, overallocate=False) - for i in range(self.len): - a.buffer[i] = self.buffer[i] - for i in range(other.len): - a.buffer[i + self.len] = other.buffer[i] - return a - - def inplace_add__Array_Array(space, self, other): - oldlen = self.len - otherlen = other.len - self.setlen(oldlen + otherlen) - for i in range(otherlen): - self.buffer[oldlen + i] = other.buffer[i] - return self - - def mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, False) - - def mul__ANY_Array(space, w_repeat, self): - return _mul_helper(space, self, w_repeat, False) - - def inplace_mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, True) + def descr_inplace_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, True) def _mul_helper(space, self, w_repeat, is_inplace): try: repeat = space.getindex_w(w_repeat, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - raise FailedToImplement + return space.w_NotImplemented raise repeat = max(repeat, 0) try: @@ -577,186 +954,11 @@ a.buffer[r * oldlen + i] = self.buffer[i] return a - # Convertions - - def array_tolist__Array(space, self): - w_l = space.newlist([]) - for i in range(self.len): - w_l.append(self.w_getitem(space, i)) - return w_l - - def array_fromlist__Array_List(space, self, w_lst): - self.fromlist(w_lst) - - def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(space.str_w(w_s)) - - def array_tostring__Array(space, self): - cbuf = self._charbuf_start() - s = rffi.charpsize2str(cbuf, self.len * mytype.bytes) - self._charbuf_stop() - return self.space.wrap(s) - - def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - n = space.int_w(w_n) - - try: - size = ovfcheck(self.itemsize * n) - except OverflowError: - raise MemoryError - w_item = space.call_method(w_f, 'read', space.wrap(size)) - item = space.str_w(w_item) - if len(item) < size: - n = len(item) % self.itemsize - elems = max(0, len(item) - (len(item) % self.itemsize)) - if n != 0: - item = item[0:elems] - w_item = space.wrap(item) - array_fromstring__Array_ANY(space, self, w_item) - msg = "not enough items in file" - raise OperationError(space.w_EOFError, space.wrap(msg)) - array_fromstring__Array_ANY(space, self, w_item) - - def array_tofile__Array_ANY(space, self, w_f): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_s = array_tostring__Array(space, self) - space.call_method(w_f, 'write', w_s) - - if mytype.typecode == 'u': - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - # XXX the following probable bug is not emulated: - # CPython accepts a non-unicode string or a buffer, and then - # behaves just like fromstring(), except that it strangely truncate - # string arguments at multiples of the unicode byte size. - # Let's only accept unicode arguments for now. - self.fromsequence(w_ustr) - - def array_tounicode__Array(space, self): - return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) - else: - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - msg = "fromunicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - def array_tounicode__Array(space, self): - msg = "tounicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - # Compare methods - @specialize.arg(3) - def _cmp_impl(space, self, other, space_fn): - # XXX this is a giant slow hack - w_lst1 = array_tolist__Array(space, self) - w_lst2 = space.call_method(other, 'tolist') - return space_fn(w_lst1, w_lst2) - - def eq__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.eq) - - def ne__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ne) - - def lt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.lt) - - def le__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.le) - - def gt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.gt) - - def ge__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ge) - - # Misc methods - - def buffer__Array(space, self): - return space.wrap(ArrayBuffer(self)) - - def array_buffer_info__Array(space, self): - w_ptr = space.wrap(rffi.cast(lltype.Unsigned, self.buffer)) - w_len = space.wrap(self.len) - return space.newtuple([w_ptr, w_len]) - - def array_reduce__Array(space, self): - if self.len > 0: - w_s = array_tostring__Array(space, self) - args = [space.wrap(mytype.typecode), w_s] - else: - args = [space.wrap(mytype.typecode)] - try: - dct = space.getattr(self, space.wrap('__dict__')) - except OperationError: - dct = space.w_None - return space.newtuple([space.type(self), space.newtuple(args), dct]) - - def array_copy__Array(space, self): - w_a = mytype.w_class(self.space) - w_a.setlen(self.len, overallocate=False) - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, w_a.buffer), - rffi.cast(rffi.VOIDP, self.buffer), - self.len * mytype.bytes - ) - return w_a - - def array_byteswap__Array(space, self): - if mytype.bytes not in [1, 2, 4, 8]: - msg = "byteswap not supported for this array" - raise OperationError(space.w_RuntimeError, space.wrap(msg)) - if self.len == 0: - return - bytes = self._charbuf_start() - tmp = [bytes[0]] * mytype.bytes - for start in range(0, self.len * mytype.bytes, mytype.bytes): - stop = start + mytype.bytes - 1 - for i in range(mytype.bytes): - tmp[i] = bytes[start + i] - for i in range(mytype.bytes): - bytes[stop - i] = tmp[i] - self._charbuf_stop() - - def repr__Array(space, self): - if self.len == 0: - return space.wrap("array('%s')" % self.typecode) - elif self.typecode == "c": - r = space.repr(array_tostring__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - elif self.typecode == "u": - r = space.repr(array_tounicode__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - else: - r = space.repr(array_tolist__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - mytype.w_class = W_Array - - # Annotator seems to mess up if the names are not unique + W_Array.constructor = W_Array name = 'ArrayType' + mytype.typecode W_Array.__name__ = 'W_' + name - import re - for n, f in locals().items(): - new, n = re.subn('_Array_', '_%s_' % name, n) - if n > 0: - f.__name__ = new - - from pypy.objspace.std.sliceobject import W_SliceObject - from pypy.objspace.std.listobject import W_ListObject - from pypy.objspace.std.unicodeobject import W_UnicodeObject - register_all(locals(), globals()) - for mytype in types.values(): make_array(mytype) - -register_all(locals(), globals()) +del mytype diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -19,7 +19,7 @@ class BaseArrayTests: - + def test_ctor(self): assert len(self.array('c')) == 0 assert len(self.array('i')) == 0 @@ -390,7 +390,6 @@ assert self.array('c', ('h', 'i')).tostring() == 'hi' a = self.array('i', [0, 0, 0]) assert a.tostring() == '\x00' * 3 * a.itemsize - s = self.array('i', [1, 2, 3]).tostring() assert '\x00' in s assert '\x01' in s @@ -502,7 +501,7 @@ return 0 class incomparable(object): pass - + for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'), ('abc', 'acb', 'c'), (unicode('abc'), unicode('acb'), 'u')): @@ -653,14 +652,14 @@ raises(TypeError, "a * 'hi'") raises(TypeError, "'hi' * a") raises(TypeError, "a *= 'hi'") - + class mulable(object): def __mul__(self, other): return "mul" def __rmul__(self, other): return "rmul" - + assert mulable() * self.array('i') == 'mul' assert self.array('i') * mulable() == 'rmul' @@ -769,7 +768,7 @@ def __getitem__(self, i): return array.__getitem__(self, self._index(i)) - + def __setitem__(self, i, val): return array.__setitem__(self, self._index(i), val) @@ -783,7 +782,7 @@ assert img[3, 25] == 3 * 9 - + def test_override_from(self): class mya(self.array): def fromlist(self, lst): @@ -854,7 +853,7 @@ def test_subclass_del(self): import array, gc, weakref l = [] - + class A(array.array): pass diff --git a/pypy/module/array/test/test_ztranslation.py b/pypy/module/array/test/test_ztranslation.py new file mode 100644 --- /dev/null +++ b/pypy/module/array/test/test_ztranslation.py @@ -0,0 +1,6 @@ + +from pypy.objspace.fake.checkmodule import checkmodule + +def test_checkmodule(): + checkmodule('array') + diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -544,11 +544,27 @@ def make_wrapper(space, callable): "NOT_RPYTHON" names = callable.api_func.argnames - argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes, - [name.startswith("w_") for name in names]))) + argtypes = callable.api_func.argtypes + is_wrapped_list = [name.startswith("w_") for name in names] fatal_value = callable.api_func.restype._defl() - def wrapper(*args): + lines = [] + for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)): + if is_PyObject(argtype) and is_wrapped: + new_lines = [ + 'if %(arg)s:', + ' %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))', + 'else:', + ' %(arg)s = None', + ] + for j in range(len(new_lines)): + new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i} + lines += new_lines + middle = '\n '.join(lines) + arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))]) + + source = py.code.Source(""" + def wrapper(%(args)s): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference retval = fatal_value @@ -556,20 +572,10 @@ try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, - assert len(args) == len(callable.api_func.argtypes) - for i, (typ, is_wrapped) in argtypes_enum_ui: - arg = args[i] - if is_PyObject(typ) and is_wrapped: - if arg: - arg_conv = from_ref(space, rffi.cast(PyObject, arg)) - else: - arg_conv = None - else: - arg_conv = arg - boxed_args += (arg_conv, ) state = space.fromcache(State) + %(middle)s try: - result = callable(space, *boxed_args) + result = callable(space, %(args)s) if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, " DONE" except OperationError, e: @@ -591,8 +597,8 @@ if failed: error_value = callable.api_func.error_value if error_value is CANNOT_FAIL: - raise SystemError("The function '%s' was not supposed to fail" - % (callable.__name__,)) + raise SystemError("The function '%%s' was not supposed to fail" + %% (callable.__name__,)) retval = error_value elif is_PyObject(callable.api_func.restype): @@ -620,6 +626,12 @@ print str(e) pypy_debug_catch_fatal_exception() return retval + """ % {"middle": middle, "args": arg_spec}) + d = {} + d.update(locals()) + d.update(globals()) + exec source.compile() in d + wrapper = d['wrapper'] callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -1017,7 +1029,7 @@ export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): - deco = entrypoint("cpyext", func.argtypes, name, relax=True) + deco = entrypoint("cpyext", func.argtypes, name) deco(func.get_wrapper(space)) setup_init_functions(eci, translating=True) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -80,8 +80,6 @@ import pypy.objspace.std.default # register a few catch-all multimethods import pypy.objspace.std.marshal_impl # install marshal multimethods - if config.objspace.usemodules.array: - import pypy.module.array # the set of implementation types self.typeorder = { diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py --- a/rpython/annotator/description.py +++ b/rpython/annotator/description.py @@ -215,9 +215,8 @@ if len(self._cache) != 1: raise NoStandardGraph(self) [graph] = self._cache.values() - relax_sig_check = getattr(self.pyobj, "relax_sig_check", False) if (graph.signature != self.signature or - graph.defaults != self.defaults) and not relax_sig_check: + graph.defaults != self.defaults): raise NoStandardGraph(self) return graph diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -3542,16 +3542,6 @@ s = a.build_types(f, [int]) assert s.knowntype is int - def test_relax(self): - def f(*args): - return args[0] + args[1] - f.relax_sig_check = True - def g(x): - return f(x, x - x) - a = self.RPythonAnnotator() - s = a.build_types(g, [int]) - assert a.bookkeeper.getdesc(f).getuniquegraph() - def test_cannot_raise_ll_exception(self): from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr # diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -7,7 +7,7 @@ pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) -def entrypoint(key, argtypes, c_name=None, relax=False): +def entrypoint(key, argtypes, c_name=None): """ Note: entrypoint should call llop.gc_stack_bottom on it's own. That's necessary for making it work with asmgcc and hence JIT @@ -47,8 +47,6 @@ wrapper.func_name = func.func_name if c_name is not None: wrapper.c_name = c_name - if relax: - wrapper.relax_sig_check = True wrapper._compilation_info = ExternalCompilationInfo( export_symbols=[c_name or func.func_name]) return wrapper diff --git a/rpython/translator/c/test/test_genc.py b/rpython/translator/c/test/test_genc.py --- a/rpython/translator/c/test/test_genc.py +++ b/rpython/translator/c/test/test_genc.py @@ -522,9 +522,8 @@ f = getattr(self, "_f", None) if f is not None: return f - f = lambda *args: self.func(*args) + f = lambda arg: self.func(arg) f.c_name = self.name - f.relax_sig_check = True f.__name__ = "WRAP%s" % (self.name, ) self._f = f return f From noreply at buildbot.pypy.org Tue May 14 10:18:02 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:18:02 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-ellipse-indexing: test, fix for scalars Message-ID: <20130514081802.DC6D11C009D@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-ellipse-indexing Changeset: r64063:2a7f866e80e8 Date: 2013-05-14 11:12 +0300 http://bitbucket.org/pypy/pypy/changeset/2a7f866e80e8/ Log: test, fix for scalars diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -3,6 +3,7 @@ from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support from pypy.interpreter.error import OperationError +from pypy.interpreter.special import Ellipsis class ScalarIterator(base.BaseArrayIterator): def __init__(self, v): @@ -73,7 +74,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +103,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( @@ -119,7 +120,10 @@ space.wrap("scalars cannot be indexed")) def descr_setitem(self, space, _, w_idx, w_val): - raise OperationError(space.w_IndexError, + if isinstance(w_idx, Ellipsis): + self.value = self.dtype.coerce(space, w_val) + else: + raise OperationError(space.w_IndexError, space.wrap("scalars cannot be indexed")) def setitem_index(self, space, idx, w_val): diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -1634,7 +1634,7 @@ assert (zeros(1)[[]] == []).all() def test_int_array_index_setitem(self): - from numpypy import arange, zeros + from numpypy import arange, zeros, array a = arange(10) a[[3, 2, 1, 5]] = zeros(4, dtype=int) assert (a == [0, 0, 0, 0, 4, 0, 6, 7, 8, 9]).all() @@ -1662,7 +1662,7 @@ raises(ValueError, "array([1, 2])[array([True, False, True])] = [1, 2, 3]") def test_ellipse_index(self): - from numpypy import arange + from numpypy import arange, array b = arange(24).reshape(2,3,4) b[...] = 100 assert (b == 100).all() @@ -1673,6 +1673,11 @@ assert b.shape == b[...].shape assert (b == b[...]).all() + a = array(1) + a[...] = 100 + assert (a == 100).all() + assert a == a[...] + def test_weakref(self): import _weakref from numpypy import array From noreply at buildbot.pypy.org Tue May 14 10:18:03 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 10:18:03 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: reopen closed branch for failing ztranslation test Message-ID: <20130514081803.F1ED91C009D@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: remove-array-smm Changeset: r64064:13c604db8178 Date: 2013-05-14 11:14 +0300 http://bitbucket.org/pypy/pypy/changeset/13c604db8178/ Log: reopen closed branch for failing ztranslation test diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -63,6 +63,10 @@ def get_module(self): return w_some_obj() +class W_List(W_MyObject): + def append(self, item): + return self + def w_some_obj(): if NonConstant(False): return W_Root() @@ -131,7 +135,7 @@ def newlist(self, list_w): for w_x in list_w: is_root(w_x) - return w_some_obj() + return W_List() def newslice(self, w_start, w_end, w_step): is_root(w_start) From noreply at buildbot.pypy.org Tue May 14 13:16:41 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 13:16:41 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: readwrite works Message-ID: <20130514111641.6FFE71C1422@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r64066:8b31168ea449 Date: 2013-05-14 14:07 +0300 http://bitbucket.org/pypy/pypy/changeset/8b31168ea449/ Log: readwrite works diff --git a/pypy/module/micronumpy/interp_nditer.py b/pypy/module/micronumpy/interp_nditer.py --- a/pypy/module/micronumpy/interp_nditer.py +++ b/pypy/module/micronumpy/interp_nditer.py @@ -6,6 +6,7 @@ from pypy.module.micronumpy.strides import calculate_broadcast_strides from pypy.module.micronumpy.iter import MultiDimViewIterator from pypy.module.micronumpy import support +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray def parse_op_arg(space, name, w_op_flags, n, parse_one_arg): ret = [] @@ -42,13 +43,14 @@ self.allocate = False self.get_it_item = get_readonly_item -def get_readonly_item(space, it): +def get_readonly_item(space, array, it): return space.wrap(it.getitem()) -def get_readwrite_item(space, it): - res = W_NDimArray.from_shape([1], it.dtype, it.array.order) - it.dtype.setitem(res.implementation, 0, it.getitem()) - return res +def get_readwrite_item(space, array, it): + #create a single-value view (since scalars are not views) + res = SliceArray(it.array.start + it.offset, [0], [0], [1,], it.array, array) + #it.dtype.setitem(res, 0, it.getitem()) + return W_NDimArray(res) def parse_op_flag(space, lst): op_flag = OpFlag() @@ -157,7 +159,8 @@ raise OperationError(space.w_StopIteration, space.w_None) res = [] for i in range(len(self.iters)): - res.append(self.op_flags[i].get_it_item(space, self.iters[i])) + res.append(self.op_flags[i].get_it_item(space, self.seq[i], + self.iters[i])) self.iters[i].next() if len(res) <2: return res[0] diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py --- a/pypy/module/micronumpy/test/test_nditer.py +++ b/pypy/module/micronumpy/test/test_nditer.py @@ -39,7 +39,6 @@ from numpypy import arange, nditer a = arange(6).reshape(2,3) for x in nditer(a, op_flags=['readwrite']): - print x,x.shape x[...] = 2 * x assert (a == [[0, 2, 4], [6, 8, 10]]).all() @@ -53,6 +52,7 @@ r = [] for x in nditer(a, flags=['external_loop'], order='F'): r.append(x) + print r assert (array(r) == [[0, 3], [1, 4], [2, 5]]).all() def test_interface(self): From noreply at buildbot.pypy.org Tue May 14 13:16:39 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 13:16:39 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: merge numpypy-ellipse-indexing into branch Message-ID: <20130514111639.C7DE41C1406@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r64065:bda069a8a5ea Date: 2013-05-14 11:27 +0300 http://bitbucket.org/pypy/pypy/changeset/bda069a8a5ea/ Log: merge numpypy-ellipse-indexing into branch diff too long, truncating to 2000 out of 3525 lines 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 @@ -119,13 +119,13 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: - cflags = os.environ["CFLAGS"] - compiler.compiler.append(cflags) - compiler.compiler_so.append(cflags) - compiler.linker_so.append(cflags) + cflags = os.environ["CFLAGS"].split() + compiler.compiler.extend(cflags) + compiler.compiler_so.extend(cflags) + compiler.linker_so.extend(cflags) from sysconfig_cpython import ( 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 @@ -5,3 +5,5 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 +.. branch: numpy-pickle +Pickling of numpy arrays and dtypes (including record dtypes) diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -8,7 +8,9 @@ arch = 'linux' cmd = 'wget "%s"' tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" -if sys.platform.startswith('darwin'): + if os.uname()[-1].startswith('arm'): + arch += '-armhf-raspbian' +elif sys.platform.startswith('darwin'): arch = 'osx' cmd = 'curl -O "%s"' tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -2,6 +2,7 @@ import os, sys +import pypy from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.tool.ann_override import PyPyAnnotatorPolicy @@ -78,7 +79,41 @@ # should be used as sparsely as possible, just to register callbacks from rpython.rlib.entrypoint import entrypoint - from rpython.rtyper.lltypesystem import rffi + from rpython.rtyper.lltypesystem import rffi, lltype + + w_pathsetter = space.appexec([], """(): + def f(path): + import sys + sys.path[:] = path + return f + """) + + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') + def pypy_setup_home(ll_home, verbose): + from pypy.module.sys.initpath import pypy_find_stdlib + if ll_home: + home = rffi.charp2str(ll_home) + else: + home = pypydir + w_path = pypy_find_stdlib(space, home) + if space.is_none(w_path): + if verbose: + debug("Failed to find library based on pypy_find_stdlib") + return 1 + space.startup() + space.call_function(w_pathsetter, w_path) + # import site + try: + import_ = space.getattr(space.getbuiltinmodule('__builtin__'), + space.wrap('__import__')) + space.call_function(import_, space.wrap('site')) + return 0 + except OperationError, e: + if verbose: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') def pypy_execute_source(ll_source): @@ -101,7 +136,8 @@ return 1 return 0 - return entry_point, _pypy_execute_source # for tests + return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_setup_home': pypy_setup_home} def call_finish(space): space.finish() diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -803,7 +803,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -812,11 +811,13 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = {} + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -13,6 +13,7 @@ # imported yet, and when it has been, it is mod.__dict__.items() just # after startup(). w_initialdict = None + lazy = False def __init__(self, space, w_name): """ NOT_RPYTHON """ diff --git a/pypy/interpreter/special.py b/pypy/interpreter/special.py --- a/pypy/interpreter/special.py +++ b/pypy/interpreter/special.py @@ -5,13 +5,13 @@ def __init__(self, space): self.space = space - def descr__repr__(self): - return self.space.wrap('Ellipsis') + def descr__repr__(self, space): + return space.wrap('Ellipsis') class NotImplemented(W_Root): def __init__(self, space): self.space = space - def descr__repr__(self): - return self.space.wrap('NotImplemented') + def descr__repr__(self, space): + return space.wrap('NotImplemented') 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 @@ -461,7 +461,7 @@ p = os.path.abspath(p) monkeypatch.chdir(os.path.dirname(app_main)) child = self.spawn(['-i', - '-m', 'test2.mymodule', + '-m', 'test.mymodule', 'extra']) child.expect('mymodule running') child.expect('Name: __main__') @@ -472,9 +472,9 @@ child.expect(re.escape(repr("foobar"))) child.expect('>>> ') child.sendline('import sys') - child.sendline('"test2" in sys.modules') + child.sendline('"test" in sys.modules') child.expect('True') - child.sendline('"test2.mymodule" in sys.modules') + child.sendline('"test.mymodule" in sys.modules') child.expect('False') child.sendline('sys.path[0]') child.expect("''") @@ -566,7 +566,7 @@ child.expect('hello') monkeypatch.chdir(os.path.dirname(app_main)) - child = self.spawn(['-mtest2.mymodule']) + child = self.spawn(['-mtest.mymodule']) child.expect('mymodule running') def test_ps1_only_if_interactive(self): @@ -671,7 +671,7 @@ p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') p = os.path.abspath(p) monkeypatch.chdir(os.path.dirname(app_main)) - data = self.run('-m test2.mymodule extra') + data = self.run('-m test.mymodule extra') assert 'mymodule running' in data assert 'Name: __main__' in data # ignoring case for windows. abspath behaves different from autopath diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -135,18 +135,39 @@ def test_interpindirect2app(self): space = self.space + class BaseA(W_Root): def method(self, space, x): + "This is a method" + pass + + def method_with_default(self, space, x=5): + pass + + @gateway.unwrap_spec(x=int) + def method_with_unwrap_spec(self, space, x): pass class A(BaseA): def method(self, space, x): return space.wrap(x + 2) + def method_with_default(self, space, x): + return space.wrap(x + 2) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 2) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) + def method_with_default(self, space, x): + return space.wrap(x + 1) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 1) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -163,6 +184,23 @@ assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2 assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1 + doc = space.str_w(space.getattr(w_c, space.wrap('__doc__'))) + assert doc == "This is a method" + + meth_with_default = gateway.interpindirect2app( + BaseA.method_with_default, {'x': int}) + w_d = space.wrap(meth_with_default) + + assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2 + assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1 + assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2 + assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1 + + meth_with_unwrap_spec = gateway.interpindirect2app( + BaseA.method_with_unwrap_spec) + w_e = space.wrap(meth_with_unwrap_spec) + assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2 + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py --- a/pypy/interpreter/test/test_targetpypy.py +++ b/pypy/interpreter/test/test_targetpypy.py @@ -1,5 +1,6 @@ from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point from pypy.config.pypyoption import get_pypy_config +from rpython.rtyper.lltypesystem import rffi, lltype class TestTargetPyPy(object): def test_run(self): @@ -8,11 +9,20 @@ entry_point(['pypy-c' , '-S', '-c', 'print 3']) def test_exeucte_source(space): - _, execute_source = create_entry_point(space, None) - execute_source("import sys; sys.modules['xyz'] = 3") + _, d = create_entry_point(space, None) + execute_source = d['pypy_execute_source'] + lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3") + execute_source(lls) + lltype.free(lls, flavor='raw') x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'], space.wrap('modules')), space.wrap('xyz'))) assert x == 3 - execute_source("sys") + lls = rffi.str2charp("sys") + execute_source(lls) + lltype.free(lls, flavor='raw') # did not crash - the same globals + pypy_setup_home = d['pypy_setup_home'] + lls = rffi.str2charp(__file__) + pypy_setup_home(lls, 1) + lltype.free(lls, flavor='raw') diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,4 +1,3 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import unwrap_spec from rpython.rlib.objectmodel import we_are_translated @@ -56,7 +55,7 @@ bltn = BuiltinFunction(func) return space.wrap(bltn) - at unwrap_spec(ObjSpace, W_Root, str) + at unwrap_spec(meth=str) def lookup_special(space, w_obj, meth): """Lookup up a special method on an object.""" if space.is_oldstyle_instance(w_obj): diff --git a/pypy/module/array/__init__.py b/pypy/module/array/__init__.py --- a/pypy/module/array/__init__.py +++ b/pypy/module/array/__init__.py @@ -1,12 +1,5 @@ from pypy.interpreter.mixedmodule import MixedModule -from pypy.module.array.interp_array import types -from pypy.objspace.std.model import registerimplementation - -for mytype in types.values(): - registerimplementation(mytype.w_class) - - class Module(MixedModule): interpleveldefs = { 'array': 'interp_array.W_ArrayBase', 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 @@ -2,17 +2,14 @@ from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr +from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app +from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef +from pypy.interpreter.baseobjspace import W_Root from pypy.module._file.interp_file import W_File -from pypy.objspace.std.model import W_Object -from pypy.objspace.std.multimethod import FailedToImplement -from pypy.objspace.std.stdtypedef import SMM, StdTypeDef -from pypy.objspace.std.register_all import register_all from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.objectmodel import specialize, keepalive_until_here +from rpython.rlib.objectmodel import keepalive_until_here from rpython.rtyper.lltypesystem import lltype, rffi @@ -39,9 +36,9 @@ if len(__args__.arguments_w) > 0: w_initializer = __args__.arguments_w[0] if space.type(w_initializer) is space.w_str: - a.fromstring(space.str_w(w_initializer)) + a.descr_fromstring(space, space.str_w(w_initializer)) elif space.type(w_initializer) is space.w_list: - a.fromlist(w_initializer) + a.descr_fromlist(space, w_initializer) else: a.extend(w_initializer, True) break @@ -52,31 +49,6 @@ return a -array_append = SMM('append', 2) -array_extend = SMM('extend', 2) - -array_count = SMM('count', 2) -array_index = SMM('index', 2) -array_reverse = SMM('reverse', 1) -array_remove = SMM('remove', 2) -array_pop = SMM('pop', 2, defaults=(-1,)) -array_insert = SMM('insert', 3) - -array_tolist = SMM('tolist', 1) -array_fromlist = SMM('fromlist', 2) -array_tostring = SMM('tostring', 1) -array_fromstring = SMM('fromstring', 2) -array_tounicode = SMM('tounicode', 1) -array_fromunicode = SMM('fromunicode', 2) -array_tofile = SMM('tofile', 2) -array_fromfile = SMM('fromfile', 3) - -array_buffer_info = SMM('buffer_info', 1) -array_reduce = SMM('__reduce__', 1) -array_copy = SMM('__copy__', 1) -array_byteswap = SMM('byteswap', 1) - - def descr_itemsize(space, self): return space.wrap(self.itemsize) @@ -84,28 +56,476 @@ def descr_typecode(space, self): return space.wrap(self.typecode) +arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') +EQ, NE, LT, LE, GT, GE = range(6) -class W_ArrayBase(W_Object): - @staticmethod - def register(typeorder): - typeorder[W_ArrayBase] = [] +def compare_arrays(space, arr1, arr2, comp_op, comp_func): + if (not isinstance(arr1, W_ArrayBase) or + not isinstance(arr2, W_ArrayBase)): + return space.w_NotImplemented + if comp_op == EQ and arr1.len != arr2.len: + return space.w_False + if comp_op == NE and arr1.len != arr2.len: + return space.w_True + lgt = min(arr1.len, arr2.len) + for i in range(lgt): + arr_eq_driver.jit_merge_point(comp_func=comp_func) + w_elem1 = arr1.w_getitem(space, i) + w_elem2 = arr2.w_getitem(space, i) + res = space.is_true(comp_func(w_elem1, w_elem2)) + if comp_op == EQ: + if not res: + return space.w_False + elif comp_op == NE: + if res: + return space.w_True + elif comp_op == LT or comp_op == GT: + if res: + return space.w_True + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_False + else: + if not res: + return space.w_False + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_True + # we have some leftovers + if comp_op == EQ: + return space.w_True + elif comp_op == NE: + return space.w_False + if arr1.len == arr2.len: + if comp_op == LT or comp_op == GT: + return space.w_False + return space.w_True + if comp_op == LT or comp_op == LE: + if arr1.len < arr2.len: + return space.w_False + return space.w_True + if arr1.len > arr2.len: + return space.w_False + return space.w_True -W_ArrayBase.typedef = StdTypeDef( +UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, + hints={'nolength': True})) + +class W_ArrayBase(W_Root): + _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer + + def __init__(self, space): + self.space = space + self.len = 0 + self.allocated = 0 + + def descr_append(self, space, w_x): + """ append(x) + + Append new value x to the end of the array. + """ + raise NotImplementedError + + def descr_extend(self, space, w_x): + """ extend(array or iterable) + + Append items to the end of the array. + """ + self.extend(w_x) + + def descr_count(self, space, w_val): + """ count(x) + + Return number of occurrences of x in the array. + """ + raise NotImplementedError + + def descr_index(self, space, w_x): + """ index(x) + + Return index of first occurrence of x in the array. + """ + raise NotImplementedError + + def descr_reverse(self, space): + """ reverse() + + Reverse the order of the items in the array. + """ + raise NotImplementedError + + def descr_remove(self, space, w_val): + """ remove(x) + + Remove the first occurrence of x in the array. + """ + raise NotImplementedError + + @unwrap_spec(i=int) + def descr_pop(self, space, i=-1): + """ pop([i]) + + Return the i-th element and delete it from the array. i defaults to -1. + """ + raise NotImplementedError + + @unwrap_spec(idx=int) + def descr_insert(self, space, idx, w_val): + """ insert(i,x) + + Insert a new item x into the array before position i. + """ + raise NotImplementedError + + def descr_tolist(self, space): + """ tolist() -> list + + Convert array to an ordinary list with the same items. + """ + w_l = space.newlist([]) + for i in range(self.len): + w_l.append(self.w_getitem(space, i)) + return w_l + + def descr_fromlist(self, space, w_lst): + """ fromlist(list) + + Append items to array from list. + """ + if not space.isinstance_w(w_lst, space.w_list): + raise OperationError(space.w_TypeError, + space.wrap("arg must be list")) + s = self.len + try: + self.fromsequence(w_lst) + except OperationError: + self.setlen(s) + raise + + def descr_tostring(self, space): + """ tostring() -> string + + Convert the array to an array of machine values and return the string + representation. + """ + cbuf = self._charbuf_start() + s = rffi.charpsize2str(cbuf, self.len * self.itemsize) + self._charbuf_stop() + return self.space.wrap(s) + + @unwrap_spec(s=str) + def descr_fromstring(self, space, s): + """ fromstring(string) + + Appends items from the string, interpreting it as an array of machine + values,as if it had been read from a file using the fromfile() method). + """ + if len(s) % self.itemsize != 0: + msg = 'string length not a multiple of item size' + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) + oldlen = self.len + new = len(s) / self.itemsize + self.setlen(oldlen + new) + cbuf = self._charbuf_start() + for i in range(len(s)): + cbuf[oldlen * self.itemsize + i] = s[i] + self._charbuf_stop() + + @unwrap_spec(w_f=W_File, n=int) + def descr_fromfile(self, space, w_f, n): + """ fromfile(f, n) + + Read n objects from the file object f and append them to the end of the + array. Also called as read. + """ + try: + size = ovfcheck(self.itemsize * n) + except OverflowError: + raise MemoryError + w_item = space.call_method(w_f, 'read', space.wrap(size)) + item = space.str_w(w_item) + if len(item) < size: + n = len(item) % self.itemsize + elems = max(0, len(item) - (len(item) % self.itemsize)) + if n != 0: + item = item[0:elems] + self.descr_fromstring(space, item) + msg = "not enough items in file" + raise OperationError(space.w_EOFError, space.wrap(msg)) + self.descr_fromstring(space, item) + + @unwrap_spec(w_f=W_File) + def descr_tofile(self, space, w_f): + """ tofile(f) + + Write all items (as machine values) to the file object f. Also called as + write. + """ + w_s = self.descr_tostring(space) + space.call_method(w_f, 'write', w_s) + + def descr_fromunicode(self, space, w_ustr): + """ fromunicode(ustr) + + Extends this array with data from the unicode string ustr. + The array must be a type 'u' array; otherwise a ValueError + is raised. Use array.fromstring(ustr.decode(...)) to + append Unicode data to an array of some other type. + """ + # XXX the following probable bug is not emulated: + # CPython accepts a non-unicode string or a buffer, and then + # behaves just like fromstring(), except that it strangely truncate + # string arguments at multiples of the unicode byte size. + # Let's only accept unicode arguments for now. + if self.typecode == 'u': + self.fromsequence(w_ustr) + else: + msg = "fromunicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_tounicode(self, space): + """ tounicode() -> unicode + + Convert the array to a unicode string. The array must be + a type 'u' array; otherwise a ValueError is raised. Use + array.tostring().decode() to obtain a unicode string from + an array of some other type. + """ + if self.typecode == 'u': + buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned()) + return space.wrap(rffi.wcharpsize2unicode(buf, self.len)) + else: + msg = "tounicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_buffer_info(self, space): + """ buffer_info() -> (address, length) + + Return a tuple (address, length) giving the current memory address and + the length in items of the buffer used to hold array's contents + The length should be multiplied by the itemsize attribute to calculate + the buffer length in bytes. + """ + w_ptr = space.wrap(self._buffer_as_unsigned()) + w_len = space.wrap(self.len) + return space.newtuple([w_ptr, w_len]) + + def descr_reduce(self, space): + """ Return state information for pickling. + """ + if self.len > 0: + w_s = self.descr_tostring(space) + args = [space.wrap(self.typecode), w_s] + else: + args = [space.wrap(self.typecode)] + try: + dct = space.getattr(self, space.wrap('__dict__')) + except OperationError: + dct = space.w_None + return space.newtuple([space.type(self), space.newtuple(args), dct]) + + def descr_copy(self, space): + """ copy(array) + + Return a copy of the array. + """ + w_a = self.constructor(self.space) + w_a.setlen(self.len, overallocate=False) + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()), + rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()), + self.len * self.itemsize + ) + return w_a + + def descr_byteswap(self, space): + """ byteswap() + + Byteswap all items of the array. If the items in the array are not 1, 2, + 4, or 8 bytes in size, RuntimeError is raised. + """ + if self.itemsize not in [1, 2, 4, 8]: + msg = "byteswap not supported for this array" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + if self.len == 0: + return + bytes = self._charbuf_start() + tmp = [bytes[0]] * self.itemsize + for start in range(0, self.len * self.itemsize, self.itemsize): + stop = start + self.itemsize - 1 + for i in range(self.itemsize): + tmp[i] = bytes[start + i] + for i in range(self.itemsize): + bytes[stop - i] = tmp[i] + self._charbuf_stop() + + def descr_len(self, space): + return space.wrap(self.len) + + def descr_eq(self, space, w_arr2): + "x.__eq__(y) <==> x==y" + return compare_arrays(space, self, w_arr2, EQ, space.eq) + + def descr_ne(self, space, w_arr2): + "x.__ne__(y) <==> x!=y" + return compare_arrays(space, self, w_arr2, NE, space.ne) + + def descr_lt(self, space, w_arr2): + "x.__lt__(y) <==> x x<=y" + return compare_arrays(space, self, w_arr2, LE, space.le) + + def descr_gt(self, space, w_arr2): + "x.__gt__(y) <==> x>y" + return compare_arrays(space, self, w_arr2, GT, space.gt) + + def descr_ge(self, space, w_arr2): + "x.__ge__(y) <==> x>=y" + return compare_arrays(space, self, w_arr2, GE, space.ge) + + # Basic get/set/append/extend methods + + def descr_getitem(self, space, w_idx): + "x.__getitem__(y) <==> x[y]" + if not space.isinstance_w(w_idx, space.w_slice): + idx, stop, step = space.decode_index(w_idx, self.len) + assert step == 0 + return self.w_getitem(space, idx) + else: + return self.getitem_slice(space, w_idx) + + def descr_getslice(self, space, w_i, w_j): + return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) + + + def descr_setitem(self, space, w_idx, w_item): + "x.__setitem__(i, y) <==> x[i]=y" + if space.isinstance_w(w_idx, space.w_slice): + self.setitem_slice(space, w_idx, w_item) + else: + self.setitem(space, w_idx, w_item) + + def descr_setslice(self, space, w_start, w_stop, w_item): + self.setitem_slice(space, + space.newslice(w_start, w_stop, space.w_None), + w_item) + + def descr_delitem(self, space, w_idx): + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + if step != 1: + # I don't care about efficiency of that so far + w_lst = self.descr_tolist(space) + space.delitem(w_lst, w_idx) + self.setlen(0) + self.fromsequence(w_lst) + return + return self.delitem(space, start, stop) + + def descr_delslice(self, space, w_start, w_stop): + self.descr_delitem(space, space.newslice(w_start, w_stop, space.w_None)) + + def descr_add(self, space, w_other): + raise NotImplementedError + + def descr_inplace_add(self, space, w_other): + raise NotImplementedError + + def descr_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_inplace_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_radd(self, space, w_other): + return self.descr_add(space, w_other) + + def descr_rmul(self, space, w_repeat): + return self.descr_mul(space, w_repeat) + + # Misc methods + + def descr_buffer(self, space): + return space.wrap(ArrayBuffer(self)) + + def descr_repr(self, space): + if self.len == 0: + return space.wrap("array('%s')" % self.typecode) + elif self.typecode == "c": + r = space.repr(self.descr_tostring(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + elif self.typecode == "u": + r = space.repr(self.descr_tounicode(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + else: + r = space.repr(self.descr_tolist(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + +W_ArrayBase.typedef = TypeDef( 'array', __new__ = interp2app(w_array), __module__ = 'array', + + __len__ = interp2app(W_ArrayBase.descr_len), + __eq__ = interp2app(W_ArrayBase.descr_eq), + __ne__ = interp2app(W_ArrayBase.descr_ne), + __lt__ = interp2app(W_ArrayBase.descr_lt), + __le__ = interp2app(W_ArrayBase.descr_le), + __gt__ = interp2app(W_ArrayBase.descr_gt), + __ge__ = interp2app(W_ArrayBase.descr_ge), + + __getitem__ = interp2app(W_ArrayBase.descr_getitem), + __getslice__ = interp2app(W_ArrayBase.descr_getslice), + __setitem__ = interp2app(W_ArrayBase.descr_setitem), + __setslice__ = interp2app(W_ArrayBase.descr_setslice), + __delitem__ = interp2app(W_ArrayBase.descr_delitem), + __delslice__ = interp2app(W_ArrayBase.descr_delslice), + + __add__ = interpindirect2app(W_ArrayBase.descr_add), + __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add), + __mul__ = interpindirect2app(W_ArrayBase.descr_mul), + __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul), + __radd__ = interp2app(W_ArrayBase.descr_radd), + __rmul__ = interp2app(W_ArrayBase.descr_rmul), + + __buffer__ = interp2app(W_ArrayBase.descr_buffer), + __repr__ = interp2app(W_ArrayBase.descr_repr), + itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), + append = interpindirect2app(W_ArrayBase.descr_append), + extend = interp2app(W_ArrayBase.descr_extend), + count = interpindirect2app(W_ArrayBase.descr_count), + index = interpindirect2app(W_ArrayBase.descr_index), + reverse = interpindirect2app(W_ArrayBase.descr_reverse), + remove = interpindirect2app(W_ArrayBase.descr_remove), + pop = interpindirect2app(W_ArrayBase.descr_pop), + insert = interpindirect2app(W_ArrayBase.descr_insert), + + tolist = interp2app(W_ArrayBase.descr_tolist), + fromlist = interp2app(W_ArrayBase.descr_fromlist), + tostring = interp2app(W_ArrayBase.descr_tostring), + fromstring = interp2app(W_ArrayBase.descr_fromstring), + tofile = interp2app(W_ArrayBase.descr_tofile), + fromfile = interp2app(W_ArrayBase.descr_fromfile), + fromunicode = interp2app(W_ArrayBase.descr_fromunicode), + tounicode = interp2app(W_ArrayBase.descr_tounicode), + + buffer_info = interp2app(W_ArrayBase.descr_buffer_info), + __copy__ = interp2app(W_ArrayBase.descr_copy), + __reduce__ = interp2app(W_ArrayBase.descr_reduce), + byteswap = interp2app(W_ArrayBase.descr_byteswap), ) -W_ArrayBase.typedef.registermethods(globals()) class TypeCode(object): def __init__(self, itemtype, unwrap, canoverflow=False, signed=False): self.itemtype = itemtype self.bytes = rffi.sizeof(itemtype) - #self.arraytype = lltype.GcArray(itemtype) self.arraytype = lltype.Array(itemtype, hints={'nolength': True}) self.unwrap = unwrap self.signed = signed @@ -175,14 +595,10 @@ itemsize = mytype.bytes typecode = mytype.typecode - @staticmethod - def register(typeorder): - typeorder[W_Array] = [(W_ArrayBase, None)] + _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer') def __init__(self, space): - self.space = space - self.len = 0 - self.allocated = 0 + W_ArrayBase.__init__(self, space) self.buffer = lltype.nullptr(mytype.arraytype) def item_w(self, w_item): @@ -289,26 +705,6 @@ raise self.setlen(oldlen + i) - def fromstring(self, s): - if len(s) % self.itemsize != 0: - msg = 'string length not a multiple of item size' - raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) - oldlen = self.len - new = len(s) / mytype.bytes - self.setlen(oldlen + new) - cbuf = self._charbuf_start() - for i in range(len(s)): - cbuf[oldlen * mytype.bytes + i] = s[i] - self._charbuf_stop() - - def fromlist(self, w_lst): - s = self.len - try: - self.fromsequence(w_lst) - except OperationError: - self.setlen(s) - raise - def extend(self, w_iterable, accept_different_array=False): space = self.space if isinstance(w_iterable, W_Array): @@ -332,6 +728,9 @@ def _charbuf_start(self): return rffi.cast(rffi.CCHARP, self.buffer) + def _buffer_as_unsigned(self): + return rffi.cast(lltype.Unsigned, self.buffer) + def _charbuf_stop(self): keepalive_until_here(self) @@ -343,202 +742,180 @@ item = float(item) return space.wrap(item) - # Basic get/set/append/extend methods + # interface - def len__Array(space, self): - return space.wrap(self.len) + def descr_append(self, space, w_x): + x = self.item_w(w_x) + self.setlen(self.len + 1) + self.buffer[self.len - 1] = x - def getitem__Array_ANY(space, self, w_idx): - idx, stop, step = space.decode_index(w_idx, self.len) - assert step == 0 - return self.w_getitem(space, idx) + # List interface + def descr_count(self, space, w_val): + cnt = 0 + for i in range(self.len): + # XXX jitdriver + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + cnt += 1 + return space.wrap(cnt) - def getitem__Array_Slice(space, self, w_slice): - start, stop, step, size = space.decode_index4(w_slice, self.len) - w_a = mytype.w_class(self.space) - w_a.setlen(size, overallocate=False) - assert step != 0 - j = 0 - for i in range(start, stop, step): - w_a.buffer[j] = self.buffer[i] - j += 1 - return w_a + def descr_index(self, space, w_val): + for i in range(self.len): + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + return space.wrap(i) + msg = 'array.index(x): x not in list' + raise OperationError(space.w_ValueError, space.wrap(msg)) - def getslice__Array_ANY_ANY(space, self, w_i, w_j): - return space.getitem(self, space.newslice(w_i, w_j, space.w_None)) + def descr_reverse(self, space): + b = self.buffer + for i in range(self.len / 2): + b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] - def setitem__Array_ANY_ANY(space, self, w_idx, w_item): - idx, stop, step = space.decode_index(w_idx, self.len) - if step != 0: - msg = 'can only assign array to array slice' - raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) - item = self.item_w(w_item) - self.buffer[idx] = item + def descr_pop(self, space, i): + if i < 0: + i += self.len + if i < 0 or i >= self.len: + msg = 'pop index out of range' + raise OperationError(space.w_IndexError, space.wrap(msg)) + w_val = self.w_getitem(space, i) + while i < self.len - 1: + self.buffer[i] = self.buffer[i + 1] + i += 1 + self.setlen(self.len - 1) + return w_val - def setitem__Array_Slice_Array(space, self, w_idx, w_item): - start, stop, step, size = self.space.decode_index4(w_idx, self.len) - assert step != 0 - if w_item.len != size or self is w_item: - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - w_item = space.call_method(w_item, 'tolist') - space.setitem(w_lst, w_idx, w_item) - self.setlen(0) - self.fromsequence(w_lst) - else: + def descr_remove(self, space, w_val): + w_idx = self.descr_index(space, w_val) + self.descr_pop(space, space.int_w(w_idx)) + + def descr_insert(self, space, idx, w_val): + if idx < 0: + idx += self.len + if idx < 0: + idx = 0 + if idx > self.len: + idx = self.len + + val = self.item_w(w_val) + self.setlen(self.len + 1) + i = self.len - 1 + while i > idx: + self.buffer[i] = self.buffer[i - 1] + i -= 1 + self.buffer[i] = val + + def getitem_slice(self, space, w_idx): + start, stop, step, size = space.decode_index4(w_idx, self.len) + w_a = mytype.w_class(self.space) + w_a.setlen(size, overallocate=False) + assert step != 0 j = 0 for i in range(start, stop, step): - self.buffer[i] = w_item.buffer[j] + w_a.buffer[j] = self.buffer[i] j += 1 + return w_a - def setslice__Array_ANY_ANY_ANY(space, self, w_i, w_j, w_x): - space.setitem(self, space.newslice(w_i, w_j, space.w_None), w_x) + def setitem(self, space, w_idx, w_item): + idx, stop, step = space.decode_index(w_idx, self.len) + if step != 0: + msg = 'can only assign array to array slice' + raise OperationError(self.space.w_TypeError, + self.space.wrap(msg)) + item = self.item_w(w_item) + self.buffer[idx] = item - def array_append__Array_ANY(space, self, w_x): - x = self.item_w(w_x) - self.setlen(self.len + 1) - self.buffer[self.len - 1] = x + def setitem_slice(self, space, w_idx, w_item): + if not isinstance(w_item, W_Array): + raise OperationError(space.w_TypeError, space.wrap( + "can only assign to a slice array")) + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + assert step != 0 + if w_item.len != size or self is w_item: + # XXX this is a giant slow hack + w_lst = self.descr_tolist(space) + w_item = space.call_method(w_item, 'tolist') + space.setitem(w_lst, w_idx, w_item) + self.setlen(0) + self.fromsequence(w_lst) + else: + j = 0 + for i in range(start, stop, step): + self.buffer[i] = w_item.buffer[j] + j += 1 - def array_extend__Array_ANY(space, self, w_iterable): - self.extend(w_iterable) + # We can't look into this function until ptradd works with things (in the + # JIT) other than rffi.CCHARP + @jit.dont_look_inside + def delitem(self, space, i, j): + if i < 0: + i += self.len + if i < 0: + i = 0 + if j < 0: + j += self.len + if j < 0: + j = 0 + if j > self.len: + j = self.len + if i >= j: + return None + oldbuffer = self.buffer + self.buffer = lltype.malloc(mytype.arraytype, + max(self.len - (j - i), 0), flavor='raw', + add_memory_pressure=True) + if i: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, self.buffer), + rffi.cast(rffi.VOIDP, oldbuffer), + i * mytype.bytes + ) + if j < self.len: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), + rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), + (self.len - j) * mytype.bytes + ) + self.len -= j - i + self.allocated = self.len + if oldbuffer: + lltype.free(oldbuffer, flavor='raw') - # List interface - def array_count__Array_ANY(space, self, w_val): - cnt = 0 - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - cnt += 1 - return space.wrap(cnt) + # Add and mul methods - def array_index__Array_ANY(space, self, w_val): - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - return space.wrap(i) - msg = 'array.index(x): x not in list' - raise OperationError(space.w_ValueError, space.wrap(msg)) + def descr_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + a = mytype.w_class(space) + a.setlen(self.len + w_other.len, overallocate=False) + for i in range(self.len): + a.buffer[i] = self.buffer[i] + for i in range(w_other.len): + a.buffer[i + self.len] = w_other.buffer[i] + return a - def array_reverse__Array(space, self): - b = self.buffer - for i in range(self.len / 2): - b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] + def descr_inplace_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + oldlen = self.len + otherlen = w_other.len + self.setlen(oldlen + otherlen) + for i in range(otherlen): + self.buffer[oldlen + i] = w_other.buffer[i] + return self - def array_pop__Array_ANY(space, self, w_idx): - i = space.int_w(w_idx) - if i < 0: - i += self.len - if i < 0 or i >= self.len: - msg = 'pop index out of range' - raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = self.w_getitem(space, i) - while i < self.len - 1: - self.buffer[i] = self.buffer[i + 1] - i += 1 - self.setlen(self.len - 1) - return w_val + def descr_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, False) - def array_remove__Array_ANY(space, self, w_val): - w_idx = array_index__Array_ANY(space, self, w_val) - array_pop__Array_ANY(space, self, w_idx) - - def array_insert__Array_ANY_ANY(space, self, w_idx, w_val): - idx = space.int_w(w_idx) - if idx < 0: - idx += self.len - if idx < 0: - idx = 0 - if idx > self.len: - idx = self.len - - val = self.item_w(w_val) - self.setlen(self.len + 1) - i = self.len - 1 - while i > idx: - self.buffer[i] = self.buffer[i - 1] - i -= 1 - self.buffer[i] = val - - def delitem__Array_ANY(space, self, w_idx): - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - space.delitem(w_lst, w_idx) - self.setlen(0) - self.fromsequence(w_lst) - - # We can't look into this function until ptradd works with things (in the - # JIT) other than rffi.CCHARP - @jit.dont_look_inside - def delslice__Array_ANY_ANY(space, self, w_i, w_j): - i = space.int_w(w_i) - if i < 0: - i += self.len - if i < 0: - i = 0 - j = space.int_w(w_j) - if j < 0: - j += self.len - if j < 0: - j = 0 - if j > self.len: - j = self.len - if i >= j: - return None - oldbuffer = self.buffer - self.buffer = lltype.malloc(mytype.arraytype, - max(self.len - (j - i), 0), flavor='raw', - add_memory_pressure=True) - if i: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, self.buffer), - rffi.cast(rffi.VOIDP, oldbuffer), - i * mytype.bytes - ) - if j < self.len: - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), - rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), - (self.len - j) * mytype.bytes - ) - self.len -= j - i - self.allocated = self.len - if oldbuffer: - lltype.free(oldbuffer, flavor='raw') - - # Add and mul methods - - def add__Array_Array(space, self, other): - a = mytype.w_class(space) - a.setlen(self.len + other.len, overallocate=False) - for i in range(self.len): - a.buffer[i] = self.buffer[i] - for i in range(other.len): - a.buffer[i + self.len] = other.buffer[i] - return a - - def inplace_add__Array_Array(space, self, other): - oldlen = self.len - otherlen = other.len - self.setlen(oldlen + otherlen) - for i in range(otherlen): - self.buffer[oldlen + i] = other.buffer[i] - return self - - def mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, False) - - def mul__ANY_Array(space, w_repeat, self): - return _mul_helper(space, self, w_repeat, False) - - def inplace_mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, True) + def descr_inplace_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, True) def _mul_helper(space, self, w_repeat, is_inplace): try: repeat = space.getindex_w(w_repeat, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - raise FailedToImplement + return space.w_NotImplemented raise repeat = max(repeat, 0) try: @@ -577,186 +954,11 @@ a.buffer[r * oldlen + i] = self.buffer[i] return a - # Convertions - - def array_tolist__Array(space, self): - w_l = space.newlist([]) - for i in range(self.len): - w_l.append(self.w_getitem(space, i)) - return w_l - - def array_fromlist__Array_List(space, self, w_lst): - self.fromlist(w_lst) - - def array_fromstring__Array_ANY(space, self, w_s): - self.fromstring(space.str_w(w_s)) - - def array_tostring__Array(space, self): - cbuf = self._charbuf_start() - s = rffi.charpsize2str(cbuf, self.len * mytype.bytes) - self._charbuf_stop() - return self.space.wrap(s) - - def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - n = space.int_w(w_n) - - try: - size = ovfcheck(self.itemsize * n) - except OverflowError: - raise MemoryError - w_item = space.call_method(w_f, 'read', space.wrap(size)) - item = space.str_w(w_item) - if len(item) < size: - n = len(item) % self.itemsize - elems = max(0, len(item) - (len(item) % self.itemsize)) - if n != 0: - item = item[0:elems] - w_item = space.wrap(item) - array_fromstring__Array_ANY(space, self, w_item) - msg = "not enough items in file" - raise OperationError(space.w_EOFError, space.wrap(msg)) - array_fromstring__Array_ANY(space, self, w_item) - - def array_tofile__Array_ANY(space, self, w_f): - if not isinstance(w_f, W_File): - msg = "arg1 must be open file" - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_s = array_tostring__Array(space, self) - space.call_method(w_f, 'write', w_s) - - if mytype.typecode == 'u': - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - # XXX the following probable bug is not emulated: - # CPython accepts a non-unicode string or a buffer, and then - # behaves just like fromstring(), except that it strangely truncate - # string arguments at multiples of the unicode byte size. - # Let's only accept unicode arguments for now. - self.fromsequence(w_ustr) - - def array_tounicode__Array(space, self): - return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) - else: - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - msg = "fromunicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - def array_tounicode__Array(space, self): - msg = "tounicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - # Compare methods - @specialize.arg(3) - def _cmp_impl(space, self, other, space_fn): - # XXX this is a giant slow hack - w_lst1 = array_tolist__Array(space, self) - w_lst2 = space.call_method(other, 'tolist') - return space_fn(w_lst1, w_lst2) - - def eq__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.eq) - - def ne__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ne) - - def lt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.lt) - - def le__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.le) - - def gt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.gt) - - def ge__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ge) - - # Misc methods - - def buffer__Array(space, self): - return space.wrap(ArrayBuffer(self)) - - def array_buffer_info__Array(space, self): - w_ptr = space.wrap(rffi.cast(lltype.Unsigned, self.buffer)) - w_len = space.wrap(self.len) - return space.newtuple([w_ptr, w_len]) - - def array_reduce__Array(space, self): - if self.len > 0: - w_s = array_tostring__Array(space, self) - args = [space.wrap(mytype.typecode), w_s] - else: - args = [space.wrap(mytype.typecode)] - try: - dct = space.getattr(self, space.wrap('__dict__')) - except OperationError: - dct = space.w_None - return space.newtuple([space.type(self), space.newtuple(args), dct]) - - def array_copy__Array(space, self): - w_a = mytype.w_class(self.space) - w_a.setlen(self.len, overallocate=False) - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, w_a.buffer), - rffi.cast(rffi.VOIDP, self.buffer), - self.len * mytype.bytes - ) - return w_a - - def array_byteswap__Array(space, self): - if mytype.bytes not in [1, 2, 4, 8]: - msg = "byteswap not supported for this array" - raise OperationError(space.w_RuntimeError, space.wrap(msg)) - if self.len == 0: - return - bytes = self._charbuf_start() - tmp = [bytes[0]] * mytype.bytes - for start in range(0, self.len * mytype.bytes, mytype.bytes): - stop = start + mytype.bytes - 1 - for i in range(mytype.bytes): - tmp[i] = bytes[start + i] - for i in range(mytype.bytes): - bytes[stop - i] = tmp[i] - self._charbuf_stop() - - def repr__Array(space, self): - if self.len == 0: - return space.wrap("array('%s')" % self.typecode) - elif self.typecode == "c": - r = space.repr(array_tostring__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - elif self.typecode == "u": - r = space.repr(array_tounicode__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - else: - r = space.repr(array_tolist__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - mytype.w_class = W_Array - - # Annotator seems to mess up if the names are not unique + W_Array.constructor = W_Array name = 'ArrayType' + mytype.typecode W_Array.__name__ = 'W_' + name - import re - for n, f in locals().items(): - new, n = re.subn('_Array_', '_%s_' % name, n) - if n > 0: - f.__name__ = new - - from pypy.objspace.std.sliceobject import W_SliceObject - from pypy.objspace.std.listobject import W_ListObject - from pypy.objspace.std.unicodeobject import W_UnicodeObject - register_all(locals(), globals()) - for mytype in types.values(): make_array(mytype) - -register_all(locals(), globals()) +del mytype diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -19,7 +19,7 @@ class BaseArrayTests: - + def test_ctor(self): assert len(self.array('c')) == 0 assert len(self.array('i')) == 0 @@ -390,7 +390,6 @@ assert self.array('c', ('h', 'i')).tostring() == 'hi' a = self.array('i', [0, 0, 0]) assert a.tostring() == '\x00' * 3 * a.itemsize - s = self.array('i', [1, 2, 3]).tostring() assert '\x00' in s assert '\x01' in s @@ -502,7 +501,7 @@ return 0 class incomparable(object): pass - + for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'), ('abc', 'acb', 'c'), (unicode('abc'), unicode('acb'), 'u')): @@ -653,14 +652,14 @@ raises(TypeError, "a * 'hi'") raises(TypeError, "'hi' * a") raises(TypeError, "a *= 'hi'") - + class mulable(object): def __mul__(self, other): return "mul" def __rmul__(self, other): return "rmul" - + assert mulable() * self.array('i') == 'mul' assert self.array('i') * mulable() == 'rmul' @@ -769,7 +768,7 @@ def __getitem__(self, i): return array.__getitem__(self, self._index(i)) - + def __setitem__(self, i, val): return array.__setitem__(self, self._index(i), val) @@ -783,7 +782,7 @@ assert img[3, 25] == 3 * 9 - + def test_override_from(self): class mya(self.array): def fromlist(self, lst): @@ -854,7 +853,7 @@ def test_subclass_del(self): import array, gc, weakref l = [] - + class A(array.array): pass diff --git a/pypy/module/array/test/test_ztranslation.py b/pypy/module/array/test/test_ztranslation.py new file mode 100644 --- /dev/null +++ b/pypy/module/array/test/test_ztranslation.py @@ -0,0 +1,6 @@ + +from pypy.objspace.fake.checkmodule import checkmodule + +def test_checkmodule(): + checkmodule('array') + diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -544,37 +544,38 @@ def make_wrapper(space, callable): "NOT_RPYTHON" names = callable.api_func.argnames - argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes, - [name.startswith("w_") for name in names]))) + argtypes = callable.api_func.argtypes + is_wrapped_list = [name.startswith("w_") for name in names] fatal_value = callable.api_func.restype._defl() - @specialize.ll() - def wrapper(*args): + lines = [] + for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)): + if is_PyObject(argtype) and is_wrapped: + new_lines = [ + 'if %(arg)s:', + ' %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))', + 'else:', + ' %(arg)s = None', + ] + for j in range(len(new_lines)): + new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i} + lines += new_lines + middle = '\n '.join(lines) + arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))]) + + source = py.code.Source(""" + def wrapper(%(args)s): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference - # we hope that malloc removal removes the newtuple() that is - # inserted exactly here by the varargs specializer - rffi.stackcounter.stacks_counter += 1 - llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py retval = fatal_value boxed_args = () try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, - assert len(args) == len(callable.api_func.argtypes) - for i, (typ, is_wrapped) in argtypes_enum_ui: - arg = args[i] - if is_PyObject(typ) and is_wrapped: - if arg: - arg_conv = from_ref(space, rffi.cast(PyObject, arg)) - else: - arg_conv = None - else: - arg_conv = arg - boxed_args += (arg_conv, ) state = space.fromcache(State) + %(middle)s try: - result = callable(space, *boxed_args) + result = callable(space, %(args)s) if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, " DONE" except OperationError, e: @@ -596,8 +597,8 @@ if failed: error_value = callable.api_func.error_value if error_value is CANNOT_FAIL: - raise SystemError("The function '%s' was not supposed to fail" - % (callable.__name__,)) + raise SystemError("The function '%%s' was not supposed to fail" + %% (callable.__name__,)) retval = error_value elif is_PyObject(callable.api_func.restype): @@ -624,8 +625,13 @@ else: print str(e) pypy_debug_catch_fatal_exception() - rffi.stackcounter.stacks_counter -= 1 return retval + """ % {"middle": middle, "args": arg_spec}) + d = {} + d.update(locals()) + d.update(globals()) + exec source.compile() in d + wrapper = d['wrapper'] callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -1023,7 +1029,7 @@ export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): - deco = entrypoint("cpyext", func.argtypes, name, relax=True) + deco = entrypoint("cpyext", func.argtypes, name) deco(func.get_wrapper(space)) setup_init_functions(eci, translating=True) diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -12,6 +12,7 @@ 'zeros': 'interp_numarray.zeros', 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', + '_reconstruct' : 'interp_numarray._reconstruct', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -13,6 +13,7 @@ raw_storage_setitem, RAW_STORAGE from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized +from pypy.interpreter.special import Ellipsis class BaseConcreteArray(base.BaseArrayImplementation): @@ -55,6 +56,9 @@ def get_size(self): return self.size // self.dtype.itemtype.get_element_size() + def get_storage_size(self): + return self.size + def reshape(self, space, orig_array, new_shape): # Since we got to here, prod(new_shape) == self.size new_strides = None @@ -154,6 +158,7 @@ """ if (space.isinstance_w(w_idx, space.w_str) or space.isinstance_w(w_idx, space.w_slice) or + isinstance(w_idx, Ellipsis) or space.is_w(w_idx, space.w_None)): raise IndexError if isinstance(w_idx, W_NDimArray) and not isinstance(w_idx.implementation, scalar.Scalar): @@ -200,7 +205,7 @@ if (space.isinstance_w(w_idx, space.w_int) or space.isinstance_w(w_idx, space.w_slice)): return Chunks([Chunk(*space.decode_index4(w_idx, self.get_shape()[0]))]) - elif space.is_w(w_idx, space.w_None): + elif space.is_w(w_idx, space.w_None) or isinstance(w_idx, Ellipsis): return Chunks([NewAxisChunk()]) result = [] i = 0 @@ -328,13 +333,14 @@ class ConcreteArray(ConcreteArrayNotOwning): - def __init__(self, shape, dtype, order, strides, backstrides): - # we allocate the actual storage later because we need to compute - # self.size first + def __init__(self, shape, dtype, order, strides, backstrides, storage=lltype.nullptr(RAW_STORAGE)): null_storage = lltype.nullptr(RAW_STORAGE) ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides, null_storage) - self.storage = dtype.itemtype.malloc(self.size) + if storage == lltype.nullptr(RAW_STORAGE): + self.storage = dtype.itemtype.malloc(self.size) + else: + self.storage = storage def __del__(self): free_raw_storage(self.storage, track_allocation=False) diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -3,6 +3,7 @@ from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support from pypy.interpreter.error import OperationError +from pypy.interpreter.special import Ellipsis class ScalarIterator(base.BaseArrayIterator): def __init__(self, v): @@ -73,7 +74,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +103,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( @@ -119,7 +120,10 @@ space.wrap("scalars cannot be indexed")) def descr_setitem(self, space, _, w_idx, w_val): - raise OperationError(space.w_IndexError, + if isinstance(w_idx, Ellipsis): + self.value = self.dtype.coerce(space, w_val) + else: + raise OperationError(space.w_IndexError, space.wrap("scalars cannot be indexed")) def setitem_index(self, space, idx, w_val): diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -35,12 +35,17 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(shape, storage, dtype, order='C'): + def from_shape_and_storage(shape, storage, dtype, order='C', owning=False): from pypy.module.micronumpy.arrayimpl import concrete assert shape strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, - backstrides, storage) + if owning: + # Will free storage when GCd + impl = concrete.ConcreteArray(shape, dtype, order, strides, + backstrides, storage=storage) + else: + impl = concrete.ConcreteArrayNotOwning(shape, dtype, order, strides, + backstrides, storage) return W_NDimArray(impl) @staticmethod diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -58,7 +58,8 @@ w_str = "str" w_unicode = "unicode" w_complex = "complex" - + w_dict = "dict" + def __init__(self): """NOT_RPYTHON""" self.fromcache = InternalSpaceCache(self).getorbuild @@ -115,9 +116,13 @@ def newcomplex(self, r, i): return ComplexObject(r, i) - def listview(self, obj): + def listview(self, obj, number=-1): assert isinstance(obj, ListObject) + if number != -1: + assert number == 2 + return [obj.items[0], obj.items[1]] return obj.items + fixedview = listview def float(self, w_obj): @@ -480,7 +485,7 @@ w_res = neg.call(interp.space, [arr]) elif self.name == "cos": cos = interp_ufuncs.get(interp.space).cos - w_res = cos.call(interp.space, [arr]) + w_res = cos.call(interp.space, [arr]) elif self.name == "flat": w_res = arr.descr_get_flatiter(interp.space) elif self.name == "argsort": diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -133,11 +133,46 @@ space.wrap(offset)])) return w_d + def set_fields(self, space, w_fields): + if w_fields == space.w_None: + self.fields = None + else: + ofs_and_items = [] + size = 0 + for key in space.listview(w_fields): + value = space.getitem(w_fields, key) + + dtype = space.getitem(value, space.wrap(0)) + assert isinstance(dtype, W_Dtype) + + offset = space.int_w(space.getitem(value, space.wrap(1))) + self.fields[space.str_w(key)] = offset, dtype + + ofs_and_items.append((offset, dtype.itemtype)) + size += dtype.itemtype.get_element_size() + + self.itemtype = types.RecordType(ofs_and_items, size) + self.name = "void" + str(8 * self.itemtype.get_element_size()) + def descr_get_names(self, space): if self.fieldnames is None: return space.w_None return space.newtuple([space.wrap(name) for name in self.fieldnames]) + def set_names(self, space, w_names): + if w_names == space.w_None: + self.fieldnames = None + else: + self.fieldnames = [] + iter = space.iter(w_names) + while True: + try: + self.fieldnames.append(space.str_w(space.next(iter))) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + @unwrap_spec(item=str) def descr_getitem(self, space, item): if self.fields is None: @@ -180,6 +215,51 @@ def get_size(self): return self.itemtype.get_element_size() + def descr_reduce(self, space): + w_class = space.type(self) + + kind = self.kind + elemsize = self.itemtype.get_element_size() + builder_args = space.newtuple([space.wrap("%s%d" % (kind, elemsize)), space.wrap(0), space.wrap(1)]) + + version = space.wrap(3) + order = space.wrap(byteorder_prefix if self.native else nonnative_byteorder_prefix) + names = self.descr_get_names(space) + values = self.descr_get_fields(space) + if self.fields: + #TODO: Implement this when subarrays are implemented + subdescr = space.w_None + #TODO: Change this when alignment is implemented : + size = 0 + for key in self.fields: + dtype = self.fields[key][1] + assert isinstance(dtype, W_Dtype) + size += dtype.get_size() + w_size = space.wrap(size) + alignment = space.wrap(1) + else: + subdescr = space.w_None + w_size = space.wrap(-1) + alignment = space.wrap(-1) + flags = space.wrap(0) + + data = space.newtuple([version, order, subdescr, names, values, w_size, alignment, flags]) + + return space.newtuple([w_class, builder_args, data]) + + def descr_setstate(self, space, w_data): + if space.int_w(space.getitem(w_data, space.wrap(0))) != 3: + raise OperationError(space.w_NotImplementedError, space.wrap("Pickling protocol version not supported")) + + self.native = space.str_w(space.getitem(w_data, space.wrap(1))) == byteorder_prefix + + fieldnames = space.getitem(w_data, space.wrap(3)) + self.set_names(space, fieldnames) + + fields = space.getitem(w_data, space.wrap(4)) + self.set_fields(space, fields) + print self.itemtype + class W_ComplexDtype(W_Dtype): def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], @@ -238,8 +318,7 @@ num = 20 basename = 'void' w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - raise OperationError(space.w_NotImplementedError, space.wrap( - "pure void dtype")) + return dtype_from_list(space, space.newlist([])) else: assert char == 'U' basename = 'unicode' @@ -252,9 +331,10 @@ def dtype_from_spec(space, name): raise OperationError(space.w_NotImplementedError, space.wrap( - "dtype from spec")) + "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): + # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) if space.is_none(w_dtype): @@ -297,6 +377,9 @@ __ne__ = interp2app(W_Dtype.descr_ne), __getitem__ = interp2app(W_Dtype.descr_getitem), + __reduce__ = interp2app(W_Dtype.descr_reduce), + __setstate__ = interp2app(W_Dtype.descr_setstate), + num = interp_attrproperty("num", cls=W_Dtype), kind = interp_attrproperty("kind", cls=W_Dtype), char = interp_attrproperty("char", cls=W_Dtype), diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -20,6 +20,7 @@ from rpython.rlib import jit from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation +from pypy.interpreter.special import Ellipsis def _find_shape(space, w_size): if space.is_none(w_size): @@ -167,6 +168,8 @@ prefix) def descr_getitem(self, space, w_idx): + if isinstance(w_idx, Ellipsis): + return self if (isinstance(w_idx, W_NDimArray) and w_idx.get_dtype().is_bool_type()): return self.getitem_filter(space, w_idx) @@ -781,6 +784,42 @@ From noreply at buildbot.pypy.org Tue May 14 13:54:22 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 13:54:22 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Add contact information in index.rst. Message-ID: <20130514115422.947E71C0498@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64067:070a876e7d20 Date: 2013-05-14 13:15 +0200 http://bitbucket.org/pypy/pypy/changeset/070a876e7d20/ Log: Add contact information in index.rst. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -39,7 +39,31 @@ Contact ------- -.. TODO add contact information +`#pypy on irc.freenode.net`_ + Many of the core developers are hanging out here. You are welcome to join + and ask questions (if they are not already answered in the :doc:`FAQ + `). You can find logs of the channel here_. + +`Development mailing list`_ + Development and conceptual discussions + +`Commit mailing list`_ + Updates to code and documentation + +`Development bug/feature tracker`_ + Filing bugs and feature requests + +Meeting PyPy developers + The PyPy developers are organizing sprints and presenting results at + conferences all year round. They will be happy to meet in person with + anyone interested in the project. Watch out for sprint announcements on + the `development mailing list`_. + +.. _#pypy on irc.freenode.net: irc://irc.freenode.net/pypy +.. _here: http://tismerysoft.de/pypy/irc-logs/pypy +.. _Development mailing list: http://python.org/mailman/listinfo/pypy-dev +.. _Commit mailing list: http://python.org/mailman/listinfo/pypy-commit +.. _Development bug/feature tracker: https://bugs.pypy.org/ Indices and tables From noreply at buildbot.pypy.org Tue May 14 13:54:24 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 13:54:24 +0200 (CEST) Subject: [pypy-commit] pypy improve-docs: Write an introduction; set the depth of the user TOC to 1. Message-ID: <20130514115424.11F7E1C0498@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: improve-docs Changeset: r64068:c0bb38b87c76 Date: 2013-05-14 13:52 +0200 http://bitbucket.org/pypy/pypy/changeset/c0bb38b87c76/ Log: Write an introduction; set the depth of the user TOC to 1. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -1,14 +1,26 @@ Welcome to PyPy's documentation! ================================ -.. TODO write introduction +Welcome to the documentation for PyPy, a fast_, compliant alternative +implementation of the Python_ language. If you don't know what PyPy is, +consult the `PyPy website`_. + +PyPy is written using the RPython toolchain. RPython enables writing dynamic +language interpreters in a subset of Python which can be translated to C code +including an automatically generated JIT for the implemented language. If you +want to learn more about RPython, see the `RPython website`_. + +.. _fast: http://speed.pypy.org +.. _Python: http://python.org/ +.. _PyPy website: http://pypy.org/ +.. _RPython website: http://rpython.readthedocs.org/ User documentation ------------------ .. toctree:: - :maxdepth: 2 + :maxdepth: 1 install build From noreply at buildbot.pypy.org Tue May 14 14:41:27 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Tue, 14 May 2013 14:41:27 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Make the creation of subarrays at applevel possible Message-ID: <20130514124127.7DE621C009D@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64069:e90bb7b49080 Date: 2013-05-14 14:40 +0200 http://bitbucket.org/pypy/pypy/changeset/e90bb7b49080/ Log: Make the creation of subarrays at applevel possible diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -349,10 +349,12 @@ # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) - if w_shape is not None and space.len_w(w_shape) > 0: + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) assert isinstance(subdtype, W_Dtype) size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) shape = space.listview(w_shape) for dim in shape: size *= space.int_w(dim) @@ -377,6 +379,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -804,6 +804,11 @@ assert e.fields.keys() == keys assert e['x'].shape == (2,) + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype("float64"), (10,)) class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): From noreply at buildbot.pypy.org Tue May 14 14:43:51 2013 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 14 May 2013 14:43:51 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: parse func level flags, improve external_loop test Message-ID: <20130514124351.0BB8C1C009D@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r64070:a5fd211f5b3b Date: 2013-05-14 15:42 +0300 http://bitbucket.org/pypy/pypy/changeset/a5fd211f5b3b/ Log: parse func level flags, improve external_loop test diff --git a/pypy/module/micronumpy/interp_nditer.py b/pypy/module/micronumpy/interp_nditer.py --- a/pypy/module/micronumpy/interp_nditer.py +++ b/pypy/module/micronumpy/interp_nditer.py @@ -94,6 +94,53 @@ op_flag.get_it_item = get_readwrite_item return op_flag +def parse_func_flags(space, nditer, w_flags): + if space.is_w(w_flags, space.w_None): + return + elif not space.isinstance_w(w_flags, space.w_tuple) and not \ + space.isinstance_w(w_flags, space.w_list): + raise OperationError(space.w_ValueError, space.wrap( + 'Iter global flags must be a list or tuple of strings')) + lst = space.listview(w_flags) + for w_item in lst: + if not space.isinstance_w(w_item, space.w_str) and not \ + space.isinstance_w(w_item, space.w_unicode): + typename = space.type(w_item).getname(space) + raise OperationError(space.w_TypeError, space.wrap( + 'expected string or Unicode object, %s found' % typename)) + item = space.str_w(w_item) + if item == 'external_loop': + nditer.external_loop = True + elif item == 'buffered': + nditer.buffered = True + elif item == 'c_index': + nditer.tracked_index = 'C' + elif item == 'f_index': + nditer.tracked_index = 'F' + elif item == 'multi_index': + nditer.tracked_index = 'multi' + elif item == 'common_dtype': + nditer.common_dtype = True + elif item == 'delay_bufalloc': + nditer.delay_bufalloc = True + elif item == 'grow_inner': + nditer.grow_inner = True + elif item == 'ranged': + nditer.ranged = True + elif item == 'refs_ok': + nditer.refs_ok = True + elif item == 'reduce_ok': + nditer.reduce_ok = True + elif item == 'zerosize_ok': + nditer.zerosize_ok = True + else: + raise OperationError(space.w_ValueError, space.wrap( + 'Unexpected iterator global flag "%s"', item)) + if nditer.tracked_index and nditer.external_loop: + raise OperationError(space.w_ValueError, space.wrap( + 'Iterator flag EXTERNAL_LOOP cannot be used if an index or ' + 'multi-index is being tracked')) + def get_iter(space, order, imp, backward): if order == 'K' or (order == 'C' and imp.order == 'C'): backward = False @@ -123,16 +170,28 @@ def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, w_itershape, w_buffersize, order): self.order = order + self.external_loop = False + self.buffered = False + self.tracked_index = '' + self.common_dtype = False + self.delay_bufalloc = False + self.grow_inner = False + self.ranged = False + self.refs_ok = False + self.reduce_ok = False + self.zerosize_ok = False if space.isinstance_w(w_seq, space.w_tuple) or \ space.isinstance_w(w_seq, space.w_list): w_seq_as_list = space.listview(w_seq) self.seq = [convert_to_array(space, w_elem) for w_elem in w_seq_as_list] else: self.seq =[convert_to_array(space, w_seq)] + parse_func_flags(space, self, w_flags) self.op_flags = parse_op_arg(space, 'op_flags', w_op_flags, len(self.seq), parse_op_flag) self.iters=[] for i in range(len(self.seq)): + # XXX the shape of the iter depends on all the seq.shapes together self.iters.append(get_iter(space, self.order, self.seq[i].implementation, self.op_flags[i])) diff --git a/pypy/module/micronumpy/test/test_nditer.py b/pypy/module/micronumpy/test/test_nditer.py --- a/pypy/module/micronumpy/test/test_nditer.py +++ b/pypy/module/micronumpy/test/test_nditer.py @@ -46,13 +46,18 @@ from numpypy import arange, nditer, array a = arange(6).reshape(2,3) r = [] + n = 0 for x in nditer(a, flags=['external_loop']): r.append(x) + n += 1 + assert n == 1 assert (array(r) == [0, 1, 2, 3, 4, 5]).all() r = [] + n = 0 for x in nditer(a, flags=['external_loop'], order='F'): r.append(x) - print r + n += 1 + assert n == 3 assert (array(r) == [[0, 3], [1, 4], [2, 5]]).all() def test_interface(self): From noreply at buildbot.pypy.org Tue May 14 17:20:32 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:32 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Move contents of pypy/objspace/std/dicttype.py. Message-ID: <20130514152032.8583B1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64071:6335c9fbeba9 Date: 2013-05-14 15:36 +0200 http://bitbucket.org/pypy/pypy/changeset/6335c9fbeba9/ Log: Move contents of pypy/objspace/std/dicttype.py. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -2,8 +2,11 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.settype import set_typedef as settypedef +from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef +from pypy.interpreter import gateway from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint @@ -41,8 +44,6 @@ class W_DictMultiObject(W_Object): - from pypy.objspace.std.dicttype import dict_typedef as typedef - @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, strdict=False, kwargs=False): @@ -971,8 +972,6 @@ class W_BaseDictMultiIterObject(W_Object): - from pypy.objspace.std.dicttype import dictiter_typedef as typedef - _immutable_fields_ = ["iteratorimplementation"] ignore_for_isinstance_cache = True @@ -1032,15 +1031,15 @@ w_self.w_dict = w_dict class W_DictViewKeysObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_keys_typedef as typedef + pass registerimplementation(W_DictViewKeysObject) class W_DictViewItemsObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_items_typedef as typedef + pass registerimplementation(W_DictViewItemsObject) class W_DictViewValuesObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_values_typedef as typedef + pass registerimplementation(W_DictViewValuesObject) def len__DictViewKeys(space, w_dictview): @@ -1115,5 +1114,221 @@ # ____________________________________________________________ -from pypy.objspace.std import dicttype -register_all(vars(), dicttype) + + +dict_copy = SMM('copy', 1, + doc='D.copy() -> a shallow copy of D') +dict_items = SMM('items', 1, + doc="D.items() -> list of D's (key, value) pairs, as" + ' 2-tuples') +dict_keys = SMM('keys', 1, + doc="D.keys() -> list of D's keys") +dict_values = SMM('values', 1, + doc="D.values() -> list of D's values") +dict_has_key = SMM('has_key', 2, + doc='D.has_key(k) -> True if D has a key k, else False') +dict_clear = SMM('clear', 1, + doc='D.clear() -> None. Remove all items from D.') +dict_get = SMM('get', 3, defaults=(None,), + doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' + ' to None.') +dict_pop = SMM('pop', 2, varargs_w=True, + doc='D.pop(k[,d]) -> v, remove specified key and return' + ' the corresponding value\nIf key is not found, d is' + ' returned if given, otherwise KeyError is raised') +dict_popitem = SMM('popitem', 1, + doc='D.popitem() -> (k, v), remove and return some (key,' + ' value) pair as a\n2-tuple; but raise KeyError if D' + ' is empty') +dict_setdefault = SMM('setdefault', 3, defaults=(None,), + doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' + ' if k not in D') +dict_update = SMM('update', 1, general__args__=True, + doc='D.update(E, **F) -> None. Update D from E and F:' + ' for k in E: D[k] = E[k]\n(if E has keys else: for' + ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' + ' F[k]') +dict_iteritems = SMM('iteritems', 1, + doc='D.iteritems() -> an iterator over the (key, value)' + ' items of D') +dict_iterkeys = SMM('iterkeys', 1, + doc='D.iterkeys() -> an iterator over the keys of D') +dict_itervalues = SMM('itervalues', 1, + doc='D.itervalues() -> an iterator over the values of D') +dict_viewkeys = SMM('viewkeys', 1, + doc="D.viewkeys() -> a set-like object providing a view on D's keys") +dict_viewitems = SMM('viewitems', 1, + doc="D.viewitems() -> a set-like object providing a view on D's items") +dict_viewvalues = SMM('viewvalues', 1, + doc="D.viewvalues() -> an object providing a view on D's values") +dict_reversed = SMM('__reversed__', 1) + +def dict_reversed__ANY(space, w_dict): + raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + +register_all(vars(), globals()) + +def descr_fromkeys(space, w_type, w_keys, w_fill=None): + from pypy.objspace.std.dictmultiobject import W_DictMultiObject + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + + +app = gateway.applevel(''' + def dictrepr(currently_in_repr, d): + if len(d) == 0: + return "{}" + dict_id = id(d) + if dict_id in currently_in_repr: + return '{...}' + currently_in_repr[dict_id] = 1 + try: + items = [] + # XXX for now, we cannot use iteritems() at app-level because + # we want a reasonable result instead of a RuntimeError + # even if the dict is mutated by the repr() in the loop. + for k, v in dict.items(d): + items.append(repr(k) + ": " + repr(v)) + return "{" + ', '.join(items) + "}" + finally: + try: + del currently_in_repr[dict_id] + except: + pass +''', filename=__file__) + +dictrepr = app.interphook("dictrepr") + + +def descr_repr(space, w_dict): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, w_dict) + + +# ____________________________________________________________ + +def descr__new__(space, w_dicttype, __args__): + from pypy.objspace.std.dictmultiobject import W_DictMultiObject + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + +# ____________________________________________________________ + +W_DictMultiObject.typedef = StdTypeDef("dict", + __doc__ = '''dict() -> new empty dictionary. +dict(mapping) -> new dictionary initialized from a mapping object\'s + (key, value) pairs. +dict(seq) -> new dictionary initialized as if via: + d = {} + for k, v in seq: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)''', + __new__ = gateway.interp2app(descr__new__), + __hash__ = None, + __repr__ = gateway.interp2app(descr_repr), + fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), + ) +W_DictMultiObject.typedef.registermethods(globals()) +dict_typedef = W_DictMultiObject.typedef + +# ____________________________________________________________ + +def descr_dictiter__length_hint__(space, w_self): + from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject + assert isinstance(w_self, W_BaseDictMultiIterObject) + return space.wrap(w_self.iteratorimplementation.length()) + + +def descr_dictiter__reduce__(w_self, space): + """ + This is a slightly special case of pickling. + Since iteration over a dict is a bit hairy, + we do the following: + - create a clone of the dict iterator + - run it to the original position + - collect all remaining elements into a list + At unpickling time, we just use that list + and create an iterator on it. + This is of course not the standard way. + + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('dictiter_surrogate_new') + w_typeobj = space.gettypeobject(dictiter_typedef) + + raise OperationError( + space.w_TypeError, + space.wrap("can't pickle dictionary-keyiterator objects")) + # XXXXXX get that working again + + # we cannot call __init__ since we don't have the original dict + if isinstance(w_self, W_DictIter_Keys): + w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) + elif isinstance(w_self, W_DictIter_Values): + w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) + elif isinstance(w_self, W_DictIter_Items): + w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + else: + msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_clone.space = space + w_clone.content = w_self.content + w_clone.len = w_self.len + w_clone.pos = 0 + w_clone.setup_iterator() + # spool until we have the same pos + while w_clone.pos < w_self.pos: + w_obj = w_clone.next_entry() + w_clone.pos += 1 + stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] + w_res = space.newlist(stuff) + tup = [ + w_res + ] + w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + return w_ret + +# ____________________________________________________________ + + +W_BaseDictMultiIterObject.typedef = StdTypeDef("dictionaryiterator", + __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), + __reduce__ = gateway.interp2app(descr_dictiter__reduce__), + ) + +# ____________________________________________________________ +# Dict views + +W_DictViewKeysObject.typedef = StdTypeDef( + "dict_keys", + ) + +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + ) + +W_DictViewValuesObject.typedef = StdTypeDef( + "dict_values", + ) diff --git a/pypy/objspace/std/dicttype.py b/pypy/objspace/std/dicttype.py deleted file mode 100644 --- a/pypy/objspace/std/dicttype.py +++ /dev/null @@ -1,221 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter.mixedmodule import MixedModule -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.register_all import register_all - -dict_copy = SMM('copy', 1, - doc='D.copy() -> a shallow copy of D') -dict_items = SMM('items', 1, - doc="D.items() -> list of D's (key, value) pairs, as" - ' 2-tuples') -dict_keys = SMM('keys', 1, - doc="D.keys() -> list of D's keys") -dict_values = SMM('values', 1, - doc="D.values() -> list of D's values") -dict_has_key = SMM('has_key', 2, - doc='D.has_key(k) -> True if D has a key k, else False') -dict_clear = SMM('clear', 1, - doc='D.clear() -> None. Remove all items from D.') -dict_get = SMM('get', 3, defaults=(None,), - doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' - ' to None.') -dict_pop = SMM('pop', 2, varargs_w=True, - doc='D.pop(k[,d]) -> v, remove specified key and return' - ' the corresponding value\nIf key is not found, d is' - ' returned if given, otherwise KeyError is raised') -dict_popitem = SMM('popitem', 1, - doc='D.popitem() -> (k, v), remove and return some (key,' - ' value) pair as a\n2-tuple; but raise KeyError if D' - ' is empty') -dict_setdefault = SMM('setdefault', 3, defaults=(None,), - doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' - ' if k not in D') -dict_update = SMM('update', 1, general__args__=True, - doc='D.update(E, **F) -> None. Update D from E and F:' - ' for k in E: D[k] = E[k]\n(if E has keys else: for' - ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' - ' F[k]') -dict_iteritems = SMM('iteritems', 1, - doc='D.iteritems() -> an iterator over the (key, value)' - ' items of D') -dict_iterkeys = SMM('iterkeys', 1, - doc='D.iterkeys() -> an iterator over the keys of D') -dict_itervalues = SMM('itervalues', 1, - doc='D.itervalues() -> an iterator over the values of D') -dict_viewkeys = SMM('viewkeys', 1, - doc="D.viewkeys() -> a set-like object providing a view on D's keys") -dict_viewitems = SMM('viewitems', 1, - doc="D.viewitems() -> a set-like object providing a view on D's items") -dict_viewvalues = SMM('viewvalues', 1, - doc="D.viewvalues() -> an object providing a view on D's values") -dict_reversed = SMM('__reversed__', 1) - -def dict_reversed__ANY(space, w_dict): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - -register_all(vars(), globals()) - -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - - -app = gateway.applevel(''' - def dictrepr(currently_in_repr, d): - if len(d) == 0: - return "{}" - dict_id = id(d) - if dict_id in currently_in_repr: - return '{...}' - currently_in_repr[dict_id] = 1 - try: - items = [] - # XXX for now, we cannot use iteritems() at app-level because - # we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in dict.items(d): - items.append(repr(k) + ": " + repr(v)) - return "{" + ', '.join(items) + "}" - finally: - try: - del currently_in_repr[dict_id] - except: - pass -''', filename=__file__) - -dictrepr = app.interphook("dictrepr") - - -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - -dict_typedef = StdTypeDef("dict", - __doc__ = '''dict() -> new empty dictionary. -dict(mapping) -> new dictionary initialized from a mapping object\'s - (key, value) pairs. -dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v -dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), - ) -dict_typedef.registermethods(globals()) - -# ____________________________________________________________ - -def descr_dictiter__length_hint__(space, w_self): - from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject - assert isinstance(w_self, W_BaseDictMultiIterObject) - return space.wrap(w_self.iteratorimplementation.length()) - - -def descr_dictiter__reduce__(w_self, space): - """ - This is a slightly special case of pickling. - Since iteration over a dict is a bit hairy, - we do the following: - - create a clone of the dict iterator - - run it to the original position - - collect all remaining elements into a list - At unpickling time, we just use that list - and create an iterator on it. - This is of course not the standard way. - - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) - - raise OperationError( - space.w_TypeError, - space.wrap("can't pickle dictionary-keyiterator objects")) - # XXXXXX get that working again - - # we cannot call __init__ since we don't have the original dict - if isinstance(w_self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(w_self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(w_self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) - else: - msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_clone.space = space - w_clone.content = w_self.content - w_clone.len = w_self.len - w_clone.pos = 0 - w_clone.setup_iterator() - # spool until we have the same pos - while w_clone.pos < w_self.pos: - w_obj = w_clone.next_entry() - w_clone.pos += 1 - stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] - w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) - return w_ret - -# ____________________________________________________________ - - -dictiter_typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), - __reduce__ = gateway.interp2app(descr_dictiter__reduce__), - ) - -# ____________________________________________________________ -# Dict views - -dict_keys_typedef = StdTypeDef( - "dict_keys", - ) - -dict_items_typedef = StdTypeDef( - "dict_items", - ) - -dict_values_typedef = StdTypeDef( - "dict_values", - ) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -42,7 +42,7 @@ from pypy.objspace.std.frozensettype import frozenset_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef - from pypy.objspace.std.dicttype import dict_typedef + from pypy.objspace.std.dictmultiobject import dict_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef From noreply at buildbot.pypy.org Tue May 14 17:20:33 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:33 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.copy SMM. Message-ID: <20130514152033.CCEBF1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64072:7816d0cf2655 Date: 2013-05-14 15:46 +0200 http://bitbucket.org/pypy/pypy/changeset/7816d0cf2655/ Log: Remove dict.copy SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -109,6 +109,12 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + def descr_copy(self, space): + """D.copy() -> a shallow copy of D""" + w_new = W_DictMultiObject.allocate_and_init_instance(space) + update1_dict_dict(space, w_new, self) + return w_new + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -897,11 +903,6 @@ w_res = space.lt(w_leftval, w_rightval) return w_res -def dict_copy__DictMulti(space, w_self): - w_new = W_DictMultiObject.allocate_and_init_instance(space) - update1_dict_dict(space, w_new, w_self) - return w_new - def dict_items__DictMulti(space, w_self): return space.newlist(w_self.items()) @@ -1116,8 +1117,6 @@ -dict_copy = SMM('copy', 1, - doc='D.copy() -> a shallow copy of D') dict_items = SMM('items', 1, doc="D.items() -> list of D's (key, value) pairs, as" ' 2-tuples') @@ -1246,6 +1245,7 @@ __hash__ = None, __repr__ = gateway.interp2app(descr_repr), fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), + copy = gateway.interp2app(W_DictMultiObject.descr_copy), ) W_DictMultiObject.typedef.registermethods(globals()) dict_typedef = W_DictMultiObject.typedef From noreply at buildbot.pypy.org Tue May 14 17:20:35 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:35 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Add stubs. Message-ID: <20130514152035.238381C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64073:dc9c8fc43e0b Date: 2013-05-14 15:55 +0200 http://bitbucket.org/pypy/pypy/changeset/dc9c8fc43e0b/ Log: Add stubs. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -115,6 +115,57 @@ update1_dict_dict(space, w_new, self) return w_new +# def descr_items(self, space): +# """""" + +# def descr_keys(self, space): +# """""" + +# def descr_values(self, space): +# """""" + +# def descr_has_key(self, space): +# """""" + +# def descr_clear(self, space): +# """""" + +# def descr_get(self, space): +# """""" + +# def descr_pop(self, space): +# """""" + +# def descr_popitem(self, space): +# """""" + +# def descr_setdefault(self, space): +# """""" + +# def descr_update(self, space): +# """""" + +# def descr_iteritems(self, space): +# """""" + +# def descr_iterkeys(self, space): +# """""" + +# def descr_itervalues(self, space): +# """""" + +# def descr_viewkeys(self, space): +# """""" + +# def descr_viewitems(self, space): +# """""" + +# def descr_viewvalues(self, space): +# """""" + +# def descr_reversed(self, space): +# """""" + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -1246,6 +1297,23 @@ __repr__ = gateway.interp2app(descr_repr), fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), copy = gateway.interp2app(W_DictMultiObject.descr_copy), + #items = gateway.interp2app(W_DictMultiObject.descr_items), + #keys = gateway.interp2app(W_DictMultiObject.descr_keys), + #values = gateway.interp2app(W_DictMultiObject.descr_values), + #has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), + #clear = gateway.interp2app(W_DictMultiObject.descr_clear), + #get = gateway.interp2app(W_DictMultiObject.descr_get), + #pop = gateway.interp2app(W_DictMultiObject.descr_pop), + #popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), + #setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), + #update = gateway.interp2app(W_DictMultiObject.descr_update), + #iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), + #iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), + #itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), + #viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), + #viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), + #viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), + #reversed = gateway.interp2app(W_DictMultiObject.descr_reversed), ) W_DictMultiObject.typedef.registermethods(globals()) dict_typedef = W_DictMultiObject.typedef From noreply at buildbot.pypy.org Tue May 14 17:20:36 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:36 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.items SMM. Message-ID: <20130514152036.54CF51C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64074:f86c89b3e2e1 Date: 2013-05-14 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/f86c89b3e2e1/ Log: Remove dict.items SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -115,8 +115,9 @@ update1_dict_dict(space, w_new, self) return w_new -# def descr_items(self, space): -# """""" + def descr_items(self, space): + """D.items() -> list of D's (key, value) pairs, as 2-tuples""" + return space.newlist(self.items()) # def descr_keys(self, space): # """""" @@ -954,9 +955,6 @@ w_res = space.lt(w_leftval, w_rightval) return w_res -def dict_items__DictMulti(space, w_self): - return space.newlist(w_self.items()) - def dict_keys__DictMulti(space, w_self): return w_self.w_keys() @@ -1168,9 +1166,6 @@ -dict_items = SMM('items', 1, - doc="D.items() -> list of D's (key, value) pairs, as" - ' 2-tuples') dict_keys = SMM('keys', 1, doc="D.keys() -> list of D's keys") dict_values = SMM('values', 1, @@ -1297,7 +1292,7 @@ __repr__ = gateway.interp2app(descr_repr), fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), copy = gateway.interp2app(W_DictMultiObject.descr_copy), - #items = gateway.interp2app(W_DictMultiObject.descr_items), + items = gateway.interp2app(W_DictMultiObject.descr_items), #keys = gateway.interp2app(W_DictMultiObject.descr_keys), #values = gateway.interp2app(W_DictMultiObject.descr_values), #has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), From noreply at buildbot.pypy.org Tue May 14 17:20:37 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:37 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.keys SMM. Message-ID: <20130514152037.8B8941C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64075:95b4b5617f4f Date: 2013-05-14 16:06 +0200 http://bitbucket.org/pypy/pypy/changeset/95b4b5617f4f/ Log: Remove dict.keys SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -119,8 +119,9 @@ """D.items() -> list of D's (key, value) pairs, as 2-tuples""" return space.newlist(self.items()) -# def descr_keys(self, space): -# """""" + def descr_keys(self, space): + """D.keys() -> list of D's keys""" + return self.w_keys() # def descr_values(self, space): # """""" @@ -955,9 +956,6 @@ w_res = space.lt(w_leftval, w_rightval) return w_res -def dict_keys__DictMulti(space, w_self): - return w_self.w_keys() - def dict_values__DictMulti(space, w_self): return space.newlist(w_self.values()) @@ -1167,7 +1165,7 @@ dict_keys = SMM('keys', 1, - doc="D.keys() -> list of D's keys") + doc="") dict_values = SMM('values', 1, doc="D.values() -> list of D's values") dict_has_key = SMM('has_key', 2, @@ -1293,7 +1291,7 @@ fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), copy = gateway.interp2app(W_DictMultiObject.descr_copy), items = gateway.interp2app(W_DictMultiObject.descr_items), - #keys = gateway.interp2app(W_DictMultiObject.descr_keys), + keys = gateway.interp2app(W_DictMultiObject.descr_keys), #values = gateway.interp2app(W_DictMultiObject.descr_values), #has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), #clear = gateway.interp2app(W_DictMultiObject.descr_clear), From noreply at buildbot.pypy.org Tue May 14 17:20:38 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:38 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.values SMM. Message-ID: <20130514152038.ABB791C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64076:e54f2a055f4d Date: 2013-05-14 16:08 +0200 http://bitbucket.org/pypy/pypy/changeset/e54f2a055f4d/ Log: Remove dict.values SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -123,8 +123,9 @@ """D.keys() -> list of D's keys""" return self.w_keys() -# def descr_values(self, space): -# """""" + def descr_values(self, space): + """D.values() -> list of D's values""" + return space.newlist(self.values()) # def descr_has_key(self, space): # """""" @@ -956,9 +957,6 @@ w_res = space.lt(w_leftval, w_rightval) return w_res -def dict_values__DictMulti(space, w_self): - return space.newlist(w_self.values()) - def dict_iteritems__DictMulti(space, w_self): return W_DictMultiIterItemsObject(space, w_self.iteritems()) @@ -1167,7 +1165,7 @@ dict_keys = SMM('keys', 1, doc="") dict_values = SMM('values', 1, - doc="D.values() -> list of D's values") + doc="") dict_has_key = SMM('has_key', 2, doc='D.has_key(k) -> True if D has a key k, else False') dict_clear = SMM('clear', 1, @@ -1292,7 +1290,7 @@ copy = gateway.interp2app(W_DictMultiObject.descr_copy), items = gateway.interp2app(W_DictMultiObject.descr_items), keys = gateway.interp2app(W_DictMultiObject.descr_keys), - #values = gateway.interp2app(W_DictMultiObject.descr_values), + values = gateway.interp2app(W_DictMultiObject.descr_values), #has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), #clear = gateway.interp2app(W_DictMultiObject.descr_clear), #get = gateway.interp2app(W_DictMultiObject.descr_get), From noreply at buildbot.pypy.org Tue May 14 17:20:39 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:39 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.has_key SMM. Message-ID: <20130514152039.CE8AF1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64077:84cc4042b49d Date: 2013-05-14 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/84cc4042b49d/ Log: Remove dict.has_key SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -127,8 +127,10 @@ """D.values() -> list of D's values""" return space.newlist(self.values()) -# def descr_has_key(self, space): -# """""" + def descr_has_key(self, space, w_key): + """D.has_key(k) -> True if D has a key k, else False""" + # XXX duplication with contains + return space.newbool(self.getitem(w_key) is not None) # def descr_clear(self, space): # """""" @@ -891,8 +893,6 @@ def contains__DictMulti_ANY(space, w_dict, w_key): return space.newbool(w_dict.getitem(w_key) is not None) -dict_has_key__DictMulti_ANY = contains__DictMulti_ANY - def iter__DictMulti(space, w_dict): return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) @@ -1167,7 +1167,7 @@ dict_values = SMM('values', 1, doc="") dict_has_key = SMM('has_key', 2, - doc='D.has_key(k) -> True if D has a key k, else False') + doc='') dict_clear = SMM('clear', 1, doc='D.clear() -> None. Remove all items from D.') dict_get = SMM('get', 3, defaults=(None,), @@ -1291,7 +1291,7 @@ items = gateway.interp2app(W_DictMultiObject.descr_items), keys = gateway.interp2app(W_DictMultiObject.descr_keys), values = gateway.interp2app(W_DictMultiObject.descr_values), - #has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), + has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), #clear = gateway.interp2app(W_DictMultiObject.descr_clear), #get = gateway.interp2app(W_DictMultiObject.descr_get), #pop = gateway.interp2app(W_DictMultiObject.descr_pop), From noreply at buildbot.pypy.org Tue May 14 17:20:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:41 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.clear SMM. Message-ID: <20130514152041.0717D1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64078:2520692c9e40 Date: 2013-05-14 16:14 +0200 http://bitbucket.org/pypy/pypy/changeset/2520692c9e40/ Log: Remove dict.clear SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -132,8 +132,9 @@ # XXX duplication with contains return space.newbool(self.getitem(w_key) is not None) -# def descr_clear(self, space): -# """""" + def descr_clear(self, space): + """D.clear() -> None. Remove all items from D.""" + self.clear() # def descr_get(self, space): # """""" @@ -975,9 +976,6 @@ def dict_viewvalues__DictMulti(space, w_self): return W_DictViewValuesObject(space, w_self) -def dict_clear__DictMulti(space, w_self): - w_self.clear() - def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): w_value = w_dict.getitem(w_key) if w_value is not None: @@ -1169,7 +1167,7 @@ dict_has_key = SMM('has_key', 2, doc='') dict_clear = SMM('clear', 1, - doc='D.clear() -> None. Remove all items from D.') + doc='') dict_get = SMM('get', 3, defaults=(None,), doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' ' to None.') @@ -1292,7 +1290,7 @@ keys = gateway.interp2app(W_DictMultiObject.descr_keys), values = gateway.interp2app(W_DictMultiObject.descr_values), has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), - #clear = gateway.interp2app(W_DictMultiObject.descr_clear), + clear = gateway.interp2app(W_DictMultiObject.descr_clear), #get = gateway.interp2app(W_DictMultiObject.descr_get), #pop = gateway.interp2app(W_DictMultiObject.descr_pop), #popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), From noreply at buildbot.pypy.org Tue May 14 17:20:42 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:42 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.{iter, view}{items, keys, values} SMMs. Message-ID: <20130514152042.208D41C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64079:fdb190651450 Date: 2013-05-14 16:31 +0200 http://bitbucket.org/pypy/pypy/changeset/fdb190651450/ Log: Remove dict.{iter,view}{items,keys,values} SMMs. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -127,6 +127,30 @@ """D.values() -> list of D's values""" return space.newlist(self.values()) + def descr_iteritems(self, space): + """D.iteritems() -> an iterator over the (key, value) items of D""" + return W_DictMultiIterItemsObject(space, self.iteritems()) + + def descr_iterkeys(self, space): + """D.iterkeys() -> an iterator over the keys of D""" + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_itervalues(self, space): + """D.itervalues() -> an iterator over the values of D""" + return W_DictMultiIterValuesObject(space, self.itervalues()) + + def descr_viewitems(self, space): + """D.viewitems() -> a set-like object providing a view on D's items""" + return W_DictViewItemsObject(space, self) + + def descr_viewkeys(self, space): + """D.viewkeys() -> a set-like object providing a view on D's keys""" + return W_DictViewKeysObject(space, self) + + def descr_viewvalues(self, space): + """D.viewvalues() -> an object providing a view on D's values""" + return W_DictViewValuesObject(space, self) + def descr_has_key(self, space, w_key): """D.has_key(k) -> True if D has a key k, else False""" # XXX duplication with contains @@ -151,24 +175,6 @@ # def descr_update(self, space): # """""" -# def descr_iteritems(self, space): -# """""" - -# def descr_iterkeys(self, space): -# """""" - -# def descr_itervalues(self, space): -# """""" - -# def descr_viewkeys(self, space): -# """""" - -# def descr_viewitems(self, space): -# """""" - -# def descr_viewvalues(self, space): -# """""" - # def descr_reversed(self, space): # """""" @@ -958,24 +964,6 @@ w_res = space.lt(w_leftval, w_rightval) return w_res -def dict_iteritems__DictMulti(space, w_self): - return W_DictMultiIterItemsObject(space, w_self.iteritems()) - -def dict_iterkeys__DictMulti(space, w_self): - return W_DictMultiIterKeysObject(space, w_self.iterkeys()) - -def dict_itervalues__DictMulti(space, w_self): - return W_DictMultiIterValuesObject(space, w_self.itervalues()) - -def dict_viewitems__DictMulti(space, w_self): - return W_DictViewItemsObject(space, w_self) - -def dict_viewkeys__DictMulti(space, w_self): - return W_DictViewKeysObject(space, w_self) - -def dict_viewvalues__DictMulti(space, w_self): - return W_DictViewValuesObject(space, w_self) - def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): w_value = w_dict.getitem(w_key) if w_value is not None: @@ -1074,29 +1062,25 @@ def __init__(w_self, space, w_dict): w_self.w_dict = w_dict +class W_DictViewItemsObject(W_DictViewObject): + def descr__iter__(self, space): + return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) +registerimplementation(W_DictViewItemsObject) + class W_DictViewKeysObject(W_DictViewObject): - pass + def descr__iter__(self, space): + return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) registerimplementation(W_DictViewKeysObject) -class W_DictViewItemsObject(W_DictViewObject): - pass -registerimplementation(W_DictViewItemsObject) - class W_DictViewValuesObject(W_DictViewObject): - pass + def descr__iter__(self, space): + return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) registerimplementation(W_DictViewValuesObject) def len__DictViewKeys(space, w_dictview): return space.len(w_dictview.w_dict) len__DictViewItems = len__DictViewValues = len__DictViewKeys -def iter__DictViewKeys(space, w_dictview): - return dict_iterkeys__DictMulti(space, w_dictview.w_dict) -def iter__DictViewItems(space, w_dictview): - return dict_iteritems__DictMulti(space, w_dictview.w_dict) -def iter__DictViewValues(space, w_dictview): - return dict_itervalues__DictMulti(space, w_dictview.w_dict) - def all_contained_in(space, w_dictview, w_otherview): w_iter = space.iter(w_dictview) @@ -1187,19 +1171,6 @@ ' for k in E: D[k] = E[k]\n(if E has keys else: for' ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' ' F[k]') -dict_iteritems = SMM('iteritems', 1, - doc='D.iteritems() -> an iterator over the (key, value)' - ' items of D') -dict_iterkeys = SMM('iterkeys', 1, - doc='D.iterkeys() -> an iterator over the keys of D') -dict_itervalues = SMM('itervalues', 1, - doc='D.itervalues() -> an iterator over the values of D') -dict_viewkeys = SMM('viewkeys', 1, - doc="D.viewkeys() -> a set-like object providing a view on D's keys") -dict_viewitems = SMM('viewitems', 1, - doc="D.viewitems() -> a set-like object providing a view on D's items") -dict_viewvalues = SMM('viewvalues', 1, - doc="D.viewvalues() -> an object providing a view on D's values") dict_reversed = SMM('__reversed__', 1) def dict_reversed__ANY(space, w_dict): @@ -1289,6 +1260,12 @@ items = gateway.interp2app(W_DictMultiObject.descr_items), keys = gateway.interp2app(W_DictMultiObject.descr_keys), values = gateway.interp2app(W_DictMultiObject.descr_values), + iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), clear = gateway.interp2app(W_DictMultiObject.descr_clear), #get = gateway.interp2app(W_DictMultiObject.descr_get), @@ -1296,12 +1273,6 @@ #popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), #setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), #update = gateway.interp2app(W_DictMultiObject.descr_update), - #iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), - #iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), - #itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), - #viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), - #viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), - #viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), #reversed = gateway.interp2app(W_DictMultiObject.descr_reversed), ) W_DictMultiObject.typedef.registermethods(globals()) @@ -1378,14 +1349,17 @@ # ____________________________________________________________ # Dict views +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + __iter__ = gateway.interp2app(W_DictViewItemsObject.descr__iter__) + ) + W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", - ) - -W_DictViewItemsObject.typedef = StdTypeDef( - "dict_items", + __iter__ = gateway.interp2app(W_DictViewKeysObject.descr__iter__) ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", + __iter__ = gateway.interp2app(W_DictViewValuesObject.descr__iter__) ) From noreply at buildbot.pypy.org Tue May 14 17:20:43 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:43 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.get SMM. Message-ID: <20130514152043.685841C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64080:a870c05e9f35 Date: 2013-05-14 16:38 +0200 http://bitbucket.org/pypy/pypy/changeset/a870c05e9f35/ Log: Remove dict.get SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -160,8 +160,14 @@ """D.clear() -> None. Remove all items from D.""" self.clear() -# def descr_get(self, space): -# """""" + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_get(self, space, w_key, w_default): + """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + else: + return w_default # def descr_pop(self, space): # """""" @@ -964,13 +970,6 @@ w_res = space.lt(w_leftval, w_rightval) return w_res -def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default - def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): return w_dict.setdefault(w_key, w_default) @@ -1153,8 +1152,7 @@ dict_clear = SMM('clear', 1, doc='') dict_get = SMM('get', 3, defaults=(None,), - doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' - ' to None.') + doc='') dict_pop = SMM('pop', 2, varargs_w=True, doc='D.pop(k[,d]) -> v, remove specified key and return' ' the corresponding value\nIf key is not found, d is' @@ -1268,7 +1266,7 @@ viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), clear = gateway.interp2app(W_DictMultiObject.descr_clear), - #get = gateway.interp2app(W_DictMultiObject.descr_get), + get = gateway.interp2app(W_DictMultiObject.descr_get), #pop = gateway.interp2app(W_DictMultiObject.descr_pop), #popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), #setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), From noreply at buildbot.pypy.org Tue May 14 17:20:44 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:44 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove leftovers. Message-ID: <20130514152044.849C91C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64081:4abd157c79c1 Date: 2013-05-14 16:39 +0200 http://bitbucket.org/pypy/pypy/changeset/4abd157c79c1/ Log: Remove leftovers. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1143,16 +1143,6 @@ -dict_keys = SMM('keys', 1, - doc="") -dict_values = SMM('values', 1, - doc="") -dict_has_key = SMM('has_key', 2, - doc='') -dict_clear = SMM('clear', 1, - doc='') -dict_get = SMM('get', 3, defaults=(None,), - doc='') dict_pop = SMM('pop', 2, varargs_w=True, doc='D.pop(k[,d]) -> v, remove specified key and return' ' the corresponding value\nIf key is not found, d is' From noreply at buildbot.pypy.org Tue May 14 17:20:45 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:45 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.pop{,item} SMMs. Message-ID: <20130514152045.C1B5C1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64082:a8e9fe27fe7c Date: 2013-05-14 16:59 +0200 http://bitbucket.org/pypy/pypy/changeset/a8e9fe27fe7c/ Log: Remove dict.pop{,item} SMMs. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -169,11 +169,36 @@ else: return w_default -# def descr_pop(self, space): -# """""" + @gateway.unwrap_spec(defaults_w='args_w') + def descr_pop(self, space, w_key, defaults_w): + """D.pop(k[,d]) -> v, remove specified key and return the + corresponding value\nIf key is not found, d is returned if given, + otherwise KeyError is raised + """ + len_defaults = len(defaults_w) + if len_defaults > 1: + raise operationerrfmt(space.w_TypeError, + "pop expected at most 2 arguments, got %d", + 1 + len_defaults) + w_item = self.getitem(w_key) + if w_item is None: + if len_defaults > 0: + return defaults_w[0] + else: + space.raise_key_error(w_key) + else: + self.delitem(w_key) + return w_item -# def descr_popitem(self, space): -# """""" + def descr_popitem(self, space): + """D.popitem() -> (k, v), remove and return some (key, value) pair as + a\n2-tuple; but raise KeyError if D is empty""" + try: + w_key, w_value = self.popitem() + except KeyError: + raise OperationError(space.w_KeyError, + space.wrap("popitem(): dictionary is empty")) + return space.newtuple([w_key, w_value]) # def descr_setdefault(self, space): # """""" @@ -973,30 +998,6 @@ def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): return w_dict.setdefault(w_key, w_default) -def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w): - len_defaults = len(defaults_w) - if len_defaults > 1: - raise operationerrfmt(space.w_TypeError, - "pop expected at most 2 arguments, got %d", - 1 + len_defaults) - w_item = w_dict.getitem(w_key) - if w_item is None: - if len_defaults > 0: - return defaults_w[0] - else: - space.raise_key_error(w_key) - else: - w_dict.delitem(w_key) - return w_item - -def dict_popitem__DictMulti(space, w_dict): - try: - w_key, w_value = w_dict.popitem() - except KeyError: - raise OperationError(space.w_KeyError, - space.wrap("popitem(): dictionary is empty")) - return space.newtuple([w_key, w_value]) - # ____________________________________________________________ # Iteration @@ -1143,14 +1144,6 @@ -dict_pop = SMM('pop', 2, varargs_w=True, - doc='D.pop(k[,d]) -> v, remove specified key and return' - ' the corresponding value\nIf key is not found, d is' - ' returned if given, otherwise KeyError is raised') -dict_popitem = SMM('popitem', 1, - doc='D.popitem() -> (k, v), remove and return some (key,' - ' value) pair as a\n2-tuple; but raise KeyError if D' - ' is empty') dict_setdefault = SMM('setdefault', 3, defaults=(None,), doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' ' if k not in D') @@ -1257,8 +1250,8 @@ has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), clear = gateway.interp2app(W_DictMultiObject.descr_clear), get = gateway.interp2app(W_DictMultiObject.descr_get), - #pop = gateway.interp2app(W_DictMultiObject.descr_pop), - #popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), + pop = gateway.interp2app(W_DictMultiObject.descr_pop), + popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), #setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), #update = gateway.interp2app(W_DictMultiObject.descr_update), #reversed = gateway.interp2app(W_DictMultiObject.descr_reversed), From noreply at buildbot.pypy.org Tue May 14 17:20:47 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:47 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.setdefault SMM. Message-ID: <20130514152047.0E4CD1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64083:41bfd843576c Date: 2013-05-14 17:03 +0200 http://bitbucket.org/pypy/pypy/changeset/41bfd843576c/ Log: Remove dict.setdefault SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -200,8 +200,10 @@ space.wrap("popitem(): dictionary is empty")) return space.newtuple([w_key, w_value]) -# def descr_setdefault(self, space): -# """""" + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_setdefault(self, space, w_key, w_default): + """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" + return self.setdefault(w_key, w_default) # def descr_update(self, space): # """""" @@ -995,9 +997,6 @@ w_res = space.lt(w_leftval, w_rightval) return w_res -def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - return w_dict.setdefault(w_key, w_default) - # ____________________________________________________________ # Iteration @@ -1252,7 +1251,7 @@ get = gateway.interp2app(W_DictMultiObject.descr_get), pop = gateway.interp2app(W_DictMultiObject.descr_pop), popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), - #setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), + setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), #update = gateway.interp2app(W_DictMultiObject.descr_update), #reversed = gateway.interp2app(W_DictMultiObject.descr_reversed), ) From noreply at buildbot.pypy.org Tue May 14 17:20:48 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:48 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: oops Message-ID: <20130514152048.4E6561C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64084:f1b72c5959f3 Date: 2013-05-14 17:03 +0200 http://bitbucket.org/pypy/pypy/changeset/f1b72c5959f3/ Log: oops diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1143,9 +1143,6 @@ -dict_setdefault = SMM('setdefault', 3, defaults=(None,), - doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' - ' if k not in D') dict_update = SMM('update', 1, general__args__=True, doc='D.update(E, **F) -> None. Update D from E and F:' ' for k in E: D[k] = E[k]\n(if E has keys else: for' From noreply at buildbot.pypy.org Tue May 14 17:20:49 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:49 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.update SMM. Message-ID: <20130514152049.76A7B1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64085:ada1228f9414 Date: 2013-05-14 17:09 +0200 http://bitbucket.org/pypy/pypy/changeset/ada1228f9414/ Log: Remove dict.update SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -205,8 +205,11 @@ """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" return self.setdefault(w_key, w_default) -# def descr_update(self, space): -# """""" + def descr_update(self, space, __args__): + """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] + = E[k]\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in + F: D[k] = F[k]""" + init_or_update(space, self, __args__, 'dict.update') # def descr_reversed(self, space): # """""" @@ -904,9 +907,6 @@ def init__DictMulti(space, w_dict, __args__): init_or_update(space, w_dict, __args__, 'dict') -def dict_update__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict.update') - def getitem__DictMulti_ANY(space, w_dict, w_key): w_value = w_dict.getitem(w_key) if w_value is not None: @@ -1143,11 +1143,6 @@ -dict_update = SMM('update', 1, general__args__=True, - doc='D.update(E, **F) -> None. Update D from E and F:' - ' for k in E: D[k] = E[k]\n(if E has keys else: for' - ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' - ' F[k]') dict_reversed = SMM('__reversed__', 1) def dict_reversed__ANY(space, w_dict): @@ -1249,7 +1244,7 @@ pop = gateway.interp2app(W_DictMultiObject.descr_pop), popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), - #update = gateway.interp2app(W_DictMultiObject.descr_update), + update = gateway.interp2app(W_DictMultiObject.descr_update), #reversed = gateway.interp2app(W_DictMultiObject.descr_reversed), ) W_DictMultiObject.typedef.registermethods(globals()) From noreply at buildbot.pypy.org Tue May 14 17:20:50 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:50 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.__reversed__ SMM. Message-ID: <20130514152050.9A83D1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64086:3b5cdc40455c Date: 2013-05-14 17:14 +0200 http://bitbucket.org/pypy/pypy/changeset/3b5cdc40455c/ Log: Remove dict.__reversed__ SMM. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -211,8 +211,8 @@ F: D[k] = F[k]""" init_or_update(space, self, __args__, 'dict.update') -# def descr_reversed(self, space): -# """""" + def descr_reversed(self, space): + raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) def _add_indirections(): @@ -1142,12 +1142,6 @@ # ____________________________________________________________ - -dict_reversed = SMM('__reversed__', 1) - -def dict_reversed__ANY(space, w_dict): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - register_all(vars(), globals()) def descr_fromkeys(space, w_type, w_keys, w_fill=None): @@ -1245,7 +1239,7 @@ popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), update = gateway.interp2app(W_DictMultiObject.descr_update), - #reversed = gateway.interp2app(W_DictMultiObject.descr_reversed), + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), ) W_DictMultiObject.typedef.registermethods(globals()) dict_typedef = W_DictMultiObject.typedef From noreply at buildbot.pypy.org Tue May 14 17:20:51 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 17:20:51 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove unused imports. Message-ID: <20130514152051.B38EA1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64087:0cc10be8dbc8 Date: 2013-05-14 17:18 +0200 http://bitbucket.org/pypy/pypy/changeset/0cc10be8dbc8/ Log: Remove unused imports. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,8 +1,7 @@ -import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM +from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef from pypy.interpreter import gateway from pypy.interpreter.error import OperationError, operationerrfmt From noreply at buildbot.pypy.org Tue May 14 18:13:58 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Tue, 14 May 2013 18:13:58 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Fix test Message-ID: <20130514161358.4D88D1C1494@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64088:9e3624021257 Date: 2013-05-14 18:13 +0200 http://bitbucket.org/pypy/pypy/changeset/9e3624021257/ Log: Fix test diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2705,8 +2705,8 @@ d = dtype([("x", "int", 3), ("y", "float", 5)]) a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5])], dtype=d) - assert a[0]["x"] == [1, 2, 3].all() - assert a[1]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5].all() + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[1]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() class AppTestPyPy(BaseNumpyAppTest): From noreply at buildbot.pypy.org Tue May 14 21:24:19 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:19 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Move __reversed__ up. Message-ID: <20130514192419.DF3081C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64089:2262aa5ad631 Date: 2013-05-14 17:50 +0200 http://bitbucket.org/pypy/pypy/changeset/2262aa5ad631/ Log: Move __reversed__ up. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -108,6 +108,9 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + def descr_reversed(self, space): + raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + def descr_copy(self, space): """D.copy() -> a shallow copy of D""" w_new = W_DictMultiObject.allocate_and_init_instance(space) @@ -210,9 +213,6 @@ F: D[k] = F[k]""" init_or_update(space, self, __args__, 'dict.update') - def descr_reversed(self, space): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -1220,6 +1220,7 @@ __new__ = gateway.interp2app(descr__new__), __hash__ = None, __repr__ = gateway.interp2app(descr_repr), + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), copy = gateway.interp2app(W_DictMultiObject.descr_copy), items = gateway.interp2app(W_DictMultiObject.descr_items), @@ -1238,7 +1239,6 @@ popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), update = gateway.interp2app(W_DictMultiObject.descr_update), - __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), ) W_DictMultiObject.typedef.registermethods(globals()) dict_typedef = W_DictMultiObject.typedef From noreply at buildbot.pypy.org Tue May 14 21:24:21 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:21 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.__eq__ multi-method. Message-ID: <20130514192421.32B131C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64090:f82799a81e9d Date: 2013-05-14 18:51 +0200 http://bitbucket.org/pypy/pypy/changeset/f82799a81e9d/ Log: Remove dict.__eq__ multi-method. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -108,6 +108,28 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + def descr_eq(self, space, w_other): + if space.is_w(self, w_other): + return space.w_True + + if self.length() != w_other.length(): + return space.w_False + iteratorimplementation = self.iteritems() + while 1: + w_key, w_val = iteratorimplementation.next_item() + if w_key is None: + break + w_rightval = w_other.getitem(w_key) + if w_rightval is None: + return space.w_False + if not space.eq_w(w_val, w_rightval): + return space.w_False + return space.w_True + + def descr_ne(self, space, w_other): + # XXX automatize this + return space.not_(self.descr_eq(space, w_other)) + def descr_reversed(self, space): raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) @@ -935,24 +957,6 @@ def iter__DictMulti(space, w_dict): return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) -def eq__DictMulti_DictMulti(space, w_left, w_right): - if space.is_w(w_left, w_right): - return space.w_True - - if w_left.length() != w_right.length(): - return space.w_False - iteratorimplementation = w_left.iteritems() - while 1: - w_key, w_val = iteratorimplementation.next_item() - if w_key is None: - break - w_rightval = w_right.getitem(w_key) - if w_rightval is None: - return space.w_False - if not space.eq_w(w_val, w_rightval): - return space.w_False - return space.w_True - def characterize(space, w_a, w_b): """ (similar to CPython) returns the smallest key in acontent for which b's value is different or absent and this value """ @@ -1220,6 +1224,10 @@ __new__ = gateway.interp2app(descr__new__), __hash__ = None, __repr__ = gateway.interp2app(descr_repr), + + __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), + __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), copy = gateway.interp2app(W_DictMultiObject.descr_copy), From noreply at buildbot.pypy.org Tue May 14 21:24:22 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:22 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict.__lt__ multi-method. Message-ID: <20130514192422.711681C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64091:9e0df1084b99 Date: 2013-05-14 19:02 +0200 http://bitbucket.org/pypy/pypy/changeset/9e0df1084b99/ Log: Remove dict.__lt__ multi-method. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -130,6 +130,28 @@ # XXX automatize this return space.not_(self.descr_eq(space, w_other)) + def descr_lt(self, space, w_other): + # Different sizes, no problem + if self.length() < w_other.length(): + return space.w_True + if self.length() > w_other.length(): + return space.w_False + + # Same size + w_leftdiff, w_leftval = characterize(space, self, w_other) + if w_leftdiff is None: + return space.w_False + w_rightdiff, w_rightval = characterize(space, w_other, self) + if w_rightdiff is None: + # w_leftdiff is not None, w_rightdiff is None + return space.w_True + w_res = space.lt(w_leftdiff, w_rightdiff) + if (not space.is_true(w_res) and + space.eq_w(w_leftdiff, w_rightdiff) and + w_rightval is not None): + w_res = space.lt(w_leftval, w_rightval) + return w_res + def descr_reversed(self, space): raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) @@ -978,28 +1000,6 @@ w_smallest_diff_a_key = w_key return w_smallest_diff_a_key, w_its_value -def lt__DictMulti_DictMulti(space, w_left, w_right): - # Different sizes, no problem - if w_left.length() < w_right.length(): - return space.w_True - if w_left.length() > w_right.length(): - return space.w_False - - # Same size - w_leftdiff, w_leftval = characterize(space, w_left, w_right) - if w_leftdiff is None: - return space.w_False - w_rightdiff, w_rightval = characterize(space, w_right, w_left) - if w_rightdiff is None: - # w_leftdiff is not None, w_rightdiff is None - return space.w_True - w_res = space.lt(w_leftdiff, w_rightdiff) - if (not space.is_true(w_res) and - space.eq_w(w_leftdiff, w_rightdiff) and - w_rightval is not None): - w_res = space.lt(w_leftval, w_rightval) - return w_res - # ____________________________________________________________ # Iteration @@ -1227,6 +1227,8 @@ __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), + __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), + # XXX other comparison methods? __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), From noreply at buildbot.pypy.org Tue May 14 21:24:23 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:23 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove more dict multi-methods. Message-ID: <20130514192423.B9E761C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64092:e9d52885b4b4 Date: 2013-05-14 20:06 +0200 http://bitbucket.org/pypy/pypy/changeset/e9d52885b4b4/ Log: Remove more dict multi-methods. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -108,6 +108,9 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + def descr_init(self, space, __args__): + init_or_update(space, self, __args__, 'dict') + def descr_eq(self, space, w_other): if space.is_w(self, w_other): return space.w_True @@ -152,6 +155,35 @@ w_res = space.lt(w_leftval, w_rightval) return w_res + def descr_len(self, space): + return space.wrap(self.length()) + + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_contains(self, space, w_key): + return space.newbool(self.getitem(w_key) is not None) + + def descr_getitem(self, space, w_key): + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + + w_missing_item = self.missing_method(space, w_key) + if w_missing_item is not None: + return w_missing_item + + space.raise_key_error(w_key) + + def descr_setitem(self, space, w_newkey, w_newvalue): + self.setitem(w_newkey, w_newvalue) + + def descr_delitem(self, space, w_key): + try: + self.delitem(w_key) + except KeyError: + space.raise_key_error(w_key) + def descr_reversed(self, space): raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) @@ -947,38 +979,6 @@ if space.is_true(w_kwds): update1(space, w_dict, w_kwds) -def init__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict') - -def getitem__DictMulti_ANY(space, w_dict, w_key): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - - w_missing_item = w_dict.missing_method(space, w_key) - if w_missing_item is not None: - return w_missing_item - - space.raise_key_error(w_key) - -def setitem__DictMulti_ANY_ANY(space, w_dict, w_newkey, w_newvalue): - w_dict.setitem(w_newkey, w_newvalue) - -def delitem__DictMulti_ANY(space, w_dict, w_key): - try: - w_dict.delitem(w_key) - except KeyError: - space.raise_key_error(w_key) - -def len__DictMulti(space, w_dict): - return space.wrap(w_dict.length()) - -def contains__DictMulti_ANY(space, w_dict, w_key): - return space.newbool(w_dict.getitem(w_key) is not None) - -def iter__DictMulti(space, w_dict): - return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) - def characterize(space, w_a, w_b): """ (similar to CPython) returns the smallest key in acontent for which b's value is different or absent and this value """ @@ -1224,12 +1224,21 @@ __new__ = gateway.interp2app(descr__new__), __hash__ = None, __repr__ = gateway.interp2app(descr_repr), + __init__ = gateway.interp2app(W_DictMultiObject.descr_init), __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), # XXX other comparison methods? + __len__ = gateway.interp2app(W_DictMultiObject.descr_len), + __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), + __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + + __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), copy = gateway.interp2app(W_DictMultiObject.descr_copy), diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -2,8 +2,7 @@ import py from pypy.objspace.std.dictmultiobject import (W_DictMultiObject, - setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, StringDictStrategy, - ObjectDictStrategy) + StringDictStrategy, ObjectDictStrategy) class TestW_DictObject(object): @@ -971,10 +970,10 @@ pydict = {} for i in range(N): x = randint(-N, N) - setitem__DictMulti_ANY_ANY(self.space, d, x, i) + d.descr_setitem(self.space, x, i) pydict[x] = i for key, value in pydict.iteritems(): - assert value == getitem__DictMulti_ANY(self.space, d, key) + assert value == d.descr_getitem(self.space, key) class BaseTestRDictImplementation: From noreply at buildbot.pypy.org Tue May 14 21:24:25 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:25 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Rename descr__iter__ to descr_iter. Message-ID: <20130514192425.0F1E51C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64093:19e0d3a13d91 Date: 2013-05-14 20:08 +0200 http://bitbucket.org/pypy/pypy/changeset/19e0d3a13d91/ Log: Rename descr__iter__ to descr_iter. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1065,17 +1065,17 @@ w_self.w_dict = w_dict class W_DictViewItemsObject(W_DictViewObject): - def descr__iter__(self, space): + def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) registerimplementation(W_DictViewItemsObject) class W_DictViewKeysObject(W_DictViewObject): - def descr__iter__(self, space): + def descr_iter(self, space): return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) registerimplementation(W_DictViewKeysObject) class W_DictViewValuesObject(W_DictViewObject): - def descr__iter__(self, space): + def descr_iter(self, space): return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) registerimplementation(W_DictViewValuesObject) @@ -1335,15 +1335,15 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", - __iter__ = gateway.interp2app(W_DictViewItemsObject.descr__iter__) + __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter) ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", - __iter__ = gateway.interp2app(W_DictViewKeysObject.descr__iter__) + __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter) ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", - __iter__ = gateway.interp2app(W_DictViewValuesObject.descr__iter__) + __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter) ) From noreply at buildbot.pypy.org Tue May 14 21:24:26 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:26 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove unnecessary imports. Message-ID: <20130514192426.477861C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64094:823ae1c8fb82 Date: 2013-05-14 20:10 +0200 http://bitbucket.org/pypy/pypy/changeset/823ae1c8fb82/ Log: Remove unnecessary imports. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1148,7 +1148,6 @@ register_all(vars(), globals()) def descr_fromkeys(space, w_type, w_keys, w_fill=None): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject if w_fill is None: w_fill = space.w_None if space.is_w(w_type, space.w_dict): @@ -1205,7 +1204,6 @@ # ____________________________________________________________ def descr__new__(space, w_dicttype, __args__): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) return w_obj @@ -1265,7 +1263,6 @@ # ____________________________________________________________ def descr_dictiter__length_hint__(space, w_self): - from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject assert isinstance(w_self, W_BaseDictMultiIterObject) return space.wrap(w_self.iteratorimplementation.length()) From noreply at buildbot.pypy.org Tue May 14 21:24:27 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:27 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Make descr_dictiter__length_hint__ and descr_dictiter__reduce__ methods. Message-ID: <20130514192427.893C21C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64095:e9e683af479a Date: 2013-05-14 20:26 +0200 http://bitbucket.org/pypy/pypy/changeset/e9e683af479a/ Log: Make descr_dictiter__length_hint__ and descr_dictiter__reduce__ methods. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1014,6 +1014,61 @@ w_self.space = space w_self.iteratorimplementation = iteratorimplementation + def descr_length_hint(self, space): + return space.wrap(self.iteratorimplementation.length()) + + def descr_reduce(self, space): + """ + This is a slightly special case of pickling. + Since iteration over a dict is a bit hairy, + we do the following: + - create a clone of the dict iterator + - run it to the original position + - collect all remaining elements into a list + At unpickling time, we just use that list + and create an iterator on it. + This is of course not the standard way. + + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('dictiter_surrogate_new') + w_typeobj = space.gettypeobject(dictiter_typedef) + + raise OperationError( + space.w_TypeError, + space.wrap("can't pickle dictionary-keyiterator objects")) + # XXXXXX get that working again + + # we cannot call __init__ since we don't have the original dict + if isinstance(self, W_DictIter_Keys): + w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) + elif isinstance(self, W_DictIter_Values): + w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) + elif isinstance(self, W_DictIter_Items): + w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + else: + msg = "unsupported dictiter type '%s' during pickling" % (self,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_clone.space = space + w_clone.content = self.content + w_clone.len = self.len + w_clone.pos = 0 + w_clone.setup_iterator() + # spool until we have the same pos + while w_clone.pos < self.pos: + w_obj = w_clone.next_entry() + w_clone.pos += 1 + stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] + w_res = space.newlist(stuff) + tup = [ + w_res + ] + w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + return w_ret + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): pass @@ -1262,69 +1317,10 @@ # ____________________________________________________________ -def descr_dictiter__length_hint__(space, w_self): - assert isinstance(w_self, W_BaseDictMultiIterObject) - return space.wrap(w_self.iteratorimplementation.length()) - - -def descr_dictiter__reduce__(w_self, space): - """ - This is a slightly special case of pickling. - Since iteration over a dict is a bit hairy, - we do the following: - - create a clone of the dict iterator - - run it to the original position - - collect all remaining elements into a list - At unpickling time, we just use that list - and create an iterator on it. - This is of course not the standard way. - - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) - - raise OperationError( - space.w_TypeError, - space.wrap("can't pickle dictionary-keyiterator objects")) - # XXXXXX get that working again - - # we cannot call __init__ since we don't have the original dict - if isinstance(w_self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(w_self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(w_self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) - else: - msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_clone.space = space - w_clone.content = w_self.content - w_clone.len = w_self.len - w_clone.pos = 0 - w_clone.setup_iterator() - # spool until we have the same pos - while w_clone.pos < w_self.pos: - w_obj = w_clone.next_entry() - w_clone.pos += 1 - stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] - w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) - return w_ret - -# ____________________________________________________________ - W_BaseDictMultiIterObject.typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), - __reduce__ = gateway.interp2app(descr_dictiter__reduce__), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_reduce), ) # ____________________________________________________________ From noreply at buildbot.pypy.org Tue May 14 21:24:28 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:28 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Move typedefs up. Message-ID: <20130514192428.C8F2F1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64096:8e806b411638 Date: 2013-05-14 20:29 +0200 http://bitbucket.org/pypy/pypy/changeset/8e806b411638/ Log: Move typedefs up. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -309,6 +309,120 @@ _add_indirections() +def descr_fromkeys(space, w_type, w_keys, w_fill=None): + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + + +app = gateway.applevel(''' + def dictrepr(currently_in_repr, d): + if len(d) == 0: + return "{}" + dict_id = id(d) + if dict_id in currently_in_repr: + return '{...}' + currently_in_repr[dict_id] = 1 + try: + items = [] + # XXX for now, we cannot use iteritems() at app-level because + # we want a reasonable result instead of a RuntimeError + # even if the dict is mutated by the repr() in the loop. + for k, v in dict.items(d): + items.append(repr(k) + ": " + repr(v)) + return "{" + ', '.join(items) + "}" + finally: + try: + del currently_in_repr[dict_id] + except: + pass +''', filename=__file__) + +dictrepr = app.interphook("dictrepr") + + +def descr_repr(space, w_dict): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, w_dict) + + +# ____________________________________________________________ + +def descr__new__(space, w_dicttype, __args__): + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + +# ____________________________________________________________ + +W_DictMultiObject.typedef = StdTypeDef("dict", + __doc__ = '''dict() -> new empty dictionary. +dict(mapping) -> new dictionary initialized from a mapping object\'s + (key, value) pairs. +dict(seq) -> new dictionary initialized as if via: + d = {} + for k, v in seq: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)''', + __new__ = gateway.interp2app(descr__new__), + __hash__ = None, + __repr__ = gateway.interp2app(descr_repr), + __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + + __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), + __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), + __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), + # XXX other comparison methods? + + __len__ = gateway.interp2app(W_DictMultiObject.descr_len), + __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), + __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + + __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), + fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), + copy = gateway.interp2app(W_DictMultiObject.descr_copy), + items = gateway.interp2app(W_DictMultiObject.descr_items), + keys = gateway.interp2app(W_DictMultiObject.descr_keys), + values = gateway.interp2app(W_DictMultiObject.descr_values), + iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), + has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), + clear = gateway.interp2app(W_DictMultiObject.descr_clear), + get = gateway.interp2app(W_DictMultiObject.descr_get), + pop = gateway.interp2app(W_DictMultiObject.descr_pop), + popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), + setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), + update = gateway.interp2app(W_DictMultiObject.descr_update), + ) +W_DictMultiObject.typedef.registermethods(globals()) +dict_typedef = W_DictMultiObject.typedef + + class DictStrategy(object): def __init__(self, space): @@ -1069,6 +1183,12 @@ w_ret = space.newtuple([new_inst, space.newtuple(tup)]) return w_ret + +W_BaseDictMultiIterObject.typedef = StdTypeDef("dictionaryiterator", + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_reduce), + ) + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): pass @@ -1134,6 +1254,21 @@ return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) registerimplementation(W_DictViewValuesObject) +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter) + ) + +W_DictViewKeysObject.typedef = StdTypeDef( + "dict_keys", + __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter) + ) + +W_DictViewValuesObject.typedef = StdTypeDef( + "dict_values", + __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter) + ) + def len__DictViewKeys(space, w_dictview): return space.len(w_dictview.w_dict) len__DictViewItems = len__DictViewValues = len__DictViewKeys @@ -1201,142 +1336,3 @@ register_all(vars(), globals()) - -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - - -app = gateway.applevel(''' - def dictrepr(currently_in_repr, d): - if len(d) == 0: - return "{}" - dict_id = id(d) - if dict_id in currently_in_repr: - return '{...}' - currently_in_repr[dict_id] = 1 - try: - items = [] - # XXX for now, we cannot use iteritems() at app-level because - # we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in dict.items(d): - items.append(repr(k) + ": " + repr(v)) - return "{" + ', '.join(items) + "}" - finally: - try: - del currently_in_repr[dict_id] - except: - pass -''', filename=__file__) - -dictrepr = app.interphook("dictrepr") - - -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - -W_DictMultiObject.typedef = StdTypeDef("dict", - __doc__ = '''dict() -> new empty dictionary. -dict(mapping) -> new dictionary initialized from a mapping object\'s - (key, value) pairs. -dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v -dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), - __init__ = gateway.interp2app(W_DictMultiObject.descr_init), - - __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), - __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), - __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), - # XXX other comparison methods? - - __len__ = gateway.interp2app(W_DictMultiObject.descr_len), - __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), - __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), - - __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), - __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), - __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), - - __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), - copy = gateway.interp2app(W_DictMultiObject.descr_copy), - items = gateway.interp2app(W_DictMultiObject.descr_items), - keys = gateway.interp2app(W_DictMultiObject.descr_keys), - values = gateway.interp2app(W_DictMultiObject.descr_values), - iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), - iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), - itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), - viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), - viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), - viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), - has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), - clear = gateway.interp2app(W_DictMultiObject.descr_clear), - get = gateway.interp2app(W_DictMultiObject.descr_get), - pop = gateway.interp2app(W_DictMultiObject.descr_pop), - popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), - setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), - update = gateway.interp2app(W_DictMultiObject.descr_update), - ) -W_DictMultiObject.typedef.registermethods(globals()) -dict_typedef = W_DictMultiObject.typedef - -# ____________________________________________________________ - - -W_BaseDictMultiIterObject.typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint), - __reduce__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_reduce), - ) - -# ____________________________________________________________ -# Dict views - -W_DictViewItemsObject.typedef = StdTypeDef( - "dict_items", - __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter) - ) - -W_DictViewKeysObject.typedef = StdTypeDef( - "dict_keys", - __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter) - ) - -W_DictViewValuesObject.typedef = StdTypeDef( - "dict_values", - __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter) - ) From noreply at buildbot.pypy.org Tue May 14 21:24:30 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:30 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict iterator multi-methods. Message-ID: <20130514192430.31D1C1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64097:1c6cfbb89ce8 Date: 2013-05-14 20:52 +0200 http://bitbucket.org/pypy/pypy/changeset/1c6cfbb89ce8/ Log: Remove dict iterator multi-methods. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1128,6 +1128,9 @@ w_self.space = space w_self.iteratorimplementation = iteratorimplementation + def descr_iter(self, space): + return self + def descr_length_hint(self, space): return space.wrap(self.iteratorimplementation.length()) @@ -1190,47 +1193,50 @@ ) class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key = iteratorimplementation.next_key() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterValuesObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_value = iteratorimplementation.next_value() + if w_value is not None: + return w_value + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterItemsObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key, w_value = iteratorimplementation.next_item() + if w_key is not None: + return space.newtuple([w_key, w_value]) + raise OperationError(space.w_StopIteration, space.w_None) registerimplementation(W_DictMultiIterKeysObject) registerimplementation(W_DictMultiIterValuesObject) registerimplementation(W_DictMultiIterItemsObject) -def iter__DictMultiIterKeysObject(space, w_dictiter): - return w_dictiter +W_DictMultiIterItemsObject.typedef = StdTypeDef( + "dict_iteritems", + __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next) + ) -def next__DictMultiIterKeysObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key = iteratorimplementation.next_key() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) +W_DictMultiIterKeysObject.typedef = StdTypeDef( + "dict_iterkeys", + __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next) + ) -def iter__DictMultiIterValuesObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterValuesObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_value = iteratorimplementation.next_value() - if w_value is not None: - return w_value - raise OperationError(space.w_StopIteration, space.w_None) - -def iter__DictMultiIterItemsObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterItemsObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key, w_value = iteratorimplementation.next_item() - if w_key is not None: - return space.newtuple([w_key, w_value]) - raise OperationError(space.w_StopIteration, space.w_None) +W_DictMultiIterValuesObject.typedef = StdTypeDef( + "dict_itervalues", + __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next) + ) # ____________________________________________________________ # Views From noreply at buildbot.pypy.org Tue May 14 21:24:31 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:31 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict view length multi-methods. Message-ID: <20130514192431.530D61C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64098:5c2911f4637a Date: 2013-05-14 20:56 +0200 http://bitbucket.org/pypy/pypy/changeset/5c2911f4637a/ Log: Remove dict view length multi-methods. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1245,6 +1245,9 @@ def __init__(w_self, space, w_dict): w_self.w_dict = w_dict + def descr_len(self, space): + return space.len(self.w_dict) + class W_DictViewItemsObject(W_DictViewObject): def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) @@ -1262,23 +1265,22 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", + __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter) ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", + __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter) ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", + __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter) ) -def len__DictViewKeys(space, w_dictview): - return space.len(w_dictview.w_dict) -len__DictViewItems = len__DictViewValues = len__DictViewKeys - def all_contained_in(space, w_dictview, w_otherview): w_iter = space.iter(w_dictview) From noreply at buildbot.pypy.org Tue May 14 21:24:32 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:32 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict view repr multi-methods. Message-ID: <20130514192432.9695E1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64099:3d3b181723ff Date: 2013-05-14 20:59 +0200 http://bitbucket.org/pypy/pypy/changeset/3d3b181723ff/ Log: Remove dict view repr multi-methods. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1245,6 +1245,12 @@ def __init__(w_self, space, w_dict): w_self.w_dict = w_dict + def descr_repr(self, space): + w_seq = space.call_function(space.w_list, self) + w_repr = space.repr(w_seq) + return space.wrap("%s(%s)" % (space.type(self).getname(space), + space.str_w(w_repr))) + def descr_len(self, space): return space.len(self.w_dict) @@ -1265,18 +1271,21 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", + __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter) ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", + __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter) ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", + __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter) ) @@ -1308,14 +1317,6 @@ eq__DictViewItems_settypedef = eq__DictViewItems_DictViewItems eq__DictViewItems_frozensettypedef = eq__DictViewItems_DictViewItems -def repr__DictViewKeys(space, w_dictview): - w_seq = space.call_function(space.w_list, w_dictview) - w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), - space.str_w(w_repr))) -repr__DictViewItems = repr__DictViewKeys -repr__DictViewValues = repr__DictViewKeys - def and__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): w_set = space.call_function(space.w_set, w_dictview) space.call_method(w_set, "intersection_update", w_otherview) From noreply at buildbot.pypy.org Tue May 14 21:24:33 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:33 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict view and/or/xor multi-methods. Message-ID: <20130514192433.C248D1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64100:a643941a8479 Date: 2013-05-14 21:07 +0200 http://bitbucket.org/pypy/pypy/changeset/a643941a8479/ Log: Remove dict view and/or/xor multi-methods. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1254,6 +1254,21 @@ def descr_len(self, space): return space.len(self.w_dict) + def descr_and(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "intersection_update", w_otherview) + return w_set + + def descr_or(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "update", w_otherview) + return w_set + + def descr_xor(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "symmetric_difference_update", w_otherview) + return w_set + class W_DictViewItemsObject(W_DictViewObject): def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) @@ -1273,21 +1288,30 @@ "dict_items", __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter) + __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), + __or__ = gateway.interp2app(W_DictViewItemsObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewItemsObject.descr_xor) ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter) + __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), + __or__ = gateway.interp2app(W_DictViewKeysObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewKeysObject.descr_xor) ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter) + __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), + __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) ) def all_contained_in(space, w_dictview, w_otherview): @@ -1317,30 +1341,6 @@ eq__DictViewItems_settypedef = eq__DictViewItems_DictViewItems eq__DictViewItems_frozensettypedef = eq__DictViewItems_DictViewItems -def and__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set -and__DictViewKeys_settypedef = and__DictViewKeys_DictViewKeys -and__DictViewItems_DictViewItems = and__DictViewKeys_DictViewKeys -and__DictViewItems_settypedef = and__DictViewKeys_DictViewKeys - -def or__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "update", w_otherview) - return w_set -or__DictViewKeys_settypedef = or__DictViewKeys_DictViewKeys -or__DictViewItems_DictViewItems = or__DictViewKeys_DictViewKeys -or__DictViewItems_settypedef = or__DictViewKeys_DictViewKeys - -def xor__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set -xor__DictViewKeys_settypedef = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_DictViewItems = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_settypedef = xor__DictViewKeys_DictViewKeys - # ____________________________________________________________ From noreply at buildbot.pypy.org Tue May 14 21:24:34 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 21:24:34 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict view eq multi-methods. All dict multi-methods removedhg diff Message-ID: <20130514192434.F185D1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64101:07dc888e282f Date: 2013-05-14 21:14 +0200 http://bitbucket.org/pypy/pypy/changeset/07dc888e282f/ Log: Remove dict view eq multi-methods. All dict multi-methods removedhg diff diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1251,6 +1251,23 @@ return space.wrap("%s(%s)" % (space.type(self).getname(space), space.str_w(w_repr))) + + def descr_eq(self, space, w_otherview): + if not space.eq_w(space.len(self), space.len(w_otherview)): + return space.w_False + + w_iter = space.iter(self) + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if not space.is_true(space.contains(w_otherview, w_item)): + return space.w_False + return space.w_True + def descr_len(self, space): return space.len(self.w_dict) @@ -1287,6 +1304,7 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewItemsObject.descr_eq), __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), @@ -1297,6 +1315,7 @@ W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewKeysObject.descr_eq), __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), @@ -1307,41 +1326,10 @@ W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewValuesObject.descr_eq), __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) ) - -def all_contained_in(space, w_dictview, w_otherview): - w_iter = space.iter(w_dictview) - - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - - return space.w_True - -def eq__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - if space.eq_w(space.len(w_dictview), space.len(w_otherview)): - return all_contained_in(space, w_dictview, w_otherview) - return space.w_False -eq__DictViewKeys_settypedef = eq__DictViewKeys_DictViewKeys -eq__DictViewKeys_frozensettypedef = eq__DictViewKeys_DictViewKeys - -eq__DictViewKeys_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_settypedef = eq__DictViewItems_DictViewItems -eq__DictViewItems_frozensettypedef = eq__DictViewItems_DictViewItems - -# ____________________________________________________________ - - -register_all(vars(), globals()) From noreply at buildbot.pypy.org Tue May 14 21:29:41 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 14 May 2013 21:29:41 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default, and adapt/kill the py3k SMM additions Message-ID: <20130514192941.255241C1510@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64102:e1281f255e98 Date: 2013-05-14 12:28 -0700 http://bitbucket.org/pypy/pypy/changeset/e1281f255e98/ Log: merge default, and adapt/kill the py3k SMM additions diff too long, truncating to 2000 out of 2139 lines diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -83,24 +83,40 @@ # should be used as sparsely as possible, just to register callbacks from rpython.rlib.entrypoint import entrypoint - from rpython.rtyper.lltypesystem import rffi + from rpython.rtyper.lltypesystem import rffi, lltype - @entrypoint('main', [rffi.CCHARP], c_name='pypy_setup_home') - def pypy_setup_home(ll_home): + w_pathsetter = space.appexec([], """(): + def f(path): + import sys + sys.path[:] = path + return f + """) + + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') + def pypy_setup_home(ll_home, verbose): from pypy.module.sys.initpath import pypy_find_stdlib if ll_home: home = rffi.charp2str(ll_home) else: home = pypydir - pypy_find_stdlib(space, home) + w_path = pypy_find_stdlib(space, home) + if space.is_none(w_path): + if verbose: + debug("Failed to find library based on pypy_find_stdlib") + return 1 space.startup() + space.call_function(w_pathsetter, w_path) # import site try: import_ = space.getattr(space.getbuiltinmodule('__builtin__'), space.wrap('__import__')) space.call_function(import_, space.wrap('site')) return 0 - except OperationError: + except OperationError, e: + if verbose: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py --- a/pypy/interpreter/test/test_targetpypy.py +++ b/pypy/interpreter/test/test_targetpypy.py @@ -24,5 +24,5 @@ # did not crash - the same globals pypy_setup_home = d['pypy_setup_home'] lls = rffi.str2charp(__file__) - pypy_setup_home(lls) + pypy_setup_home(lls, 1) lltype.free(lls, flavor='raw') diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -1,4 +1,3 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import unwrap_spec from rpython.rlib.objectmodel import we_are_translated @@ -63,7 +62,7 @@ func.getcode().hidden_applevel = True return w_func - at unwrap_spec(ObjSpace, W_Root, str) + at unwrap_spec(meth=str) def lookup_special(space, w_obj, meth): """Lookup up a special method on an object.""" w_descr = space.lookup(w_obj, meth) diff --git a/pypy/module/array/__init__.py b/pypy/module/array/__init__.py --- a/pypy/module/array/__init__.py +++ b/pypy/module/array/__init__.py @@ -1,12 +1,5 @@ from pypy.interpreter.mixedmodule import MixedModule -from pypy.module.array.interp_array import types -from pypy.objspace.std.model import registerimplementation - -for mytype in types.values(): - registerimplementation(mytype.w_class) - - class Module(MixedModule): interpleveldefs = { 'array': 'interp_array.W_ArrayBase', 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 @@ -2,17 +2,13 @@ from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, unwrap_spec +from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef from pypy.interpreter.baseobjspace import W_Root -from pypy.objspace.std.model import W_Object -from pypy.objspace.std.multimethod import FailedToImplement -from pypy.objspace.std.stdtypedef import SMM, StdTypeDef -from pypy.objspace.std.register_all import register_all from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck, widen from rpython.rlib.unroll import unrolling_iterable -from rpython.rlib.objectmodel import specialize, keepalive_until_here +from rpython.rlib.objectmodel import keepalive_until_here from rpython.rtyper.lltypesystem import lltype, rffi @@ -42,9 +38,10 @@ if isinstance(w_initializer, W_ArrayBase): a.extend(w_initializer, True) else: - a.fromstring(space.bufferstr_w(w_initializer)) + a.descr_fromstring(space, + space.bufferstr_w(w_initializer)) elif space.type(w_initializer) is space.w_list: - a.fromlist(w_initializer) + a.descr_fromlist(space, w_initializer) else: a.extend(w_initializer, True) break @@ -55,33 +52,6 @@ return a -array_append = SMM('append', 2) -array_extend = SMM('extend', 2) - -array_count = SMM('count', 2) -array_index = SMM('index', 2) -array_reverse = SMM('reverse', 1) -array_remove = SMM('remove', 2) -array_pop = SMM('pop', 2, defaults=(-1,)) -array_insert = SMM('insert', 3) - -array_tolist = SMM('tolist', 1) -array_fromlist = SMM('fromlist', 2) -array_tostring = SMM('tostring', 1) -array_tobytes = SMM('tobytes', 1) -array_fromstring = SMM('fromstring', 2) -array_frombytes = SMM('frombytes', 2) -array_tounicode = SMM('tounicode', 1) -array_fromunicode = SMM('fromunicode', 2) -array_tofile = SMM('tofile', 2) -array_fromfile = SMM('fromfile', 3) - -array_buffer_info = SMM('buffer_info', 1) -array_reduce_ex = SMM('__reduce_ex__', 2) -array_copy = SMM('__copy__', 1) -array_byteswap = SMM('byteswap', 1) - - def descr_itemsize(space, self): return space.wrap(self.itemsize) @@ -89,28 +59,512 @@ def descr_typecode(space, self): return space.wrap(self.typecode) +arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') +EQ, NE, LT, LE, GT, GE = range(6) -class W_ArrayBase(W_Object): - @staticmethod - def register(typeorder): - typeorder[W_ArrayBase] = [] +def compare_arrays(space, arr1, arr2, comp_op, comp_func): + if (not isinstance(arr1, W_ArrayBase) or + not isinstance(arr2, W_ArrayBase)): + return space.w_NotImplemented + if comp_op == EQ and arr1.len != arr2.len: + return space.w_False + if comp_op == NE and arr1.len != arr2.len: + return space.w_True + lgt = min(arr1.len, arr2.len) + for i in range(lgt): + arr_eq_driver.jit_merge_point(comp_func=comp_func) + w_elem1 = arr1.w_getitem(space, i) + w_elem2 = arr2.w_getitem(space, i) + res = space.is_true(comp_func(w_elem1, w_elem2)) + if comp_op == EQ: + if not res: + return space.w_False + elif comp_op == NE: + if res: + return space.w_True + elif comp_op == LT or comp_op == GT: + if res: + return space.w_True + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_False + else: + if not res: + return space.w_False + elif not space.is_true(space.eq(w_elem1, w_elem2)): + return space.w_True + # we have some leftovers + if comp_op == EQ: + return space.w_True + elif comp_op == NE: + return space.w_False + if arr1.len == arr2.len: + if comp_op == LT or comp_op == GT: + return space.w_False + return space.w_True + if comp_op == LT or comp_op == LE: + if arr1.len < arr2.len: + return space.w_False + return space.w_True + if arr1.len > arr2.len: + return space.w_False + return space.w_True -W_ArrayBase.typedef = StdTypeDef( +UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, + hints={'nolength': True})) + +class W_ArrayBase(W_Root): + _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer + + def __init__(self, space): + self.space = space + self.len = 0 + self.allocated = 0 + + def descr_append(self, space, w_x): + """ append(x) + + Append new value x to the end of the array. + """ + raise NotImplementedError + + def descr_extend(self, space, w_x): + """ extend(array or iterable) + + Append items to the end of the array. + """ + self.extend(w_x) + + def descr_count(self, space, w_val): + """ count(x) + + Return number of occurrences of x in the array. + """ + raise NotImplementedError + + def descr_index(self, space, w_x): + """ index(x) + + Return index of first occurrence of x in the array. + """ + raise NotImplementedError + + def descr_reverse(self, space): + """ reverse() + + Reverse the order of the items in the array. + """ + raise NotImplementedError + + def descr_remove(self, space, w_val): + """ remove(x) + + Remove the first occurrence of x in the array. + """ + raise NotImplementedError + + @unwrap_spec(i=int) + def descr_pop(self, space, i=-1): + """ pop([i]) + + Return the i-th element and delete it from the array. i defaults to -1. + """ + raise NotImplementedError + + @unwrap_spec(idx=int) + def descr_insert(self, space, idx, w_val): + """ insert(i,x) + + Insert a new item x into the array before position i. + """ + raise NotImplementedError + + def descr_tolist(self, space): + """ tolist() -> list + + Convert array to an ordinary list with the same items. + """ + w_l = space.newlist([]) + for i in range(self.len): + w_l.append(self.w_getitem(space, i)) + return w_l + + def descr_fromlist(self, space, w_lst): + """ fromlist(list) + + Append items to array from list. + """ + if not space.isinstance_w(w_lst, space.w_list): + raise OperationError(space.w_TypeError, + space.wrap("arg must be list")) + s = self.len + try: + self.fromsequence(w_lst) + except OperationError: + self.setlen(s) + raise + + def descr_tostring(self, space): + """ tostring() -> bytes + + Convert the array to an array of machine values and return the + bytes representation. + + This method is deprecated. Use tobytes instead. + """ + msg = "tostring() is deprecated. Use tobytes() instead." + space.warn(space.wrap(msg), space.w_DeprecationWarning) + return self.descr_tobytes(space) + + def descr_tobytes(self, space): + """tobytes() -> bytes + + Convert the array to an array of machine values and return the + bytes representation. + """ + cbuf = self._charbuf_start() + s = rffi.charpsize2str(cbuf, self.len * self.itemsize) + self._charbuf_stop() + return self.space.wrapbytes(s) + + @unwrap_spec(s='bufferstr_or_u') + def descr_fromstring(self, space, s): + """fromstring(string) + + Appends items from the string, interpreting it as an array of + machine values, as if it had been read from a file using the + fromfile() method). + + This method is deprecated. Use frombytes instead. + """ + msg = "fromstring() is deprecated. Use frombytes() instead." + space.warn(space.wrap(msg), self.space.w_DeprecationWarning) + self.descr_frombytes(space, s) + + @unwrap_spec(s='bufferstr') + def descr_frombytes(self, space, s): + """frombytes(bytestring) + + Appends items from the string, interpreting it as an array of + machine values, as if it had been read from a file using the + fromfile() method). + """ + if len(s) % self.itemsize != 0: + msg = 'string length not a multiple of item size' + raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) + oldlen = self.len + new = len(s) / self.itemsize + self.setlen(oldlen + new) + cbuf = self._charbuf_start() + for i in range(len(s)): + cbuf[oldlen * self.itemsize + i] = s[i] + self._charbuf_stop() + + @unwrap_spec(n=int) + def descr_fromfile(self, space, w_f, n): + """ fromfile(f, n) + + Read n objects from the file object f and append them to the end of the + array. Also called as read. + """ + try: + size = ovfcheck(self.itemsize * n) + except OverflowError: + raise MemoryError + w_item = space.call_method(w_f, 'read', space.wrap(size)) + item = space.bytes_w(w_item) + if len(item) < size: + n = len(item) % self.itemsize + elems = max(0, len(item) - (len(item) % self.itemsize)) + if n != 0: + item = item[0:elems] + self.descr_frombytes(space, item) + msg = "not enough items in file" + raise OperationError(space.w_EOFError, space.wrap(msg)) + self.descr_fromstring(space, item) + + def descr_tofile(self, space, w_f): + """ tofile(f) + + Write all items (as machine values) to the file object f. Also called as + write. + """ + w_s = self.descr_tobytes(space) + space.call_method(w_f, 'write', w_s) + + def descr_fromunicode(self, space, w_ustr): + """ fromunicode(ustr) + + Extends this array with data from the unicode string ustr. + The array must be a type 'u' array; otherwise a ValueError + is raised. Use array.fromstring(ustr.decode(...)) to + append Unicode data to an array of some other type. + """ + # XXX the following probable bug is not emulated: + # CPython accepts a non-unicode string or a buffer, and then + # behaves just like fromstring(), except that it strangely truncate + # string arguments at multiples of the unicode byte size. + # Let's only accept unicode arguments for now. + if self.typecode == 'u': + self.fromsequence(w_ustr) + else: + msg = "fromunicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_tounicode(self, space): + """ tounicode() -> unicode + + Convert the array to a unicode string. The array must be + a type 'u' array; otherwise a ValueError is raised. Use + array.tostring().decode() to obtain a unicode string from + an array of some other type. + """ + if self.typecode == 'u': + buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned()) + return space.wrap(rffi.wcharpsize2unicode(buf, self.len)) + else: + msg = "tounicode() may only be called on type 'u' arrays" + raise OperationError(space.w_ValueError, space.wrap(msg)) + + def descr_buffer_info(self, space): + """ buffer_info() -> (address, length) + + Return a tuple (address, length) giving the current memory address and + the length in items of the buffer used to hold array's contents + The length should be multiplied by the itemsize attribute to calculate + the buffer length in bytes. + """ + w_ptr = space.wrap(self._buffer_as_unsigned()) + w_len = space.wrap(self.len) + return space.newtuple([w_ptr, w_len]) + + @unwrap_spec(protocol=int) + def descr_reduce_ex(self, space, protocol): + """Return state information for pickling.""" + try: + w_dict = space.getattr(self, space.wrap('__dict__')) + except OperationError: + w_dict = space.w_None + from pypy.module.array import reconstructor + mformat_code = reconstructor.typecode_to_mformat_code(self.typecode) + if protocol < 3 or mformat_code == reconstructor.UNKNOWN_FORMAT: + # Convert the array to a list if we got something weird + # (e.g., non-IEEE floats), or we are pickling the array + # using a Python 2.x compatible protocol. + # + # It is necessary to use a list representation for Python + # 2.x compatible pickle protocol, since Python 2's str + # objects are unpickled as unicode by Python 3. Thus it is + # impossible to make arrays unpicklable by Python 3 by + # using their memory representation, unless we resort to + # ugly hacks such as coercing unicode objects to bytes in + # array_reconstructor. + w_list = self.descr_tolist(space) + return space.newtuple([ + space.type(self), + space.newtuple([space.wrap(self.typecode), w_list]), + w_dict]) + + w_bytes = self.descr_tobytes(space) + w_array_reconstructor = space.fromcache(State).w_array_reconstructor + return space.newtuple([ + w_array_reconstructor, + space.newtuple([space.type(self), + space.wrap(self.typecode), + space.wrap(mformat_code), + w_bytes]), + w_dict]) + + def descr_copy(self, space): + """ copy(array) + + Return a copy of the array. + """ + w_a = self.constructor(self.space) + w_a.setlen(self.len, overallocate=False) + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()), + rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()), + self.len * self.itemsize + ) + return w_a + + def descr_byteswap(self, space): + """ byteswap() + + Byteswap all items of the array. If the items in the array are not 1, 2, + 4, or 8 bytes in size, RuntimeError is raised. + """ + if self.itemsize not in [1, 2, 4, 8]: + msg = "byteswap not supported for this array" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + if self.len == 0: + return + bytes = self._charbuf_start() + tmp = [bytes[0]] * self.itemsize + for start in range(0, self.len * self.itemsize, self.itemsize): + stop = start + self.itemsize - 1 + for i in range(self.itemsize): + tmp[i] = bytes[start + i] + for i in range(self.itemsize): + bytes[stop - i] = tmp[i] + self._charbuf_stop() + + def descr_len(self, space): + return space.wrap(self.len) + + def descr_eq(self, space, w_arr2): + "x.__eq__(y) <==> x==y" + return compare_arrays(space, self, w_arr2, EQ, space.eq) + + def descr_ne(self, space, w_arr2): + "x.__ne__(y) <==> x!=y" + return compare_arrays(space, self, w_arr2, NE, space.ne) + + def descr_lt(self, space, w_arr2): + "x.__lt__(y) <==> x x<=y" + return compare_arrays(space, self, w_arr2, LE, space.le) + + def descr_gt(self, space, w_arr2): + "x.__gt__(y) <==> x>y" + return compare_arrays(space, self, w_arr2, GT, space.gt) + + def descr_ge(self, space, w_arr2): + "x.__ge__(y) <==> x>=y" + return compare_arrays(space, self, w_arr2, GE, space.ge) + + # Basic get/set/append/extend methods + + def descr_getitem(self, space, w_idx): + "x.__getitem__(y) <==> x[y]" + if not space.isinstance_w(w_idx, space.w_slice): + idx, stop, step = space.decode_index(w_idx, self.len) + assert step == 0 + return self.w_getitem(space, idx) + else: + return self.getitem_slice(space, w_idx) + + def descr_setitem(self, space, w_idx, w_item): + "x.__setitem__(i, y) <==> x[i]=y" + if space.isinstance_w(w_idx, space.w_slice): + self.setitem_slice(space, w_idx, w_item) + else: + self.setitem(space, w_idx, w_item) + + def descr_delitem(self, space, w_idx): + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + if step != 1: + # I don't care about efficiency of that so far + w_lst = self.descr_tolist(space) + space.delitem(w_lst, w_idx) + self.setlen(0) + self.fromsequence(w_lst) + return + return self.delitem(space, start, stop) + + def descr_add(self, space, w_other): + raise NotImplementedError + + def descr_inplace_add(self, space, w_other): + raise NotImplementedError + + def descr_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_inplace_mul(self, space, w_repeat): + raise NotImplementedError + + def descr_radd(self, space, w_other): + return self.descr_add(space, w_other) + + def descr_rmul(self, space, w_repeat): + return self.descr_mul(space, w_repeat) + + # Misc methods + + def descr_iter(self, space): + return space.wrap(ArrayIterator(self)) + + def descr_buffer(self, space): + return space.wrap(ArrayBuffer(self)) + + def descr_repr(self, space): + if self.len == 0: + return space.wrap("array('%s')" % self.typecode) + elif self.typecode == "u": + r = space.repr(self.descr_tounicode(space)) + s = u"array('u', %s)" % space.unicode_w(r) + return space.wrap(s) + else: + r = space.repr(self.descr_tolist(space)) + s = "array('%s', %s)" % (self.typecode, space.str_w(r)) + return space.wrap(s) + +W_ArrayBase.typedef = TypeDef( 'array', __new__ = interp2app(w_array), __module__ = 'array', + + __len__ = interp2app(W_ArrayBase.descr_len), + __eq__ = interp2app(W_ArrayBase.descr_eq), + __ne__ = interp2app(W_ArrayBase.descr_ne), + __lt__ = interp2app(W_ArrayBase.descr_lt), + __le__ = interp2app(W_ArrayBase.descr_le), + __gt__ = interp2app(W_ArrayBase.descr_gt), + __ge__ = interp2app(W_ArrayBase.descr_ge), + + __getitem__ = interp2app(W_ArrayBase.descr_getitem), + __setitem__ = interp2app(W_ArrayBase.descr_setitem), + __delitem__ = interp2app(W_ArrayBase.descr_delitem), + + __add__ = interpindirect2app(W_ArrayBase.descr_add), + __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add), + __mul__ = interpindirect2app(W_ArrayBase.descr_mul), + __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul), + __radd__ = interp2app(W_ArrayBase.descr_radd), + __rmul__ = interp2app(W_ArrayBase.descr_rmul), + + __buffer__ = interp2app(W_ArrayBase.descr_buffer), + __iter__ = interp2app(W_ArrayBase.descr_iter), + __repr__ = interp2app(W_ArrayBase.descr_repr), + itemsize = GetSetProperty(descr_itemsize), typecode = GetSetProperty(descr_typecode), __weakref__ = make_weakref_descr(W_ArrayBase), + append = interpindirect2app(W_ArrayBase.descr_append), + extend = interp2app(W_ArrayBase.descr_extend), + count = interpindirect2app(W_ArrayBase.descr_count), + index = interpindirect2app(W_ArrayBase.descr_index), + reverse = interpindirect2app(W_ArrayBase.descr_reverse), + remove = interpindirect2app(W_ArrayBase.descr_remove), + pop = interpindirect2app(W_ArrayBase.descr_pop), + insert = interpindirect2app(W_ArrayBase.descr_insert), + + tolist = interp2app(W_ArrayBase.descr_tolist), + fromlist = interp2app(W_ArrayBase.descr_fromlist), + tostring = interp2app(W_ArrayBase.descr_tostring), + fromstring = interp2app(W_ArrayBase.descr_fromstring), + tofile = interp2app(W_ArrayBase.descr_tofile), + fromfile = interp2app(W_ArrayBase.descr_fromfile), + fromunicode = interp2app(W_ArrayBase.descr_fromunicode), + tounicode = interp2app(W_ArrayBase.descr_tounicode), + tobytes = interp2app(W_ArrayBase.descr_tobytes), + frombytes = interp2app(W_ArrayBase.descr_frombytes), + + buffer_info = interp2app(W_ArrayBase.descr_buffer_info), + __copy__ = interp2app(W_ArrayBase.descr_copy), + __reduce_ex__ = interp2app(W_ArrayBase.descr_reduce_ex), + byteswap = interp2app(W_ArrayBase.descr_byteswap), ) -W_ArrayBase.typedef.registermethods(globals()) class TypeCode(object): def __init__(self, itemtype, unwrap, canoverflow=False, signed=False): self.itemtype = itemtype self.bytes = rffi.sizeof(itemtype) - #self.arraytype = lltype.GcArray(itemtype) self.arraytype = lltype.Array(itemtype, hints={'nolength': True}) self.unwrap = unwrap self.signed = signed @@ -202,14 +656,10 @@ itemsize = mytype.bytes typecode = mytype.typecode - @staticmethod - def register(typeorder): - typeorder[W_Array] = [(W_ArrayBase, None)] + _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer') def __init__(self, space): - self.space = space - self.len = 0 - self.allocated = 0 + W_ArrayBase.__init__(self, space) self.buffer = lltype.nullptr(mytype.arraytype) def item_w(self, w_item): @@ -316,26 +766,6 @@ raise self.setlen(oldlen + i) - def fromstring(self, s): - if len(s) % self.itemsize != 0: - msg = 'string length not a multiple of item size' - raise OperationError(self.space.w_ValueError, self.space.wrap(msg)) - oldlen = self.len - new = len(s) / mytype.bytes - self.setlen(oldlen + new) - cbuf = self._charbuf_start() - for i in range(len(s)): - cbuf[oldlen * mytype.bytes + i] = s[i] - self._charbuf_stop() - - def fromlist(self, w_lst): - s = self.len - try: - self.fromsequence(w_lst) - except OperationError: - self.setlen(s) - raise - def extend(self, w_iterable, accept_different_array=False): space = self.space if isinstance(w_iterable, W_Array): @@ -359,6 +789,9 @@ def _charbuf_start(self): return rffi.cast(rffi.CCHARP, self.buffer) + def _buffer_as_unsigned(self): + return rffi.cast(lltype.Unsigned, self.buffer) + def _charbuf_stop(self): keepalive_until_here(self) @@ -370,157 +803,180 @@ item = float(item) return space.wrap(item) - # Basic get/set/append/extend methods + # interface - def len__Array(space, self): - return space.wrap(self.len) + def descr_append(self, space, w_x): + x = self.item_w(w_x) + self.setlen(self.len + 1) + self.buffer[self.len - 1] = x - def getitem__Array_ANY(space, self, w_idx): - idx, stop, step = space.decode_index(w_idx, self.len) - assert step == 0 - return self.w_getitem(space, idx) + # List interface + def descr_count(self, space, w_val): + cnt = 0 + for i in range(self.len): + # XXX jitdriver + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + cnt += 1 + return space.wrap(cnt) - def getitem__Array_Slice(space, self, w_slice): - start, stop, step, size = space.decode_index4(w_slice, self.len) - w_a = mytype.w_class(self.space) - w_a.setlen(size, overallocate=False) - assert step != 0 - j = 0 - for i in range(start, stop, step): - w_a.buffer[j] = self.buffer[i] - j += 1 - return w_a + def descr_index(self, space, w_val): + for i in range(self.len): + w_item = self.w_getitem(space, i) + if space.is_true(space.eq(w_item, w_val)): + return space.wrap(i) + msg = 'array.index(x): x not in list' + raise OperationError(space.w_ValueError, space.wrap(msg)) - def setitem__Array_ANY_ANY(space, self, w_idx, w_item): - idx, stop, step = space.decode_index(w_idx, self.len) - if step != 0: - msg = 'can only assign array to array slice' - raise OperationError(self.space.w_TypeError, self.space.wrap(msg)) - item = self.item_w(w_item) - self.buffer[idx] = item + def descr_reverse(self, space): + b = self.buffer + for i in range(self.len / 2): + b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] - def setitem__Array_Slice_Array(space, self, w_idx, w_item): - start, stop, step, size = self.space.decode_index4(w_idx, self.len) - assert step != 0 - if w_item.len != size or self is w_item: - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - w_item = space.call_method(w_item, 'tolist') - space.setitem(w_lst, w_idx, w_item) - self.setlen(0) - self.fromsequence(w_lst) - else: + def descr_pop(self, space, i): + if i < 0: + i += self.len + if i < 0 or i >= self.len: + msg = 'pop index out of range' + raise OperationError(space.w_IndexError, space.wrap(msg)) + w_val = self.w_getitem(space, i) + while i < self.len - 1: + self.buffer[i] = self.buffer[i + 1] + i += 1 + self.setlen(self.len - 1) + return w_val + + def descr_remove(self, space, w_val): + w_idx = self.descr_index(space, w_val) + self.descr_pop(space, space.int_w(w_idx)) + + def descr_insert(self, space, idx, w_val): + if idx < 0: + idx += self.len + if idx < 0: + idx = 0 + if idx > self.len: + idx = self.len + + val = self.item_w(w_val) + self.setlen(self.len + 1) + i = self.len - 1 + while i > idx: + self.buffer[i] = self.buffer[i - 1] + i -= 1 + self.buffer[i] = val + + def getitem_slice(self, space, w_idx): + start, stop, step, size = space.decode_index4(w_idx, self.len) + w_a = mytype.w_class(self.space) + w_a.setlen(size, overallocate=False) + assert step != 0 j = 0 for i in range(start, stop, step): - self.buffer[i] = w_item.buffer[j] + w_a.buffer[j] = self.buffer[i] j += 1 + return w_a - def array_append__Array_ANY(space, self, w_x): - x = self.item_w(w_x) - self.setlen(self.len + 1) - self.buffer[self.len - 1] = x + def setitem(self, space, w_idx, w_item): + idx, stop, step = space.decode_index(w_idx, self.len) + if step != 0: + msg = 'can only assign array to array slice' + raise OperationError(self.space.w_TypeError, + self.space.wrap(msg)) + item = self.item_w(w_item) + self.buffer[idx] = item - def array_extend__Array_ANY(space, self, w_iterable): - self.extend(w_iterable) + def setitem_slice(self, space, w_idx, w_item): + if not isinstance(w_item, W_Array): + raise OperationError(space.w_TypeError, space.wrap( + "can only assign to a slice array")) + start, stop, step, size = self.space.decode_index4(w_idx, self.len) + assert step != 0 + if w_item.len != size or self is w_item: + # XXX this is a giant slow hack + w_lst = self.descr_tolist(space) + w_item = space.call_method(w_item, 'tolist') + space.setitem(w_lst, w_idx, w_item) + self.setlen(0) + self.fromsequence(w_lst) + else: + j = 0 + for i in range(start, stop, step): + self.buffer[i] = w_item.buffer[j] + j += 1 - # List interface - def array_count__Array_ANY(space, self, w_val): - cnt = 0 - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - cnt += 1 - return space.wrap(cnt) + # We can't look into this function until ptradd works with things (in the + # JIT) other than rffi.CCHARP + @jit.dont_look_inside + def delitem(self, space, i, j): + if i < 0: + i += self.len + if i < 0: + i = 0 + if j < 0: + j += self.len + if j < 0: + j = 0 + if j > self.len: + j = self.len + if i >= j: + return None + oldbuffer = self.buffer + self.buffer = lltype.malloc(mytype.arraytype, + max(self.len - (j - i), 0), flavor='raw', + add_memory_pressure=True) + if i: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, self.buffer), + rffi.cast(rffi.VOIDP, oldbuffer), + i * mytype.bytes + ) + if j < self.len: + rffi.c_memcpy( + rffi.cast(rffi.VOIDP, rffi.ptradd(self.buffer, i)), + rffi.cast(rffi.VOIDP, rffi.ptradd(oldbuffer, j)), + (self.len - j) * mytype.bytes + ) + self.len -= j - i + self.allocated = self.len + if oldbuffer: + lltype.free(oldbuffer, flavor='raw') - def array_index__Array_ANY(space, self, w_val): - for i in range(self.len): - w_item = self.w_getitem(space, i) - if space.is_true(space.eq(w_item, w_val)): - return space.wrap(i) - msg = 'array.index(x): x not in list' - raise OperationError(space.w_ValueError, space.wrap(msg)) + # Add and mul methods - def array_reverse__Array(space, self): - b = self.buffer - for i in range(self.len / 2): - b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i] + def descr_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + a = mytype.w_class(space) + a.setlen(self.len + w_other.len, overallocate=False) + for i in range(self.len): + a.buffer[i] = self.buffer[i] + for i in range(w_other.len): + a.buffer[i + self.len] = w_other.buffer[i] + return a - def array_pop__Array_ANY(space, self, w_idx): - i = space.int_w(w_idx) - if i < 0: - i += self.len - if i < 0 or i >= self.len: - msg = 'pop index out of range' - raise OperationError(space.w_IndexError, space.wrap(msg)) - w_val = self.w_getitem(space, i) - while i < self.len - 1: - self.buffer[i] = self.buffer[i + 1] - i += 1 - self.setlen(self.len - 1) - return w_val + def descr_inplace_add(self, space, w_other): + if not isinstance(w_other, W_Array): + return space.w_NotImplemented + oldlen = self.len + otherlen = w_other.len + self.setlen(oldlen + otherlen) + for i in range(otherlen): + self.buffer[oldlen + i] = w_other.buffer[i] + return self - def array_remove__Array_ANY(space, self, w_val): - w_idx = array_index__Array_ANY(space, self, w_val) - array_pop__Array_ANY(space, self, w_idx) + def descr_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, False) - def array_insert__Array_ANY_ANY(space, self, w_idx, w_val): - idx = space.int_w(w_idx) - if idx < 0: - idx += self.len - if idx < 0: - idx = 0 - if idx > self.len: - idx = self.len - - val = self.item_w(w_val) - self.setlen(self.len + 1) - i = self.len - 1 - while i > idx: - self.buffer[i] = self.buffer[i - 1] - i -= 1 - self.buffer[i] = val - - def delitem__Array_ANY(space, self, w_idx): - # XXX this is a giant slow hack - w_lst = array_tolist__Array(space, self) - space.delitem(w_lst, w_idx) - self.setlen(0) - self.fromsequence(w_lst) - - # Add and mul methods - - def add__Array_Array(space, self, other): - a = mytype.w_class(space) - a.setlen(self.len + other.len, overallocate=False) - for i in range(self.len): - a.buffer[i] = self.buffer[i] - for i in range(other.len): - a.buffer[i + self.len] = other.buffer[i] - return a - - def inplace_add__Array_Array(space, self, other): - oldlen = self.len - otherlen = other.len - self.setlen(oldlen + otherlen) - for i in range(otherlen): - self.buffer[oldlen + i] = other.buffer[i] - return self - - def mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, False) - - def mul__ANY_Array(space, w_repeat, self): - return _mul_helper(space, self, w_repeat, False) - - def inplace_mul__Array_ANY(space, self, w_repeat): - return _mul_helper(space, self, w_repeat, True) + def descr_inplace_mul(self, space, w_repeat): + return _mul_helper(space, self, w_repeat, True) def _mul_helper(space, self, w_repeat, is_inplace): try: repeat = space.getindex_w(w_repeat, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - raise FailedToImplement + return space.w_NotImplemented raise repeat = max(repeat, 0) try: @@ -559,218 +1015,17 @@ a.buffer[r * oldlen + i] = self.buffer[i] return a - # Convertions - - def array_tolist__Array(space, self): - w_l = space.newlist([]) - for i in range(self.len): - w_l.append(self.w_getitem(space, i)) - return w_l - - def array_fromlist__Array_List(space, self, w_lst): - self.fromlist(w_lst) - - def array_frombytes__Array_ANY(space, self, w_s): - self.fromstring(space.bufferstr_w(w_s)) - - def array_fromstring__Array_ANY(space, self, w_s): - msg = "fromstring() is deprecated. Use frombytes() instead." - space.warn(space.wrap(msg), self.space.w_DeprecationWarning) - self.fromstring(space.str_w(w_s)) - - def array_tobytes__Array(space, self): - cbuf = self._charbuf_start() - s = rffi.charpsize2str(cbuf, self.len * mytype.bytes) - self._charbuf_stop() - return self.space.wrapbytes(s) - - def array_tostring__Array(space, self): - msg = "tostring() is deprecated. Use tobytes() instead." - space.warn(space.wrap(msg), space.w_DeprecationWarning) - return array_tobytes__Array(space, self) - - def array_fromfile__Array_ANY_ANY(space, self, w_f, w_n): - n = space.int_w(w_n) - - try: - size = ovfcheck(self.itemsize * n) - except OverflowError: - raise MemoryError - w_item = space.call_method(w_f, 'read', space.wrap(size)) - item = space.bytes_w(w_item) - if len(item) < size: - n = len(item) % self.itemsize - elems = max(0, len(item) - (len(item) % self.itemsize)) - if n != 0: - item = item[0:elems] - w_item = space.wrapbytes(item) - array_fromstring__Array_ANY(space, self, w_item) - msg = "not enough items in file" - raise OperationError(space.w_EOFError, space.wrap(msg)) - array_fromstring__Array_ANY(space, self, w_item) - - def array_tofile__Array_ANY(space, self, w_f): - w_s = array_tobytes__Array(space, self) - space.call_method(w_f, 'write', w_s) - - if mytype.typecode == 'u': - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - # XXX the following probable bug is not emulated: - # CPython accepts a non-unicode string or a buffer, and then - # behaves just like fromstring(), except that it strangely truncate - # string arguments at multiples of the unicode byte size. - # Let's only accept unicode arguments for now. - self.fromsequence(w_ustr) - - def array_tounicode__Array(space, self): - return space.wrap(rffi.wcharpsize2unicode(self.buffer, self.len)) - else: - - def array_fromunicode__Array_Unicode(space, self, w_ustr): - msg = "fromunicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - def array_tounicode__Array(space, self): - msg = "tounicode() may only be called on type 'u' arrays" - raise OperationError(space.w_ValueError, space.wrap(msg)) - - # Compare methods - @specialize.arg(3) - def _cmp_impl(space, self, other, space_fn): - # XXX this is a giant slow hack - w_lst1 = array_tolist__Array(space, self) - w_lst2 = space.call_method(other, 'tolist') - return space_fn(w_lst1, w_lst2) - - def eq__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.eq) - - def ne__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ne) - - def lt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.lt) - - def le__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.le) - - def gt__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.gt) - - def ge__Array_ArrayBase(space, self, other): - return _cmp_impl(space, self, other, space.ge) - - # Misc methods - def iter__Array(space, self): - return space.wrap(ArrayIterator(self)) - - def buffer__Array(space, self): - return space.wrap(ArrayBuffer(self)) - - def array_buffer_info__Array(space, self): - w_ptr = space.wrap(rffi.cast(lltype.Unsigned, self.buffer)) - w_len = space.wrap(self.len) - return space.newtuple([w_ptr, w_len]) - - def array_reduce_ex__Array_ANY(space, self, w_protocol): - protocol = space.int_w(w_protocol) - try: - w_dict = space.getattr(self, space.wrap('__dict__')) - except OperationError: - w_dict = space.w_None - from pypy.module.array import reconstructor - mformat_code = reconstructor.typecode_to_mformat_code(mytype.typecode) - if protocol < 3 or mformat_code == reconstructor.UNKNOWN_FORMAT: - # Convert the array to a list if we got something weird - # (e.g., non-IEEE floats), or we are pickling the array - # using a Python 2.x compatible protocol. - # - # It is necessary to use a list representation for Python - # 2.x compatible pickle protocol, since Python 2's str - # objects are unpickled as unicode by Python 3. Thus it is - # impossible to make arrays unpicklable by Python 3 by - # using their memory representation, unless we resort to - # ugly hacks such as coercing unicode objects to bytes in - # array_reconstructor. - w_list = array_tolist__Array(space, self) - return space.newtuple([ - space.type(self), - space.newtuple([space.wrap(mytype.typecode), w_list]), - w_dict]) - - w_bytes = array_tobytes__Array(space, self) - w_array_reconstructor = space.fromcache(State).w_array_reconstructor - return space.newtuple([ - w_array_reconstructor, - space.newtuple([space.type(self), - space.wrap(mytype.typecode), - space.wrap(mformat_code), - w_bytes]), - w_dict]) - - def array_copy__Array(space, self): - w_a = mytype.w_class(self.space) - w_a.setlen(self.len, overallocate=False) - rffi.c_memcpy( - rffi.cast(rffi.VOIDP, w_a.buffer), - rffi.cast(rffi.VOIDP, self.buffer), - self.len * mytype.bytes - ) - return w_a - - def array_byteswap__Array(space, self): - if mytype.bytes not in [1, 2, 4, 8]: - msg = "byteswap not supported for this array" - raise OperationError(space.w_RuntimeError, space.wrap(msg)) - if self.len == 0: - return - bytes = self._charbuf_start() - tmp = [bytes[0]] * mytype.bytes - for start in range(0, self.len * mytype.bytes, mytype.bytes): - stop = start + mytype.bytes - 1 - for i in range(mytype.bytes): - tmp[i] = bytes[start + i] - for i in range(mytype.bytes): - bytes[stop - i] = tmp[i] - self._charbuf_stop() - - def repr__Array(space, self): - if self.len == 0: - return space.wrap("array('%s')" % self.typecode) - elif self.typecode == "u": - r = space.repr(array_tounicode__Array(space, self)) - s = u"array('u', %s)" % space.unicode_w(r) - return space.wrap(s) - else: - r = space.repr(array_tolist__Array(space, self)) - s = "array('%s', %s)" % (self.typecode, space.str_w(r)) - return space.wrap(s) - mytype.w_class = W_Array - - # Annotator seems to mess up if the names are not unique + W_Array.constructor = W_Array name = 'ArrayType' + mytype.typecode W_Array.__name__ = 'W_' + name - import re - for n, f in locals().items(): - new, n = re.subn('_Array_', '_%s_' % name, n) - if n > 0: - f.__name__ = new - - from pypy.objspace.std.sliceobject import W_SliceObject - from pypy.objspace.std.listobject import W_ListObject - from pypy.objspace.std.unicodeobject import W_UnicodeObject - register_all(locals(), globals()) - for mytype in types.values(): make_array(mytype) - +del mytype class State: def __init__(self, space): w_module = space.getbuiltinmodule('array') self.w_array_reconstructor = space.getattr( w_module, space.wrap("_array_reconstructor")) - diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -19,7 +19,7 @@ class BaseArrayTests: - + def test_ctor(self): assert len(self.array('i')) == 0 @@ -373,7 +373,6 @@ a = self.array('i', [0, 0, 0]) assert a.tobytes() == b'\x00' * 3 * a.itemsize - s = self.array('i', [1, 2, 3]).tobytes() assert 0x00 in s assert 0x01 in s @@ -484,7 +483,7 @@ return True class incomparable(object): pass - + for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'), ('abc', 'acb', 'u')): for t in tt: @@ -634,14 +633,14 @@ raises(TypeError, "a * 'hi'") raises(TypeError, "'hi' * a") raises(TypeError, "a *= 'hi'") - + class mulable(object): def __mul__(self, other): return "mul" def __rmul__(self, other): return "rmul" - + assert mulable() * self.array('i') == 'mul' assert self.array('i') * mulable() == 'rmul' @@ -753,7 +752,7 @@ def __getitem__(self, i): return array.__getitem__(self, self._index(i)) - + def __setitem__(self, i, val): return array.__setitem__(self, self._index(i), val) @@ -767,7 +766,7 @@ assert img[3, 25] == 3 * 9 - + def test_override_from(self): class mya(self.array): def fromlist(self, lst): @@ -836,7 +835,7 @@ def test_subclass_del(self): import array, gc, weakref l = [] - + class A(array.array): pass diff --git a/pypy/module/array/test/test_ztranslation.py b/pypy/module/array/test/test_ztranslation.py new file mode 100644 --- /dev/null +++ b/pypy/module/array/test/test_ztranslation.py @@ -0,0 +1,6 @@ + +from pypy.objspace.fake.checkmodule import checkmodule + +def test_checkmodule(): + checkmodule('array') + diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -545,12 +545,27 @@ def make_wrapper(space, callable): "NOT_RPYTHON" names = callable.api_func.argnames - argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes, - [name.startswith("w_") for name in names]))) + argtypes = callable.api_func.argtypes + is_wrapped_list = [name.startswith("w_") for name in names] fatal_value = callable.api_func.restype._defl() - @specialize.ll() - def wrapper(*args): + lines = [] + for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)): + if is_PyObject(argtype) and is_wrapped: + new_lines = [ + 'if %(arg)s:', + ' %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))', + 'else:', + ' %(arg)s = None', + ] + for j in range(len(new_lines)): + new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i} + lines += new_lines + middle = '\n '.join(lines) + arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))]) + + source = py.code.Source(""" + def wrapper(%(args)s): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference retval = fatal_value @@ -558,20 +573,10 @@ try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, - assert len(args) == len(callable.api_func.argtypes) - for i, (typ, is_wrapped) in argtypes_enum_ui: - arg = args[i] - if is_PyObject(typ) and is_wrapped: - if arg: - arg_conv = from_ref(space, rffi.cast(PyObject, arg)) - else: - arg_conv = None - else: - arg_conv = arg - boxed_args += (arg_conv, ) state = space.fromcache(State) + %(middle)s try: - result = callable(space, *boxed_args) + result = callable(space, %(args)s) if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, " DONE" except OperationError, e: @@ -593,8 +598,8 @@ if failed: error_value = callable.api_func.error_value if error_value is CANNOT_FAIL: - raise SystemError("The function '%s' was not supposed to fail" - % (callable.__name__,)) + raise SystemError("The function '%%s' was not supposed to fail" + %% (callable.__name__,)) retval = error_value elif is_PyObject(callable.api_func.restype): @@ -622,6 +627,12 @@ print str(e) pypy_debug_catch_fatal_exception() return retval + """ % {"middle": middle, "args": arg_spec}) + d = {} + d.update(locals()) + d.update(globals()) + exec source.compile() in d + wrapper = d['wrapper'] callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -1016,7 +1027,7 @@ export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): - deco = entrypoint("cpyext", func.argtypes, name, relax=True) + deco = entrypoint("cpyext", func.argtypes, name) deco(func.get_wrapper(space)) setup_init_functions(eci, translating=True) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -79,8 +79,6 @@ import pypy.objspace.std.default # register a few catch-all multimethods import pypy.objspace.std.marshal_impl # install marshal multimethods - if config.objspace.usemodules.array: - import pypy.module.array # the set of implementation types self.typeorder = { diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py --- a/rpython/annotator/description.py +++ b/rpython/annotator/description.py @@ -215,9 +215,8 @@ if len(self._cache) != 1: raise NoStandardGraph(self) [graph] = self._cache.values() - relax_sig_check = getattr(self.pyobj, "relax_sig_check", False) if (graph.signature != self.signature or - graph.defaults != self.defaults) and not relax_sig_check: + graph.defaults != self.defaults): raise NoStandardGraph(self) return graph diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -3542,16 +3542,6 @@ s = a.build_types(f, [int]) assert s.knowntype is int - def test_relax(self): - def f(*args): - return args[0] + args[1] - f.relax_sig_check = True - def g(x): - return f(x, x - x) - a = self.RPythonAnnotator() - s = a.build_types(g, [int]) - assert a.bookkeeper.getdesc(f).getuniquegraph() - def test_cannot_raise_ll_exception(self): from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr # diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py --- a/rpython/jit/metainterp/blackhole.py +++ b/rpython/jit/metainterp/blackhole.py @@ -1,7 +1,8 @@ from rpython.jit.codewriter import heaptracker, longlong from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr from rpython.jit.metainterp.compile import ResumeAtPositionDescr -from rpython.jit.metainterp.jitexc import JitException, get_llexception, reraise +from rpython.jit.metainterp.jitexc import get_llexception, reraise +from rpython.jit.metainterp import jitexc from rpython.rlib import longlong2float from rpython.rlib.debug import ll_assert, make_sure_not_resized from rpython.rlib.objectmodel import we_are_translated @@ -25,7 +26,7 @@ LONGLONG_TYPECODE = 'i' if longlong.is_64_bit else 'f' -class LeaveFrame(JitException): +class LeaveFrame(jitexc.JitException): pass class MissingValue(object): @@ -306,7 +307,7 @@ self.dispatch_loop(self, self.jitcode.code, self.position) except LeaveFrame: break - except JitException: + except jitexc.JitException: raise # go through except Exception, e: lle = get_llexception(self.cpu, e) @@ -902,8 +903,7 @@ @arguments("self", "i", "I", "R", "F", "I", "R", "F") def bhimpl_jit_merge_point(self, jdindex, *args): if self.nextblackholeinterp is None: # we are the last level - CRN = self.builder.metainterp_sd.ContinueRunningNormally - raise CRN(*args) + raise jitexc.ContinueRunningNormally(*args) # Note that the case above is an optimization: the case # below would work too. But it keeps unnecessary stuff on # the stack; the solution above first gets rid of the blackhole @@ -1400,7 +1400,7 @@ # we now proceed to interpret the bytecode in this frame self.run() # - except JitException, e: + except jitexc.JitException, e: raise # go through except Exception, e: # if we get an exception, return it to the caller frame @@ -1495,20 +1495,20 @@ sd = self.builder.metainterp_sd kind = self._return_type if kind == 'v': - raise sd.DoneWithThisFrameVoid() + raise jitexc.DoneWithThisFrameVoid() elif kind == 'i': - raise sd.DoneWithThisFrameInt(self.get_tmpreg_i()) + raise jitexc.DoneWithThisFrameInt(self.get_tmpreg_i()) elif kind == 'r': - raise sd.DoneWithThisFrameRef(self.cpu, self.get_tmpreg_r()) + raise jitexc.DoneWithThisFrameRef(self.cpu, self.get_tmpreg_r()) elif kind == 'f': - raise sd.DoneWithThisFrameFloat(self.get_tmpreg_f()) + raise jitexc.DoneWithThisFrameFloat(self.get_tmpreg_f()) else: assert False def _exit_frame_with_exception(self, e): sd = self.builder.metainterp_sd e = lltype.cast_opaque_ptr(llmemory.GCREF, e) - raise sd.ExitFrameWithExceptionRef(self.cpu, e) + raise jitexc.ExitFrameWithExceptionRef(self.cpu, e) def _handle_jitexception_in_portal(self, e): # This case is really rare, but can occur if @@ -1558,23 +1558,23 @@ while True: try: current_exc = blackholeinterp._resume_mainloop(current_exc) - except JitException, e: + except jitexc.JitException as e: blackholeinterp, current_exc = _handle_jitexception( blackholeinterp, e) blackholeinterp.builder.release_interp(blackholeinterp) blackholeinterp = blackholeinterp.nextblackholeinterp -def _handle_jitexception(blackholeinterp, jitexc): +def _handle_jitexception(blackholeinterp, exc): # See comments in _handle_jitexception_in_portal(). while not blackholeinterp.jitcode.is_portal: blackholeinterp.builder.release_interp(blackholeinterp) blackholeinterp = blackholeinterp.nextblackholeinterp if blackholeinterp.nextblackholeinterp is None: blackholeinterp.builder.release_interp(blackholeinterp) - raise jitexc # bottommost entry: go through + raise exc # bottommost entry: go through # We have reached a recursive portal level. try: - blackholeinterp._handle_jitexception_in_portal(jitexc) + blackholeinterp._handle_jitexception_in_portal(exc) except Exception, e: # It raised a general exception (it should not be a JitException here). lle = get_llexception(blackholeinterp.cpu, e) diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -12,7 +12,7 @@ from rpython.jit.metainterp.history import TreeLoop, Box, JitCellToken, TargetToken from rpython.jit.metainterp.history import AbstractFailDescr, BoxInt from rpython.jit.metainterp.history import BoxPtr, BoxFloat, ConstInt -from rpython.jit.metainterp import history, resume +from rpython.jit.metainterp import history, resume, jitexc from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp.inliner import Inliner from rpython.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP, ResumeDataDirectReader @@ -415,32 +415,32 @@ class DoneWithThisFrameDescrVoid(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.VOID - raise metainterp_sd.DoneWithThisFrameVoid() + raise jitexc.DoneWithThisFrameVoid() class DoneWithThisFrameDescrInt(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.INT result = metainterp_sd.cpu.get_int_value(deadframe, 0) - raise metainterp_sd.DoneWithThisFrameInt(result) + raise jitexc.DoneWithThisFrameInt(result) class DoneWithThisFrameDescrRef(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.REF cpu = metainterp_sd.cpu result = cpu.get_ref_value(deadframe, 0) - raise metainterp_sd.DoneWithThisFrameRef(cpu, result) + raise jitexc.DoneWithThisFrameRef(cpu, result) class DoneWithThisFrameDescrFloat(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): assert jitdriver_sd.result_type == history.FLOAT result = metainterp_sd.cpu.get_float_value(deadframe, 0) - raise metainterp_sd.DoneWithThisFrameFloat(result) + raise jitexc.DoneWithThisFrameFloat(result) class ExitFrameWithExceptionDescrRef(_DoneWithThisFrameDescr): def handle_fail(self, deadframe, metainterp_sd, jitdriver_sd): cpu = metainterp_sd.cpu value = cpu.get_ref_value(deadframe, 0) - raise metainterp_sd.ExitFrameWithExceptionRef(cpu, value) + raise jitexc.ExitFrameWithExceptionRef(cpu, value) class TerminatingLoopToken(JitCellToken): # FIXME: kill? @@ -865,7 +865,7 @@ if not exception: exception = cast_instance_to_gcref(memory_error) assert exception, "PropagateExceptionDescr: no exception??" - raise metainterp_sd.ExitFrameWithExceptionRef(cpu, exception) + raise jitexc.ExitFrameWithExceptionRef(cpu, exception) def compile_tmp_callback(cpu, jitdriver_sd, greenboxes, redargtypes, memory_manager=None): diff --git a/rpython/jit/metainterp/jitexc.py b/rpython/jit/metainterp/jitexc.py --- a/rpython/jit/metainterp/jitexc.py +++ b/rpython/jit/metainterp/jitexc.py @@ -1,8 +1,9 @@ from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr from rpython.rtyper.annlowlevel import cast_base_ptr_to_instance -from rpython.rtyper.lltypesystem import rclass +from rpython.rtyper.lltypesystem import lltype, rclass from rpython.rtyper.llinterp import LLException from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.codewriter import longlong class JitException(Exception): @@ -12,6 +13,54 @@ """ _go_through_llinterp_uncaught_ = True # ugh +class DoneWithThisFrameVoid(JitException): + def __str__(self): + return 'DoneWithThisFrameVoid()' + +class DoneWithThisFrameInt(JitException): + def __init__(self, result): + assert lltype.typeOf(result) is lltype.Signed + self.result = result + def __str__(self): + return 'DoneWithThisFrameInt(%s)' % (self.result,) + +class DoneWithThisFrameRef(JitException): + def __init__(self, cpu, result): + assert lltype.typeOf(result) == cpu.ts.BASETYPE + self.result = result + def __str__(self): + return 'DoneWithThisFrameRef(%s)' % (self.result,) + +class DoneWithThisFrameFloat(JitException): + def __init__(self, result): + assert lltype.typeOf(result) is longlong.FLOATSTORAGE + self.result = result + def __str__(self): + return 'DoneWithThisFrameFloat(%s)' % (self.result,) + +class ExitFrameWithExceptionRef(JitException): + def __init__(self, cpu, value): + assert lltype.typeOf(value) == cpu.ts.BASETYPE + self.value = value + def __str__(self): + return 'ExitFrameWithExceptionRef(%s)' % (self.value,) + +class ContinueRunningNormally(JitException): + def __init__(self, gi, gr, gf, ri, rr, rf): + # the six arguments are: lists of green ints, greens refs, + # green floats, red ints, red refs, and red floats. + self.green_int = gi + self.green_ref = gr + self.green_float = gf + self.red_int = ri + self.red_ref = rr + self.red_float = rf + def __str__(self): + return 'ContinueRunningNormally(%s, %s, %s, %s, %s, %s)' % ( + self.green_int, self.green_ref, self.green_float, + self.red_int, self.red_ref, self.red_float) + + def _get_standard_error(rtyper, Class): exdata = rtyper.getexceptiondata() clsdef = rtyper.annotator.bookkeeper.getuniqueclassdef(Class) diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -5,11 +5,10 @@ from rpython.jit.codewriter import heaptracker from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter.jitcode import JitCode, SwitchDictDescr -from rpython.jit.metainterp import history, compile, resume, executor +from rpython.jit.metainterp import history, compile, resume, executor, jitexc from rpython.jit.metainterp.heapcache import HeapCache from rpython.jit.metainterp.history import (Const, ConstInt, ConstPtr, ConstFloat, Box, TargetToken) -from rpython.jit.metainterp.jitexc import JitException, get_llexception from rpython.jit.metainterp.jitprof import EmptyProfiler from rpython.jit.metainterp.logger import Logger from rpython.jit.metainterp.optimizeopt.util import args_dict_box @@ -1705,13 +1704,13 @@ result_type = self.jitdriver_sd.result_type if result_type == history.VOID: assert resultbox is None - raise sd.DoneWithThisFrameVoid() + raise jitexc.DoneWithThisFrameVoid() elif result_type == history.INT: - raise sd.DoneWithThisFrameInt(resultbox.getint()) + raise jitexc.DoneWithThisFrameInt(resultbox.getint()) elif result_type == history.REF: - raise sd.DoneWithThisFrameRef(self.cpu, resultbox.getref_base()) + raise jitexc.DoneWithThisFrameRef(self.cpu, resultbox.getref_base()) elif result_type == history.FLOAT: - raise sd.DoneWithThisFrameFloat(resultbox.getfloatstorage()) + raise jitexc.DoneWithThisFrameFloat(resultbox.getfloatstorage()) else: assert False @@ -1734,7 +1733,7 @@ self.compile_exit_frame_with_exception(excvaluebox) except SwitchToBlackhole, stb: self.aborted_tracing(stb.reason) - raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base()) + raise jitexc.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base()) def check_recursion_invariant(self): portal_call_depth = -1 @@ -1842,9 +1841,9 @@ op.name = self.framestack[-1].jitcode.name def execute_raised(self, exception, constant=False): - if isinstance(exception, JitException): - raise JitException, exception # go through - llexception = get_llexception(self.cpu, exception) + if isinstance(exception, jitexc.JitException): + raise jitexc.JitException, exception # go through + llexception = jitexc.get_llexception(self.cpu, exception) self.execute_ll_raised(llexception, constant) def execute_ll_raised(self, llexception, constant=False): @@ -2089,7 +2088,7 @@ gi, gr, gf = self._unpack_boxes(live_arg_boxes, 0, num_green_args) ri, rr, rf = self._unpack_boxes(live_arg_boxes, num_green_args, len(live_arg_boxes)) - CRN = self.staticdata.ContinueRunningNormally + CRN = jitexc.ContinueRunningNormally raise CRN(gi, gr, gf, ri, rr, rf) else: # However, in order to keep the existing tests working @@ -2671,11 +2670,11 @@ # ____________________________________________________________ -class ChangeFrame(JitException): +class ChangeFrame(jitexc.JitException): """Raised after we mutated metainterp.framestack, in order to force it to reload the current top-of-stack frame that gets interpreted.""" -class SwitchToBlackhole(JitException): +class SwitchToBlackhole(jitexc.JitException): def __init__(self, reason, raising_exception=False): self.reason = reason self.raising_exception = raising_exception diff --git a/rpython/jit/metainterp/test/support.py b/rpython/jit/metainterp/test/support.py --- a/rpython/jit/metainterp/test/support.py +++ b/rpython/jit/metainterp/test/support.py @@ -6,7 +6,7 @@ from rpython.jit.metainterp.warmspot import ll_meta_interp, get_stats from rpython.jit.metainterp.warmstate import unspecialize_value from rpython.jit.metainterp.optimizeopt import ALL_OPTS_DICT -from rpython.jit.metainterp import pyjitpl, history +from rpython.jit.metainterp import pyjitpl, history, jitexc from rpython.jit.codewriter.policy import JitPolicy from rpython.jit.codewriter import codewriter, longlong from rpython.rlib.rfloat import isnan @@ -118,30 +118,19 @@ return blackholeinterp._final_result_anytype() def _run_with_pyjitpl(testself, args): - - class DoneWithThisFrame(Exception): - pass - - class DoneWithThisFrameRef(DoneWithThisFrame): - def __init__(self, cpu, *args): - DoneWithThisFrame.__init__(self, *args) - cw = testself.cw opt = history.Options(listops=True) metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt) metainterp_sd.finish_setup(cw) [jitdriver_sd] = metainterp_sd.jitdrivers_sd metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd) - metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame - metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef - metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame testself.metainterp = metainterp try: metainterp.compile_and_run_once(jitdriver_sd, *args) - except DoneWithThisFrame, e: - #if option.view: - # metainterp.stats.view() - return e.args[0] + except (jitexc.DoneWithThisFrameInt, + jitexc.DoneWithThisFrameRef, + jitexc.DoneWithThisFrameFloat) as e: + return e.result else: raise Exception("FAILED") diff --git a/rpython/jit/metainterp/test/test_blackhole.py b/rpython/jit/metainterp/test/test_blackhole.py --- a/rpython/jit/metainterp/test/test_blackhole.py +++ b/rpython/jit/metainterp/test/test_blackhole.py @@ -4,7 +4,7 @@ from rpython.jit.metainterp.blackhole import BlackholeInterpBuilder from rpython.jit.metainterp.blackhole import BlackholeInterpreter from rpython.jit.metainterp.blackhole import convert_and_run_from_pyjitpl -from rpython.jit.metainterp import history, pyjitpl +from rpython.jit.metainterp import history, pyjitpl, jitexc from rpython.jit.codewriter.assembler import JitCode from rpython.rtyper.lltypesystem import lltype, llmemory from rpython.rtyper.llinterp import LLException @@ -119,6 +119,7 @@ "\x01\x02", # int_return/i [], num_regs_i=3, num_regs_r=0, num_regs_f=0) + jitcode.is_portal = True pc = 1 registers_i = [history.BoxInt(40), history.ConstInt(2), None] class MyMetaInterp: @@ -129,8 +130,6 @@ def start_blackhole(): pass @staticmethod def end_blackhole(): pass - class DoneWithThisFrameInt(Exception): - pass last_exc_value_box = None framestack = [MyMIFrame()] MyMetaInterp.staticdata.blackholeinterpbuilder = getblackholeinterp( @@ -138,9 +137,9 @@ MyMetaInterp.staticdata.blackholeinterpbuilder.metainterp_sd = \ MyMetaInterp.staticdata # - d = py.test.raises(MyMetaInterp.staticdata.DoneWithThisFrameInt, + d = py.test.raises(jitexc.DoneWithThisFrameInt, convert_and_run_from_pyjitpl, MyMetaInterp()) - assert d.value.args == (42,) + assert d.value.result == 42 class TestBlackhole(LLJitMixin): diff --git a/rpython/jit/metainterp/test/test_warmspot.py b/rpython/jit/metainterp/test/test_warmspot.py --- a/rpython/jit/metainterp/test/test_warmspot.py +++ b/rpython/jit/metainterp/test/test_warmspot.py @@ -1,4 +1,5 @@ import py +from rpython.jit.metainterp import jitexc from rpython.jit.metainterp.warmspot import get_stats from rpython.rlib.jit import JitDriver, set_param, unroll_safe, jit_callback from rpython.jit.backend.llgraph import runner @@ -583,14 +584,14 @@ no = self.no assert deadframe._no == no if no == 0: - raise metainterp_sd.warmrunnerdesc.DoneWithThisFrameInt(3) + raise jitexc.DoneWithThisFrameInt(3) if no == 1: - raise metainterp_sd.warmrunnerdesc.ContinueRunningNormally( + raise jitexc.ContinueRunningNormally( [0], [], [], [1], [], []) if no == 3: exc = lltype.malloc(OBJECT) exc.typeptr = exc_vtable - raise metainterp_sd.warmrunnerdesc.ExitFrameWithExceptionRef( + raise jitexc.ExitFrameWithExceptionRef( metainterp_sd.cpu, lltype.cast_opaque_ptr(llmemory.GCREF, exc)) assert 0 diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -16,10 +16,9 @@ from rpython.translator.backendopt import removenoops from rpython.translator.unsimplify import call_final_function -from rpython.jit.metainterp import history, pyjitpl, gc, memmgr +from rpython.jit.metainterp import history, pyjitpl, gc, memmgr, jitexc from rpython.jit.metainterp.pyjitpl import MetaInterpStaticData from rpython.jit.metainterp.jitprof import Profiler, EmptyProfiler -from rpython.jit.metainterp.jitexc import JitException from rpython.jit.metainterp.jitdriver import JitDriverStaticData from rpython.jit.codewriter import support, codewriter, longlong from rpython.jit.codewriter.policy import JitPolicy @@ -172,9 +171,6 @@ stats.maybe_view() stats.check_consistency() -class ContinueRunningNormallyBase(JitException): - pass - # ____________________________________________________________ class WarmRunnerDesc(object): @@ -210,7 +206,6 @@ # self.hooks = policy.jithookiface self.make_virtualizable_infos() - self.make_exception_classes() self.make_driverhook_graphs() self.make_enter_functions() self.rewrite_jit_merge_points(policy) @@ -466,70 +461,6 @@ vinfos[VTYPEPTR] = VirtualizableInfo(self, VTYPEPTR) jd.virtualizable_info = vinfos[VTYPEPTR] - def make_exception_classes(self): - - class DoneWithThisFrameVoid(JitException): - def __str__(self): - return 'DoneWithThisFrameVoid()' - - class DoneWithThisFrameInt(JitException): - def __init__(self, result): - assert lltype.typeOf(result) is lltype.Signed - self.result = result - def __str__(self): - return 'DoneWithThisFrameInt(%s)' % (self.result,) - - class DoneWithThisFrameRef(JitException): - def __init__(self, cpu, result): - assert lltype.typeOf(result) == cpu.ts.BASETYPE - self.result = result - def __str__(self): - return 'DoneWithThisFrameRef(%s)' % (self.result,) - - class DoneWithThisFrameFloat(JitException): - def __init__(self, result): - assert lltype.typeOf(result) is longlong.FLOATSTORAGE - self.result = result - def __str__(self): - return 'DoneWithThisFrameFloat(%s)' % (self.result,) - - class ExitFrameWithExceptionRef(JitException): - def __init__(self, cpu, value): - assert lltype.typeOf(value) == cpu.ts.BASETYPE - self.value = value - def __str__(self): - return 'ExitFrameWithExceptionRef(%s)' % (self.value,) - - class ContinueRunningNormally(ContinueRunningNormallyBase): - def __init__(self, gi, gr, gf, ri, rr, rf): - # the six arguments are: lists of green ints, greens refs, - # green floats, red ints, red refs, and red floats. - self.green_int = gi - self.green_ref = gr - self.green_float = gf - self.red_int = ri - self.red_ref = rr - self.red_float = rf - def __str__(self): - return 'ContinueRunningNormally(%s, %s, %s, %s, %s, %s)' % ( - self.green_int, self.green_ref, self.green_float, - self.red_int, self.red_ref, self.red_float) - From noreply at buildbot.pypy.org Tue May 14 22:55:59 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 22:55:59 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove unused imports. Message-ID: <20130514205559.C5B8E1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64103:ab8e370f6198 Date: 2013-05-14 22:32 +0200 http://bitbucket.org/pypy/pypy/changeset/ab8e370f6198/ Log: Remove unused imports. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,8 +1,5 @@ from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.settype import set_typedef as settypedef from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef from pypy.interpreter import gateway from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.mixedmodule import MixedModule @@ -466,7 +463,6 @@ # it ends up taking n**2 time, because the next() calls below # will take longer and longer. But all interesting strategies # provide a better one. - space = self.space iterator = self.iteritems(w_dict) w_key, w_value = iterator.next_item() self.delitem(w_dict, w_key) From noreply at buildbot.pypy.org Tue May 14 22:56:01 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 22:56:01 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Fix translation. Thanks to fijal for the workaround which explicitly checks whether w_other is of the right type. Message-ID: <20130514205601.0575B1C23D0@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64104:8b5c0e47435c Date: 2013-05-14 22:53 +0200 http://bitbucket.org/pypy/pypy/changeset/8b5c0e47435c/ Log: Fix translation. Thanks to fijal for the workaround which explicitly checks whether w_other is of the right type. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -111,6 +111,10 @@ def descr_eq(self, space, w_other): if space.is_w(self, w_other): return space.w_True + if not isinstance(w_other, W_DictMultiObject): + raise operationerrfmt(space.w_TypeError, + "Expected dict object, got %s", + space.str_w(space.str(space.type(w_other)))) if self.length() != w_other.length(): return space.w_False @@ -131,6 +135,11 @@ return space.not_(self.descr_eq(space, w_other)) def descr_lt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + raise operationerrfmt(space.w_TypeError, + "Expected dict object, got %s", + space.str_w(space.str(space.type(w_other)))) + # Different sizes, no problem if self.length() < w_other.length(): return space.w_True @@ -1148,7 +1157,7 @@ w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) + w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) raise OperationError( space.w_TypeError, From noreply at buildbot.pypy.org Tue May 14 23:06:07 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 23:06:07 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Improve error message. Message-ID: <20130514210607.4FBA21C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64105:92250ea92f14 Date: 2013-05-14 23:03 +0200 http://bitbucket.org/pypy/pypy/changeset/92250ea92f14/ Log: Improve error message. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -114,7 +114,7 @@ if not isinstance(w_other, W_DictMultiObject): raise operationerrfmt(space.w_TypeError, "Expected dict object, got %s", - space.str_w(space.str(space.type(w_other)))) + space.type(w_other).getname(space)) if self.length() != w_other.length(): return space.w_False @@ -138,7 +138,7 @@ if not isinstance(w_other, W_DictMultiObject): raise operationerrfmt(space.w_TypeError, "Expected dict object, got %s", - space.str_w(space.str(space.type(w_other)))) + space.type(w_other).getname(space)) # Different sizes, no problem if self.length() < w_other.length(): From noreply at buildbot.pypy.org Tue May 14 23:31:34 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 14 May 2013 23:31:34 +0200 (CEST) Subject: [pypy-commit] pypy default: disable cpyext until annotation is fixed Message-ID: <20130514213134.28EE11C026D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64106:93c7444c99d9 Date: 2013-05-14 23:30 +0200 http://bitbucket.org/pypy/pypy/changeset/93c7444c99d9/ Log: disable cpyext until annotation is fixed diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,10 +32,11 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", - "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", + "thread", "itertools", "pyexpat", "_ssl", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_ffi", - "_continuation", "_cffi_backend", "_csv", "cppyy"] + "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"] +# disabled until problems are fixed )) translation_modules = default_modules.copy() From noreply at buildbot.pypy.org Tue May 14 23:45:54 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 23:45:54 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: hg merge default Message-ID: <20130514214554.9B4EB1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64107:7bc9f833a790 Date: 2013-05-14 23:40 +0200 http://bitbucket.org/pypy/pypy/changeset/7bc9f833a790/ Log: hg merge default diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,10 +32,11 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", - "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", + "thread", "itertools", "pyexpat", "_ssl", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_ffi", - "_continuation", "_cffi_backend", "_csv", "cppyy"] + "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"] +# disabled until problems are fixed )) translation_modules = default_modules.copy() From noreply at buildbot.pypy.org Tue May 14 23:45:55 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 14 May 2013 23:45:55 +0200 (CEST) Subject: [pypy-commit] pypy py3k: hg merge default Message-ID: <20130514214555.E017D1C1494@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: py3k Changeset: r64108:a20ff6733d15 Date: 2013-05-14 23:43 +0200 http://bitbucket.org/pypy/pypy/changeset/a20ff6733d15/ Log: hg merge default diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,12 +32,13 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_minimal_curses", - "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", + "thread", "itertools", "pyexpat", "_ssl", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "_ffi", "_continuation", "_csv", "_cffi_backend", "_posixsubprocess", # "cppyy", "micronumpy", ] +# disabled until problems are fixed )) translation_modules = default_modules.copy() From noreply at buildbot.pypy.org Wed May 15 00:03:19 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 00:03:19 +0200 (CEST) Subject: [pypy-commit] pypy default: always export pypy_debug_file Message-ID: <20130514220319.382611C23D0@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64109:9bbd1f33a8b6 Date: 2013-05-15 00:02 +0200 http://bitbucket.org/pypy/pypy/changeset/9bbd1f33a8b6/ Log: always export pypy_debug_file diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -259,7 +259,7 @@ if self.config.translation.shared: defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( - export_symbols=["pypy_main_startup"])) + export_symbols=["pypy_main_startup", "pypy_debug_file"])) self.eci, cfile, extra = gen_source(db, modulename, targetdir, self.eci, defines=defines, split=self.split) From noreply at buildbot.pypy.org Wed May 15 00:37:32 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 15 May 2013 00:37:32 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130514223732.D53071C009D@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64110:05c94aed1988 Date: 2013-05-14 15:37 -0700 http://bitbucket.org/pypy/pypy/changeset/05c94aed1988/ Log: merge default diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -259,7 +259,7 @@ if self.config.translation.shared: defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( - export_symbols=["pypy_main_startup"])) + export_symbols=["pypy_main_startup", "pypy_debug_file"])) self.eci, cfile, extra = gen_source(db, modulename, targetdir, self.eci, defines=defines, split=self.split) From noreply at buildbot.pypy.org Wed May 15 02:01:47 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 02:01:47 +0200 (CEST) Subject: [pypy-commit] pypy default: (brrt) expose add_memory_pressure Message-ID: <20130515000147.8C4251C1494@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64111:44b73d554c47 Date: 2013-05-15 02:00 +0200 http://bitbucket.org/pypy/pypy/changeset/44b73d554c47/ Log: (brrt) expose add_memory_pressure diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -55,6 +55,7 @@ 'validate_fd' : 'interp_magic.validate_fd', 'resizelist_hint' : 'interp_magic.resizelist_hint', 'newlist_hint' : 'interp_magic.newlist_hint', + 'add_memory_pressure' : 'interp_magic.add_memory_pressure', 'newdict' : 'interp_dict.newdict', 'dictstrategy' : 'interp_dict.dictstrategy', } diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -4,7 +4,7 @@ from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.typeobject import MethodCache from pypy.objspace.std.mapdict import IndexCache -from rpython.rlib import rposix +from rpython.rlib import rposix, rgc def internal_repr(space, w_object): @@ -100,3 +100,7 @@ @unwrap_spec(sizehint=int) def newlist_hint(space, sizehint): return space.newlist_hint(sizehint) + + at unwrap_spec(estimate=int) +def add_memory_pressure(estimate): + rgc.add_memory_pressure(estimate) From noreply at buildbot.pypy.org Wed May 15 09:19:10 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 09:19:10 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed test_in_squeak_4_5_image by saving some module variables which might change due to re-including in other tests in global variables (space, interp) Message-ID: <20130515071910.45F361C009D@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r384:d17bd059e09a Date: 2013-05-15 09:18 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/d17bd059e09a/ Log: fixed test_in_squeak_4_5_image by saving some module variables which might change due to re-including in other tests in global variables (space, interp) diff --git a/spyvm/test/test_in_squeak_4_5_image.py b/spyvm/test/test_in_squeak_4_5_image.py --- a/spyvm/test/test_in_squeak_4_5_image.py +++ b/spyvm/test/test_in_squeak_4_5_image.py @@ -5,6 +5,8 @@ from spyvm.test.test_miniimage import perform, w tools.setup_module(tools, filename='Squeak4.5-12568.image') +space = tools.space +interp = tools.interp def find_symbol_in_methoddict_of(string, s_class): s_methoddict = s_class.s_methoddict() @@ -26,11 +28,10 @@ w_method.tempsize = tempsize w_method.setliterals(literals) - s_method = w_method.as_compiledmethod_get_shadow(tools.space) + s_method = w_method.as_compiledmethod_get_shadow(space) return s_method def test_ensure(): - space = tools.space #ensure # [^'b1'] ensure: [^'b2'] import operator @@ -50,14 +51,13 @@ w_frame = s_method.create_frame(space, w(0), [], sender=s_initial_frame).w_self() try: - tools.interp.loop(w_frame) + interp.loop(w_frame) except interpreter.ReturnFromTopLevel, e: assert e.object.as_string() == 'b2' except interpreter.StackOverflow, e: assert False def test_ensure_save_original_nlr(): - space = tools.space #ensure # [^'b1'] ensure: ['b2'] import operator @@ -77,7 +77,7 @@ w_frame = s_method.create_frame(space, w(0), [], sender=s_initial_frame).w_self() try: - tools.interp.loop(w_frame) + interp.loop(w_frame) except interpreter.ReturnFromTopLevel, e: assert e.object.as_string() == 'b1' except interpreter.StackOverflow, e: From noreply at buildbot.pypy.org Wed May 15 10:11:57 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 10:11:57 +0200 (CEST) Subject: [pypy-commit] pypy default: This "fast path" is not any faster than the explicit loop below. Message-ID: <20130515081157.5EBDC1C146E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64112:c21a13690662 Date: 2013-05-15 10:11 +0200 http://bitbucket.org/pypy/pypy/changeset/c21a13690662/ Log: This "fast path" is not any faster than the explicit loop below. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -458,10 +458,6 @@ if (self.sign != other.sign or self.numdigits() != other.numdigits()): return False - - # Fast path. - if len(self._digits) == len(other._digits): - return self._digits == other._digits i = 0 ld = self.numdigits() From noreply at buildbot.pypy.org Wed May 15 10:20:18 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 15 May 2013 10:20:18 +0200 (CEST) Subject: [pypy-commit] lang-js default: fixed [].sort() and obj.put behaviour. Message-ID: <20130515082018.345C01C14F7@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r379:d3e475feac0c Date: 2013-05-13 00:49 -0300 http://bitbucket.org/pypy/lang-js/changeset/d3e475feac0c/ Log: fixed [].sort() and obj.put behaviour. diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,12 @@ from test.test_interp import assertv, assertp +def test_sort(capsys): + assertp("var x = [5,2]; print(x.sort());", '2,5', capsys) + assertp("var x = [1,2,3]; print(x.sort());", '1,2,3', capsys) + assertp("var x = [4,3,2,1]; print(x.sort());", '1,2,3,4', capsys) + + def test_array_push(capsys): assertv("var x = []; x.push(42); x.length;", 1) assertv("var x = []; x.push(42); x[0];", 42) diff --git a/test/test_w_array.py b/test/test_w_array.py --- a/test/test_w_array.py +++ b/test/test_w_array.py @@ -3,6 +3,14 @@ from js.object_space import _w +def test_array_put_change_index(): + a = W__Array() + a.put(u'0', 42) + assert a.get(u'0') == 42 + a.put(u'0', 43) + assert a.get(u'0') == 43 + + def test_array_get(): a = W__Array() a._set_prop(u'23', DataProperty(42, True, True, True)) From noreply at buildbot.pypy.org Wed May 15 10:20:19 2013 From: noreply at buildbot.pypy.org (stepahn) Date: Wed, 15 May 2013 10:20:19 +0200 (CEST) Subject: [pypy-commit] lang-js default: Fixed a but in optimized array member access. Message-ID: <20130515082019.7291F1C14F7@cobra.cs.uni-duesseldorf.de> Author: Stephan Branch: Changeset: r380:96c04922c1ef Date: 2013-05-15 10:19 +0200 http://bitbucket.org/pypy/lang-js/changeset/96c04922c1ef/ Log: Fixed a but in optimized array member access. Thanks to Andrews Medina https://bitbucket.org/andrewsmedina for finding and supplying tests for it. diff --git a/js/jsobj.py b/js/jsobj.py --- a/js/jsobj.py +++ b/js/jsobj.py @@ -1484,6 +1484,9 @@ return Descr(inherited.writable, None, inherited, prop) def _define_own_idx_property(self, idx, desc, throw=False, current_desc=None, prop=None): + if current_desc is None: + current_desc = self._get_idx_property(idx) + from js.object_space import _w old_len_desc = self.get_own_property(u'length') assert old_len_desc is not None @@ -1595,6 +1598,7 @@ if desc.has_set_getter() and desc.getter != current.getter: return _ireject(throw, idx) # 12 + prop = self._get_iprop(idx) prop.update_with_descriptor(desc) # 13 @@ -1612,12 +1616,13 @@ # 15.4.5.1 def define_own_property(self, p, desc, throw=False): from js.object_space import _w - old_len_desc = self.get_own_property(u'length') - assert old_len_desc is not None - old_len = old_len_desc.value.ToUInt32() # 3 if p == u'length': + old_len_desc = self.get_own_property(u'length') + assert old_len_desc is not None + old_len = old_len_desc.value.ToUInt32() + if desc.has_set_value() is False: return W_BasicObject.define_own_property(self, u'length', desc, throw) new_len_desc = desc.copy() From noreply at buildbot.pypy.org Wed May 15 10:26:48 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 15 May 2013 10:26:48 +0200 (CEST) Subject: [pypy-commit] lang-js default: implemented [].indexOf and [].forEach Message-ID: <20130515082648.33BCB1C02E4@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r381:bf3bd88b2861 Date: 2013-05-15 01:29 -0300 http://bitbucket.org/pypy/lang-js/changeset/bf3bd88b2861/ Log: implemented [].indexOf and [].forEach diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -40,6 +40,10 @@ # 15.4.4.11 put_native_function(w_ArrayPrototype, u'sort', sort) + put_native_function(w_ArrayPrototype, u'forEach', for_each) + + put_native_function(w_ArrayPrototype, u'indexOf', index_of) + # 15.4.4.7 @w_return @@ -162,6 +166,34 @@ lower = lower + 1 + at w_return +def index_of(this, args): + obj = this + length = this.get(u'length').ToUInt32() + elem = get_arg(args, 0) + from_index = get_arg(args, 1).ToUInt32() + + from js.jsobj import W_IntNumber + for i in xrange(from_index, length): + y = obj.get(unicode(i)) + if elem == y: + return W_IntNumber(i) + return W_IntNumber(-1) + + +def for_each(this, args): + obj = this + length = this.get(u'length').ToUInt32() + + callback = get_arg(args, 0) + from js.jsobj import W_BasicFunction + assert isinstance(callback, W_BasicFunction) + + for i in xrange(length): + x = obj.get(unicode(str(i))) + callback.Call(args=[x], this=newundefined()) + + # 15.4.4.11 @w_return def sort(this, args): diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,18 @@ from test.test_interp import assertv, assertp +def test_array_index_of(capsys): + assertp("var a = [1,2,3]; print(a.indexOf(1));", "0", capsys) + assertp("var a = [1,2,3]; print(a.indexOf(3));", "2", capsys) + assertp("var a = [1,2,3]; print(a.indexOf(5));", "-1", capsys) + assertp("var a = [1,2,3,1]; print(a.indexOf(1,2));", "3", capsys) + assertp("var a = [1,2,3,1]; print(a.indexOf(1,5));", "-1", capsys) + + +def test_array_foreach(capsys): + assertp("var a = [1,2,3]; var b = []; a.forEach(function(v){b.push(v*2)}); print(b);", "2,4,6", capsys) + + def test_sort(capsys): assertp("var x = [5,2]; print(x.sort());", '2,5', capsys) assertp("var x = [1,2,3]; print(x.sort());", '1,2,3', capsys) From noreply at buildbot.pypy.org Wed May 15 10:29:46 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 10:29:46 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: moved image loading to setup method Message-ID: <20130515082946.9DF791C14F7@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r385:b720ba90f384 Date: 2013-05-15 10:29 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/b720ba90f384/ Log: moved image loading to setup method diff --git a/spyvm/test/test_bootstrappedimage.py b/spyvm/test/test_bootstrappedimage.py --- a/spyvm/test/test_bootstrappedimage.py +++ b/spyvm/test/test_bootstrappedimage.py @@ -2,9 +2,9 @@ from spyvm import squeakimage, model, constants from spyvm import interpreter, shadow, objspace from spyvm.test import test_miniimage as tools -from spyvm.test.test_miniimage import perform, w -tools.setup_module(tools, filename='bootstrapped.image') +def setup(): + tools.setup_module(tools, filename='bootstrapped.image') def find_symbol_in_methoddict_of(string, s_class): s_methoddict = s_class.s_methoddict() @@ -17,19 +17,19 @@ def initialize_class(w_class): initialize_symbol = find_symbol_in_methoddict_of("initialize", w_class.shadow_of_my_class(tools.space)) - perform(w_class, initialize_symbol) + tools.perform(w_class, initialize_symbol) def test_initialize_string_class(): #initialize String class, because equality testing requires a class var set. - initialize_class(w("string").getclass(tools.space)) + initialize_class(tools.w("string").getclass(tools.space)) def test_symbol_asSymbol(): - w_result = perform(tools.image.w_asSymbol, "asSymbol") + w_result = tools.perform(tools.image.w_asSymbol, "asSymbol") assert w_result is tools.image.w_asSymbol def test_create_new_symbol(): py.test.skip("This test takes quite long and is actually included in test_retrieve_symbol.") - w_result = perform(w("someString"), "asSymbol") + w_result = tools.perform(tools.w("someString"), "asSymbol") assert w_result is not None assert w_result.as_string() == "someString" @@ -42,11 +42,10 @@ self = sym ifTrue: [ ^ sym ] ]. ^ (Symbol basicNew: self size) initFrom: self""" - w_result = perform(w("someString"), "asSymbol") + w_result = tools.perform(tools.w("someString"), "asSymbol") assert w_result.as_string() == "someString" - w_anotherSymbol = perform(w("someString"), "asSymbol") + w_anotherSymbol = tools.perform(tools.w("someString"), "asSymbol") assert w_result is w_anotherSymbol -def test_all_pointers_are_valid(): - tools.test_all_pointers_are_valid() - tools.test_lookup_abs_in_integer() +test_all_pointers_are_valid = tools.test_all_pointers_are_valid +test_lookup_abs_in_integer = tools.test_lookup_abs_in_integer diff --git a/spyvm/test/test_in_squeak_4_5_image.py b/spyvm/test/test_in_squeak_4_5_image.py --- a/spyvm/test/test_in_squeak_4_5_image.py +++ b/spyvm/test/test_in_squeak_4_5_image.py @@ -2,11 +2,12 @@ from spyvm import squeakimage, model, constants from spyvm import interpreter, shadow, objspace from spyvm.test import test_miniimage as tools -from spyvm.test.test_miniimage import perform, w +from spyvm.test.test_miniimage import w -tools.setup_module(tools, filename='Squeak4.5-12568.image') -space = tools.space -interp = tools.interp +def setup(): + tools.setup_module(tools, filename='Squeak4.5-12568.image') + global space = tools.space + global interp = tools.interp def find_symbol_in_methoddict_of(string, s_class): s_methoddict = s_class.s_methoddict() From noreply at buildbot.pypy.org Wed May 15 10:31:20 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 10:31:20 +0200 (CEST) Subject: [pypy-commit] pypy default: Like CPython, avoid returning negative numbers in "id()". We might Message-ID: <20130515083120.2D9921C14F7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64113:86a56a160503 Date: 2013-05-15 10:29 +0200 http://bitbucket.org/pypy/pypy/changeset/86a56a160503/ Log: Like CPython, avoid returning negative numbers in "id()". We might still return negative numbers for id() of ints/longs/floats/complexes but I'm not sure we care too much about that. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -666,7 +666,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): From noreply at buildbot.pypy.org Wed May 15 10:42:16 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 10:42:16 +0200 (CEST) Subject: [pypy-commit] pypy default: import test_del to arm Message-ID: <20130515084216.9CBB61C009D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64114:a16942418e07 Date: 2013-05-15 10:08 +0200 http://bitbucket.org/pypy/pypy/changeset/a16942418e07/ Log: import test_del to arm diff --git a/rpython/jit/backend/x86/test/test_del.py b/rpython/jit/backend/arm/test/test_del.py copy from rpython/jit/backend/x86/test/test_del.py copy to rpython/jit/backend/arm/test/test_del.py --- a/rpython/jit/backend/x86/test/test_del.py +++ b/rpython/jit/backend/arm/test/test_del.py @@ -1,8 +1,8 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_del import DelTests -class TestDel(Jit386Mixin, DelTests): +class TestDel(JitARMMixin, DelTests): # for the individual tests see # ====> ../../../metainterp/test/test_del.py pass From noreply at buildbot.pypy.org Wed May 15 10:42:17 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 10:42:17 +0200 (CEST) Subject: [pypy-commit] pypy default: import test_dict to arm Message-ID: <20130515084217.C923E1C1106@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64115:1f6df60dfe27 Date: 2013-05-15 10:12 +0200 http://bitbucket.org/pypy/pypy/changeset/1f6df60dfe27/ Log: import test_dict to arm diff --git a/rpython/jit/backend/x86/test/test_dict.py b/rpython/jit/backend/arm/test/test_dict.py copy from rpython/jit/backend/x86/test/test_dict.py copy to rpython/jit/backend/arm/test/test_dict.py --- a/rpython/jit/backend/x86/test/test_dict.py +++ b/rpython/jit/backend/arm/test/test_dict.py @@ -1,9 +1,9 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_dict import DictTests -class TestDict(Jit386Mixin, DictTests): +class TestDict(JitARMMixin, DictTests): # for the individual tests see # ====> ../../../metainterp/test/test_dict.py pass From noreply at buildbot.pypy.org Wed May 15 10:42:19 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 10:42:19 +0200 (CEST) Subject: [pypy-commit] pypy default: import test_quasiimmut to arm Message-ID: <20130515084219.2C78D1C009D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64116:e455c2b1a392 Date: 2013-05-15 10:37 +0200 http://bitbucket.org/pypy/pypy/changeset/e455c2b1a392/ Log: import test_quasiimmut to arm diff --git a/rpython/jit/backend/x86/test/test_quasiimmut.py b/rpython/jit/backend/arm/test/test_quasiimmut.py copy from rpython/jit/backend/x86/test/test_quasiimmut.py copy to rpython/jit/backend/arm/test/test_quasiimmut.py --- a/rpython/jit/backend/x86/test/test_quasiimmut.py +++ b/rpython/jit/backend/arm/test/test_quasiimmut.py @@ -1,9 +1,9 @@ import py -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test import test_quasiimmut -class TestLoopSpec(Jit386Mixin, test_quasiimmut.QuasiImmutTests): +class TestLoopSpec(JitARMMixin, test_quasiimmut.QuasiImmutTests): # for the individual tests see # ====> ../../../metainterp/test/test_loop.py pass From noreply at buildbot.pypy.org Wed May 15 10:42:20 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 10:42:20 +0200 (CEST) Subject: [pypy-commit] pypy default: import test_rawmem to arm Message-ID: <20130515084220.4DA901C009D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64117:c380fde95d2f Date: 2013-05-15 10:40 +0200 http://bitbucket.org/pypy/pypy/changeset/c380fde95d2f/ Log: import test_rawmem to arm diff --git a/rpython/jit/backend/x86/test/test_rawmem.py b/rpython/jit/backend/arm/test/test_rawmem.py copy from rpython/jit/backend/x86/test/test_rawmem.py copy to rpython/jit/backend/arm/test/test_rawmem.py --- a/rpython/jit/backend/x86/test/test_rawmem.py +++ b/rpython/jit/backend/arm/test/test_rawmem.py @@ -1,9 +1,9 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_rawmem import RawMemTests -class TestRawMem(Jit386Mixin, RawMemTests): +class TestRawMem(JitARMMixin, RawMemTests): # for the individual tests see # ====> ../../../metainterp/test/test_rawmem.py pass From noreply at buildbot.pypy.org Wed May 15 10:42:21 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 10:42:21 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130515084221.7BBD31C009D@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64118:e980bdaef1cb Date: 2013-05-15 10:41 +0200 http://bitbucket.org/pypy/pypy/changeset/e980bdaef1cb/ Log: merge heads diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -666,7 +666,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -458,10 +458,6 @@ if (self.sign != other.sign or self.numdigits() != other.numdigits()): return False - - # Fast path. - if len(self._digits) == len(other._digits): - return self._digits == other._digits i = 0 ld = self.numdigits() From noreply at buildbot.pypy.org Wed May 15 10:46:24 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 10:46:24 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Like CPython, avoid returning negative numbers in "id()". We might Message-ID: <20130515084624.77FD41C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64119:128e78d6a11a Date: 2013-05-15 10:29 +0200 http://bitbucket.org/pypy/pypy/changeset/128e78d6a11a/ Log: Like CPython, avoid returning negative numbers in "id()". We might still return negative numbers for id() of ints/longs/floats/complexes but I'm not sure we care too much about that. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -666,7 +666,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): From noreply at buildbot.pypy.org Wed May 15 11:23:53 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 11:23:53 +0200 (CEST) Subject: [pypy-commit] pypy callback-stacklet: A branch to attempt to fix stacklets in the presence of C callbacks. Message-ID: <20130515092353.AB2A51C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: callback-stacklet Changeset: r64120:99f39bca4c09 Date: 2013-05-15 10:14 +0200 http://bitbucket.org/pypy/pypy/changeset/99f39bca4c09/ Log: A branch to attempt to fix stacklets in the presence of C callbacks. From noreply at buildbot.pypy.org Wed May 15 11:23:55 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 11:23:55 +0200 (CEST) Subject: [pypy-commit] pypy callback-stacklet: Add a test with a C callback. It works on shadowstack but fails on asmgcc. Message-ID: <20130515092355.2AD371C1106@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: callback-stacklet Changeset: r64121:de418ba565b4 Date: 2013-05-15 11:22 +0200 http://bitbucket.org/pypy/pypy/changeset/de418ba565b4/ Log: Add a test with a C callback. It works on shadowstack but fails on asmgcc. diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -82,6 +82,29 @@ return True return False + @here_is_a_test + def test_c_callback(self): + # + self.steps = [0] + self.main_h = self.sthread.new(cb_stacklet_callback, llmemory.NULL) + self.steps.append(2) + call_qsort_rec(10) + self.steps.append(9) + assert not self.sthread.is_empty_handle(self.main_h) + self.main_h = self.sthread.switch(self.main_h) + assert self.sthread.is_empty_handle(self.main_h) + # + # check that self.steps == [0,1,2, 3,4,5,6, 3,4,5,6, 3,4,5,6,..., 9] + print self.steps + expected = 0 + assert self.steps[-1] == 9 + for i in range(len(self.steps)-1): + if expected == 7: + expected = 3 + assert self.steps[i] == expected + expected += 1 + assert expected == 7 + class FooObj: def __init__(self, n, d, next=None): @@ -211,6 +234,43 @@ print "LEAVING %d to go to %d" % (self.n, n) return h +QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType( + [llmemory.Address, llmemory.Address], rffi.INT)) +qsort = rffi.llexternal('qsort', + [llmemory.Address, rffi.SIZE_T, rffi.SIZE_T, + QSORT_CALLBACK_PTR], + lltype.Void) +def cb_compare_callback(a, b): + runner.steps.append(3) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.main_h = runner.sthread.switch(runner.main_h) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.steps.append(6) + return rffi.cast(rffi.INT, 1) +def cb_stacklet_callback(h, arg): + runner.steps.append(1) + while True: + assert not runner.sthread.is_empty_handle(h) + h = runner.sthread.switch(h) + assert not runner.sthread.is_empty_handle(h) + if runner.steps[-1] == 9: + return h + runner.steps.append(4) + rgc.collect() + runner.steps.append(5) +class GcObject(object): + num = 1234 +def call_qsort_rec(r): + if r > 0: + g = GcObject() + g.num += r + call_qsort_rec(r - 1) + assert g.num == 1234 + r + else: + raw = llmemory.raw_malloc(5) + qsort(raw, 5, 1, cb_compare_callback) + llmemory.raw_free(raw) + def entry_point(argv): seed = 0 From noreply at buildbot.pypy.org Wed May 15 11:43:40 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 11:43:40 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: renamed 4_5 image test to be executed last Message-ID: <20130515094340.CB7CF1C1306@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r386:c3327f072a4f Date: 2013-05-15 11:19 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/c3327f072a4f/ Log: renamed 4_5 image test to be executed last diff --git a/spyvm/test/test_in_squeak_4_5_image.py b/spyvm/test/testsin_squeak_4_5_image.py rename from spyvm/test/test_in_squeak_4_5_image.py rename to spyvm/test/testsin_squeak_4_5_image.py --- a/spyvm/test/test_in_squeak_4_5_image.py +++ b/spyvm/test/testsin_squeak_4_5_image.py @@ -6,8 +6,10 @@ def setup(): tools.setup_module(tools, filename='Squeak4.5-12568.image') - global space = tools.space - global interp = tools.interp + global space + global interp + space = tools.space + interp = tools.interp def find_symbol_in_methoddict_of(string, s_class): s_methoddict = s_class.s_methoddict() From noreply at buildbot.pypy.org Wed May 15 11:43:41 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 11:43:41 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fix for tests when exectued on pypy Message-ID: <20130515094341.E71E61C1306@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r387:ab85ac96fff8 Date: 2013-05-15 09:39 +0000 http://bitbucket.org/pypy/lang-smalltalk/changeset/ab85ac96fff8/ Log: fix for tests when exectued on pypy diff --git a/spyvm/test/test_model.py b/spyvm/test/test_model.py --- a/spyvm/test/test_model.py +++ b/spyvm/test/test_model.py @@ -330,4 +330,7 @@ assert weak_object.fetch(space, 0) is referenced del referenced + # When executed using pypy, del is not immediately executed. + # Thus the reference may linger until the next gc... + import gc; gc.collect() assert weak_object.fetch(space, 0) is space.w_nil From noreply at buildbot.pypy.org Wed May 15 11:43:42 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 11:43:42 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: unrolled some of the changes to test_bootstrapped Message-ID: <20130515094342.F05431C1306@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r388:d03aebb38b8d Date: 2013-05-15 11:43 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/d03aebb38b8d/ Log: unrolled some of the changes to test_bootstrapped diff --git a/spyvm/test/test_bootstrappedimage.py b/spyvm/test/test_bootstrappedimage.py --- a/spyvm/test/test_bootstrappedimage.py +++ b/spyvm/test/test_bootstrappedimage.py @@ -2,6 +2,7 @@ from spyvm import squeakimage, model, constants from spyvm import interpreter, shadow, objspace from spyvm.test import test_miniimage as tools +from spyvm.test.test_miniimage import perform, w def setup(): tools.setup_module(tools, filename='bootstrapped.image') @@ -17,19 +18,19 @@ def initialize_class(w_class): initialize_symbol = find_symbol_in_methoddict_of("initialize", w_class.shadow_of_my_class(tools.space)) - tools.perform(w_class, initialize_symbol) + perform(w_class, initialize_symbol) def test_initialize_string_class(): #initialize String class, because equality testing requires a class var set. - initialize_class(tools.w("string").getclass(tools.space)) + initialize_class(w("string").getclass(tools.space)) def test_symbol_asSymbol(): - w_result = tools.perform(tools.image.w_asSymbol, "asSymbol") + w_result = perform(tools.image.w_asSymbol, "asSymbol") assert w_result is tools.image.w_asSymbol def test_create_new_symbol(): py.test.skip("This test takes quite long and is actually included in test_retrieve_symbol.") - w_result = tools.perform(tools.w("someString"), "asSymbol") + w_result = perform(w("someString"), "asSymbol") assert w_result is not None assert w_result.as_string() == "someString" @@ -42,10 +43,11 @@ self = sym ifTrue: [ ^ sym ] ]. ^ (Symbol basicNew: self size) initFrom: self""" - w_result = tools.perform(tools.w("someString"), "asSymbol") + w_result = perform(w("someString"), "asSymbol") assert w_result.as_string() == "someString" - w_anotherSymbol = tools.perform(tools.w("someString"), "asSymbol") + w_anotherSymbol = perform(w("someString"), "asSymbol") assert w_result is w_anotherSymbol -test_all_pointers_are_valid = tools.test_all_pointers_are_valid -test_lookup_abs_in_integer = tools.test_lookup_abs_in_integer +def test_all_pointers_are_valid(): + tools.test_all_pointers_are_valid() + tools.test_lookup_abs_in_integer() From noreply at buildbot.pypy.org Wed May 15 13:03:25 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 13:03:25 +0200 (CEST) Subject: [pypy-commit] pypy default: make this test read from a word-aligned location Message-ID: <20130515110325.269CF1C1306@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64122:04721409e7a3 Date: 2013-05-15 12:47 +0200 http://bitbucket.org/pypy/pypy/changeset/04721409e7a3/ Log: make this test read from a word-aligned location diff --git a/rpython/jit/metainterp/test/test_rawmem.py b/rpython/jit/metainterp/test/test_rawmem.py --- a/rpython/jit/metainterp/test/test_rawmem.py +++ b/rpython/jit/metainterp/test/test_rawmem.py @@ -48,8 +48,8 @@ def test_raw_storage_float(self): def f(): p = alloc_raw_storage(15) - raw_storage_setitem(p, 3, 2.4e15) - res = raw_storage_getitem(lltype.Float, p, 3) + raw_storage_setitem(p, 4, 2.4e15) + res = raw_storage_getitem(lltype.Float, p, 4) free_raw_storage(p) return res res = self.interp_operations(f, []) From noreply at buildbot.pypy.org Wed May 15 13:03:26 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 13:03:26 +0200 (CEST) Subject: [pypy-commit] pypy default: import test_send to arm Message-ID: <20130515110326.654BD1C02E4@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64123:6867449dfeae Date: 2013-05-15 12:51 +0200 http://bitbucket.org/pypy/pypy/changeset/6867449dfeae/ Log: import test_send to arm diff --git a/rpython/jit/backend/x86/test/test_send.py b/rpython/jit/backend/arm/test/test_send.py copy from rpython/jit/backend/x86/test/test_send.py copy to rpython/jit/backend/arm/test/test_send.py --- a/rpython/jit/backend/x86/test/test_send.py +++ b/rpython/jit/backend/arm/test/test_send.py @@ -1,10 +1,10 @@ import py from rpython.jit.metainterp.test.test_send import SendTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.rlib import jit -class TestSend(Jit386Mixin, SendTests): +class TestSend(JitARMMixin, SendTests): # for the individual tests see # ====> ../../../metainterp/test/test_send.py def test_call_with_additional_args(self): From noreply at buildbot.pypy.org Wed May 15 13:03:27 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 15 May 2013 13:03:27 +0200 (CEST) Subject: [pypy-commit] pypy default: import some more tests Message-ID: <20130515110327.851AE1C02E4@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64124:eebf90f8ca5e Date: 2013-05-15 13:02 +0200 http://bitbucket.org/pypy/pypy/changeset/eebf90f8ca5e/ Log: import some more tests diff --git a/rpython/jit/backend/x86/test/test_slist.py b/rpython/jit/backend/arm/test/test_slist.py copy from rpython/jit/backend/x86/test/test_slist.py copy to rpython/jit/backend/arm/test/test_slist.py --- a/rpython/jit/backend/x86/test/test_slist.py +++ b/rpython/jit/backend/arm/test/test_slist.py @@ -1,8 +1,8 @@ import py from rpython.jit.metainterp.test import test_slist -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestSList(Jit386Mixin, test_slist.ListTests): +class TestSList(JitARMMixin, test_slist.ListTests): # for the individual tests see # ====> ../../../metainterp/test/test_slist.py def test_list_of_voids(self): diff --git a/rpython/jit/backend/x86/test/test_tl.py b/rpython/jit/backend/arm/test/test_tl.py copy from rpython/jit/backend/x86/test/test_tl.py copy to rpython/jit/backend/arm/test/test_tl.py --- a/rpython/jit/backend/x86/test/test_tl.py +++ b/rpython/jit/backend/arm/test/test_tl.py @@ -1,9 +1,9 @@ import py from rpython.jit.metainterp.test.test_tl import ToyLanguageTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestTL(Jit386Mixin, ToyLanguageTests): +class TestTL(JitARMMixin, ToyLanguageTests): # for the individual tests see # ====> ../../../metainterp/test/test_tl.py pass diff --git a/rpython/jit/backend/x86/test/test_tlc.py b/rpython/jit/backend/arm/test/test_tlc.py copy from rpython/jit/backend/x86/test/test_tlc.py copy to rpython/jit/backend/arm/test/test_tlc.py --- a/rpython/jit/backend/x86/test/test_tlc.py +++ b/rpython/jit/backend/arm/test/test_tlc.py @@ -1,10 +1,10 @@ import py -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_tlc import TLCTests from rpython.jit.tl import tlc -class TestTL(Jit386Mixin, TLCTests): +class TestTL(JitARMMixin, TLCTests): # for the individual tests see # ====> ../../test/test_tlc.py diff --git a/rpython/jit/backend/x86/test/test_virtual.py b/rpython/jit/backend/arm/test/test_virtual.py copy from rpython/jit/backend/x86/test/test_virtual.py copy to rpython/jit/backend/arm/test/test_virtual.py --- a/rpython/jit/backend/x86/test/test_virtual.py +++ b/rpython/jit/backend/arm/test/test_virtual.py @@ -1,10 +1,10 @@ from rpython.jit.metainterp.test.test_virtual import VirtualTests, VirtualMiscTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin class MyClass: pass -class TestsVirtual(Jit386Mixin, VirtualTests): +class TestsVirtual(JitARMMixin, VirtualTests): # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py _new_op = 'new_with_vtable' @@ -14,7 +14,7 @@ def _new(): return MyClass() -class TestsVirtualMisc(Jit386Mixin, VirtualMiscTests): +class TestsVirtualMisc(JitARMMixin, VirtualMiscTests): # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py pass diff --git a/rpython/jit/backend/x86/test/test_virtualizable.py b/rpython/jit/backend/arm/test/test_virtualizable.py copy from rpython/jit/backend/x86/test/test_virtualizable.py copy to rpython/jit/backend/arm/test/test_virtualizable.py --- a/rpython/jit/backend/x86/test/test_virtualizable.py +++ b/rpython/jit/backend/arm/test/test_virtualizable.py @@ -1,8 +1,8 @@ import py from rpython.jit.metainterp.test.test_virtualizable import ImplicitVirtualizableTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestVirtualizable(Jit386Mixin, ImplicitVirtualizableTests): +class TestVirtualizable(JitARMMixin, ImplicitVirtualizableTests): def test_blackhole_should_not_reenter(self): py.test.skip("Assertion error & llinterp mess") diff --git a/rpython/jit/backend/x86/test/test_virtualref.py b/rpython/jit/backend/arm/test/test_virtualref.py copy from rpython/jit/backend/x86/test/test_virtualref.py copy to rpython/jit/backend/arm/test/test_virtualref.py --- a/rpython/jit/backend/x86/test/test_virtualref.py +++ b/rpython/jit/backend/arm/test/test_virtualref.py @@ -1,8 +1,8 @@ from rpython.jit.metainterp.test.test_virtualref import VRefTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestVRef(Jit386Mixin, VRefTests): +class TestVRef(JitARMMixin, VRefTests): # for the individual tests see # ====> ../../../metainterp/test/test_virtualref.py pass From noreply at buildbot.pypy.org Wed May 15 13:31:08 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 13:31:08 +0200 (CEST) Subject: [pypy-commit] pypy callback-stacklet: in-progress Message-ID: <20130515113108.B23151C009D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: callback-stacklet Changeset: r64125:43633e9da628 Date: 2013-05-15 13:30 +0200 http://bitbucket.org/pypy/pypy/changeset/43633e9da628/ Log: in-progress diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -172,10 +172,45 @@ self.gctransformer = gctransformer def need_stacklet_support(self, gctransformer, getfn): + from rpython.annotator import model as annmodel + from rpython.rlib import _stacklet_asmgcc # stacklet support: BIG HACK for rlib.rstacklet - from rpython.rlib import _stacklet_asmgcc _stacklet_asmgcc._asmstackrootwalker = self # as a global! argh _stacklet_asmgcc.complete_destrptr(gctransformer) + # + def gc_detach_callback_pieces(): + # XXX use belongs_to_current_thread() below + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + initialframedata = anchor.address[1] + if initialframedata == anchor: + return llmemory.NULL # empty + lastframedata = anchor.address[0] + lastframedata.address[1] = llmemory.NULL + initialframedata.address[0] = llmemory.NULL + anchor.address[0] = anchor + anchor.address[1] = anchor + return initialframedata + # + def gc_reattach_callback_pieces(pieces): + ll_assert(pieces != llmemory.NULL, "should not be called if NULL") + ll_assert(pieces.address[0] == llmemory.NULL, + "not a correctly detached stack piece") + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + lastpiece = pieces + while lastpiece.address[1]: + lastpiece = lastpiece.address[1] + anchor_next = anchor.address[1] + lastpiece.address[1] = anchor_next + pieces.address[0] = anchor + anchor.address[1] = pieces + anchor_next.address[0] = lastpiece + # + s_addr = annmodel.SomeAddress() + s_None = annmodel.s_None + self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces, + [], s_addr) + self.gc_reattach_callback_pieces_ptr=getfn(gc_reattach_callback_pieces, + [s_addr], s_None) def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -800,6 +800,21 @@ def gct_gc_adr_of_root_stack_top(self, hop): self._gc_adr_of_gcdata_attr(hop, 'root_stack_top') + def gct_gc_detach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 0 + hop.genop("direct_call", + [self.root_walker.gc_detach_callback_pieces_ptr], + resultvar=op.result) + + def gct_gc_reattach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 1 + hop.genop("direct_call", + [self.root_walker.gc_reattach_callback_pieces_ptr, + op.args[0]], + resultvar=op.result) + def gct_gc_shadowstackref_new(self, hop): op = hop.spaceop livevars = self.push_roots(hop) diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -32,6 +32,7 @@ if not p.handle: return False self.context = llmemory.cast_ptr_to_adr(p.handle) + self.next_callback_piece = p.callback_pieces anchor = p.anchor del p self.curframe = lltype.malloc(WALKFRAME, flavor='raw') @@ -50,11 +51,17 @@ retaddraddr = self.translateptr(retaddraddr) curframe.frame_address = retaddraddr.address[0] - def teardown(self): - lltype.free(self.curframe, flavor='raw') - lltype.free(self.otherframe, flavor='raw') - self.context = llmemory.NULL - return llmemory.NULL + def fetch_next_stack_piece(self): + if self.next_callback_piece == llmemory.NULL: + lltype.free(self.curframe, flavor='raw') + lltype.free(self.otherframe, flavor='raw') + self.context = llmemory.NULL + return False + else: + anchor = self.next_callback_piece + self.next_callback_piece = anchor.address[1] # next + self.fill_initial_frame(self.curframe, anchor) + return True def next(self, obj, prev): # @@ -117,7 +124,10 @@ location) # ^^^ non-translated if caller.frame_address == llmemory.NULL: - return self.teardown() # completely done with this stack + # completely done with this piece of stack + if not self.fetch_next_stack_piece(): + return llmemory.NULL + continue # self.otherframe = callee self.curframe = caller @@ -154,6 +164,7 @@ SUSPSTACK = lltype.GcStruct('SuspStack', ('handle', _c.handle), ('anchor', llmemory.Address), + ('callback_pieces', llmemory.Address), rtti=True) NULL_SUSPSTACK = lltype.nullptr(SUSPSTACK) CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], @@ -197,6 +208,8 @@ gcrootfinder.suspstack.anchor = stackanchor alternateanchor.prev = alternateanchor alternateanchor.next = alternateanchor + gcrootfinder.suspstack.callback_pieces = ( + llop.gc_detach_callback_pieces(llmemory.Address)) def _new_runfn(h, _): # Here, we are in a fresh new stacklet. @@ -250,6 +263,7 @@ # make a fresh new clean SUSPSTACK newsuspstack = lltype.malloc(SUSPSTACK) newsuspstack.handle = _c.null_handle + newsuspstack.callback_pieces = llmemory.NULL self.suspstack = newsuspstack # Invoke '_new_callback' by closing the stack h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback), @@ -274,6 +288,10 @@ # # Return from a new() or a switch(): 'h' is a handle, possibly # an empty one, that says from where we switched to. + if self.suspstack and self.suspstack.callback_pieces: + llop.gc_reattach_callback_pieces(lltype.Void, + self.suspstack.callback_pieces) + self.suspstack.callback_pieces = llmemory.NULL if not h: raise MemoryError elif _c.is_empty_handle(h): diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -886,6 +886,11 @@ def op_gc_stack_bottom(self): pass # marker for trackgcroot.py + def op_gc_detach_callback_pieces(self): + raise NotImplementedError("gc_detach_callback_pieces") + def op_gc_reattach_callback_pieces(self): + raise NotImplementedError("gc_reattach_callback_pieces") + def op_gc_shadowstackref_new(self): # stacklet+shadowstack raise NotImplementedError("gc_shadowstackref_new") def op_gc_shadowstackref_context(self): diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py --- a/rpython/rtyper/lltypesystem/lloperation.py +++ b/rpython/rtyper/lltypesystem/lloperation.py @@ -516,6 +516,10 @@ 'gc_asmgcroot_static': LLOp(sideeffects=False), 'gc_stack_bottom': LLOp(canrun=True), + # for stacklet+asmgcroot support + 'gc_detach_callback_pieces': LLOp(), + 'gc_reattach_callback_pieces': LLOp(), + # for stacklet+shadowstack support 'gc_shadowstackref_new': LLOp(canmallocgc=True), 'gc_shadowstackref_context': LLOp(), From noreply at buildbot.pypy.org Wed May 15 13:52:21 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 13:52:21 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: deactivated someInstance, nextInstance tests for now, because they seem to stop the execution on ci Message-ID: <20130515115221.B85FA1C009D@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r389:852cfcb1edc3 Date: 2013-05-15 13:52 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/852cfcb1edc3/ Log: deactivated someInstance, nextInstance tests for now, because they seem to stop the execution on ci diff --git a/spyvm/test/test_miniimage.py b/spyvm/test/test_miniimage.py --- a/spyvm/test/test_miniimage.py +++ b/spyvm/test/test_miniimage.py @@ -193,10 +193,10 @@ def test_lookup_abs_in_integer(): + w_abs = interp.perform(w("abs"), "asSymbol") for value in [10, -3, 0]: - w_object = model.W_SmallInteger(value) - w_res = interp.perform(w_object, "abs") + w_res = interp.perform(w_object, w_abs) assert w_res.value == abs(value) diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py --- a/spyvm/test/test_primitives.py +++ b/spyvm/test/test_primitives.py @@ -616,11 +616,14 @@ assert s_new_context.gettemp(2).as_string() == "some value" def test_primitive_some_instance(): + py.test.skip('Takes too long.') + import gc; gc.collect() someInstance = map(space.wrap_list, [[1], [2]]) w_r = prim(primitives.SOME_INSTANCE, [space.w_Array]) assert w_r.getclass(space) is space.w_Array def test_primitive_next_instance(): + py.test.skip('Takes too long.') someInstances = map(space.wrap_list, [[2], [3]]) from test_interpreter import new_frame w_frame, s_context = new_frame("", From noreply at buildbot.pypy.org Wed May 15 14:00:57 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:00:57 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove all non-operator SMMs of set/frozenset. Own tests / translation / CPython's tests work. Message-ID: <20130515120057.ECACA1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64126:a6c689102654 Date: 2013-05-15 10:43 +0200 http://bitbucket.org/pypy/pypy/changeset/a6c689102654/ Log: Remove all non-operator SMMs of set/frozenset. Own tests / translation / CPython's tests work. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,8 +1,8 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef +from pypy.objspace.std.setobject import set_typedef as settypedef +from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.signature import Signature diff --git a/pypy/objspace/std/frozensettype.py b/pypy/objspace/std/frozensettype.py deleted file mode 100644 --- a/pypy/objspace/std/frozensettype.py +++ /dev/null @@ -1,55 +0,0 @@ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - - -frozenset_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -frozenset_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -frozenset_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -frozenset_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -frozenset_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -frozenset_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -frozenset_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -frozenset_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -frozenset_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__frozenset__new__(space, w_frozensettype, w_iterable=None): - from pypy.objspace.std.setobject import W_FrozensetObject - if (space.is_w(w_frozensettype, space.w_frozenset) and - w_iterable is not None and type(w_iterable) is W_FrozensetObject): - return w_iterable - w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) - W_FrozensetObject.__init__(w_obj, space, w_iterable) - return w_obj - -frozenset_typedef = StdTypeDef("frozenset", - __doc__ = """frozenset(iterable) --> frozenset object - -Build an immutable unordered collection.""", - __new__ = gateway.interp2app(descr__frozenset__new__), - ) - -frozenset_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -38,8 +38,8 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.settype import set_typedef - from pypy.objspace.std.frozensettype import frozenset_typedef + from pypy.objspace.std.setobject import set_typedef + from pypy.objspace.std.setobject import frozenset_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.dicttype import dict_typedef diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -2,12 +2,9 @@ from pypy.objspace.std.register_all import register_all from pypy.interpreter.error import OperationError from pypy.interpreter import gateway -from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef from pypy.interpreter.signature import Signature -from pypy.interpreter.generator import GeneratorIterator -from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.unicodeobject import W_UnicodeObject @@ -24,7 +21,7 @@ # declarations @classmethod def is_implementation_for(cls, typedef): - if typedef is frozensettypedef or typedef is settypedef: + if typedef is W_FrozensetObject.typedef or typedef is settypedef: assert cls is W_BaseSetObject return True return False @@ -164,9 +161,248 @@ """ Removes an arbitrary element from the set. May raise KeyError if set is empty.""" return self.strategy.popitem(self) + # app-level operations (non-mutating) + + def descr_eq(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_False + + # tested in test_buildinshortcut.py + #XXX do not make new setobject here + w_other_as_set = self._newobj(space, w_other) + return space.wrap(self.equals(w_other_as_set)) + + def descr_ne(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(not self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_True + + #XXX this is not tested + w_other_as_set = self._newobj(space, w_other) + return space.wrap(not self.equals(w_other_as_set)) + + # automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the + # correct answer here! + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() >= w_other.length(): + return space.w_False + else: + return self.descr_issubset(space, w_other) + + def descr_le(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() <= w_other.length(): + return space.w_False + else: + return self.descr_issuperset(space, w_other) + + def descr_ge(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + def descr_copy(self, space): + """Return a shallow copy of a set.""" + if type(self) is W_FrozensetObject: + return self + return self.copy_real() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference(self, space, others_w): + """Return a new set with elements in the set that are not in the others.""" + result = self.copy_real() + result.descr_difference_update(space, others_w) + return result + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection(self, space, others_w): + """Return a new set with elements common to the set and all others.""" + #XXX find smarter implementations + others_w = [self] + others_w + + # find smallest set in others_w to reduce comparisons + startindex, startlength = 0, -1 + for i in range(len(others_w)): + w_other = others_w[i] + try: + length = space.int_w(space.len(w_other)) + except OperationError, e: + if (e.match(space, space.w_TypeError) or + e.match(space, space.w_AttributeError)): + continue + raise + + if startlength == -1 or length < startlength: + startindex = i + startlength = length + + others_w[startindex], others_w[0] = others_w[0], others_w[startindex] + + result = self._newobj(space, others_w[0]) + for i in range(1,len(others_w)): + w_other = others_w[i] + if isinstance(w_other, W_BaseSetObject): + result.intersect_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + result.intersect_update(w_other_as_set) + return result + + def descr_issubset(self, space, w_other): + """Report whether another set contains this set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() > w_other_as_set.length(): + return space.w_False + return space.wrap(self.issubset(w_other_as_set)) + + def descr_issuperset(self, space, w_other): + """Report whether this set contains another set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() < w_other_as_set.length(): + return space.w_False + return space.wrap(w_other_as_set.issubset(self)) + + def descr_symmetric_difference(self, space, w_other): + """Return the symmetric difference of two sets as a new set.\n\n(i.e. + all elements that are in exactly one of the sets.)""" + + if isinstance(w_other, W_BaseSetObject): + w_result = self.symmetric_difference(w_other) + return w_result + + w_other_as_set = self._newobj(space, w_other) + w_result = self.symmetric_difference(w_other_as_set) + return w_result + + @gateway.unwrap_spec(others_w='args_w') + def descr_union(self, space, others_w): + """Return a new set with elements from the set and all others.""" + result = self.copy_real() + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + result.update(w_other) + else: + for w_key in space.listview(w_other): + result.add(w_key) + return result + + def descr_reduce(self, space): + """Return state information for pickling.""" + return setreduce(space, self) + + def descr_isdisjoint(self, space, w_other): + """Return True if two sets have a null intersection.""" + + if isinstance(w_other, W_BaseSetObject): + return space.newbool(self.isdisjoint(w_other)) + + #XXX may be optimized when other strategies are added + for w_key in space.listview(w_other): + if self.has_key(w_key): + return space.w_False + return space.w_True + + # app-level operations (mutating) + + def descr_add(self, space, w_other): + """Add an element to a set.\n\nThis has no effect if the element is already present.""" + self.add(w_other) + + def descr_clear(self, space): + """Remove all elements from this set.""" + self.clear() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference_update(self, space, others_w): + """Update the set, removing elements found in others.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.difference_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + self.difference_update(w_other_as_set) + + def descr_discard(self, space, w_item): + """Remove an element from a set if it is a member.\n\nIf the element is not a member, do nothing.""" + _discard_from_set(space, self, w_item) + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection_update(self, space, others_w): + """Update the set, keeping only elements found in it and all others.""" + result = self.descr_intersection(space, others_w) + self.strategy = result.strategy + self.sstorage = result.sstorage + + def descr_pop(self, space): + """Remove and return an arbitrary set element.""" + return self.popitem() + + def descr_remove(self, space, w_item): + """Remove an element from a set; it must be a member.\n\nIf the element is not a member, raise a KeyError.""" + if not _discard_from_set(space, self, w_item): + space.raise_key_error(w_item) + + def descr_symmetric_difference_update(self, space, w_other): + """Update a set with the symmetric difference of itself and another.""" + if isinstance(w_other, W_BaseSetObject): + self.symmetric_difference_update(w_other) + return + w_other_as_set = self._newobj(space, w_other) + self.symmetric_difference_update(w_other_as_set) + + @gateway.unwrap_spec(others_w='args_w') + def descr_update(self, space, others_w): + """Update a set with the union of itself and another.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.update(w_other) + else: + for w_key in space.listview(w_other): + self.add(w_key) + + class W_SetObject(W_BaseSetObject): - from pypy.objspace.std.settype import set_typedef as typedef - def _newobj(w_self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" if type(w_self) is W_SetObject: @@ -176,8 +412,59 @@ W_SetObject.__init__(w_obj, space, w_iterable) return w_obj +def descr__new__(space, w_settype, __args__): + w_obj = space.allocate_instance(W_SetObject, w_settype) + W_SetObject.__init__(w_obj, space) + return w_obj + +W_SetObject.typedef = StdTypeDef("set", + __doc__ = """set(iterable) --> set object + +Build an unordered collection.""", + __new__ = gateway.interp2app(descr__new__), + __hash__ = None, + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), + #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), + #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint), + + # mutating methods + add = gateway.interp2app(W_BaseSetObject.descr_add), + clear = gateway.interp2app(W_BaseSetObject.descr_clear), + difference_update = gateway.interp2app(W_BaseSetObject.descr_difference_update), + discard = gateway.interp2app(W_BaseSetObject.descr_discard), + intersection_update = gateway.interp2app(W_BaseSetObject.descr_intersection_update), + pop = gateway.interp2app(W_BaseSetObject.descr_pop), + remove = gateway.interp2app(W_BaseSetObject.descr_remove), + symmetric_difference_update = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference_update), + update = gateway.interp2app(W_BaseSetObject.descr_update) + ) +W_SetObject.typedef.registermethods(globals()) +set_typedef = W_SetObject.typedef +settypedef = W_SetObject.typedef + + class W_FrozensetObject(W_BaseSetObject): - from pypy.objspace.std.frozensettype import frozenset_typedef as typedef hash = 0 def _newobj(w_self, space, w_iterable): @@ -189,6 +476,50 @@ W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj +def descr__frozenset__new__(space, w_frozensettype, w_iterable=None): + if (space.is_w(w_frozensettype, space.w_frozenset) and + w_iterable is not None and type(w_iterable) is W_FrozensetObject): + return w_iterable + w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) + W_FrozensetObject.__init__(w_obj, space, w_iterable) + return w_obj + +W_FrozensetObject.typedef = StdTypeDef("frozenset", + __doc__ = """frozenset(iterable) --> frozenset object + +Build an immutable unordered collection.""", + __new__ = gateway.interp2app(descr__frozenset__new__), + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), + #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), + #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint) + ) + +W_FrozensetObject.typedef.registermethods(globals()) +frozenset_typedef = W_FrozensetObject.typedef +frozensettypedef = W_FrozensetObject.typedef + + registerimplementation(W_BaseSetObject) registerimplementation(W_SetObject) registerimplementation(W_FrozensetObject) @@ -432,7 +763,6 @@ w_set.add(w_key) def remove(self, w_set, w_item): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string d = self.unerase(w_set.sstorage) if not self.is_correct_type(w_item): #XXX check type of w_item and immediately return False in some cases @@ -464,7 +794,6 @@ return keys_w def has_key(self, w_set, w_key): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string if not self.is_correct_type(w_key): #XXX check type of w_item and immediately return False in some cases w_set.switch_to_object_strategy(self.space) @@ -801,7 +1130,6 @@ return self.unerase(w_set.sstorage).keys() def is_correct_type(self, w_key): - from pypy.objspace.std.intobject import W_IntObject return type(w_key) is W_IntObject def may_contain_equal_elements(self, strategy): @@ -966,8 +1294,8 @@ else: return None + class W_SetIterObject(W_Object): - from pypy.objspace.std.settype import setiter_typedef as typedef # XXX this class should be killed, and the various # iterimplementations should be W_Objects directly. @@ -975,8 +1303,18 @@ w_self.space = space w_self.iterimplementation = iterimplementation +def descr_setiterator__length_hint__(space, w_self): + assert isinstance(w_self, W_SetIterObject) + return space.wrap(w_self.iterimplementation.length()) + +W_SetIterObject.typedef = StdTypeDef("setiterator", + __length_hint__ = gateway.interp2app(descr_setiterator__length_hint__), + ) +setiter_typedef = W_SetIterObject.typedef + registerimplementation(W_SetIterObject) + def iter__SetIterObject(space, w_setiter): return w_setiter @@ -993,7 +1331,6 @@ return r_dict(space.eq_w, space.hash_w, force_non_null=True) def set_strategy_and_setdata(space, w_set, w_iterable): - from pypy.objspace.std.intobject import W_IntObject if w_iterable is None : w_set.strategy = strategy = space.fromcache(EmptySetStrategy) w_set.sstorage = strategy.get_empty_storage() @@ -1084,210 +1421,37 @@ else: return None -def set_update__Set(space, w_left, others_w): - """Update a set with the union of itself and another.""" - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - w_left.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - w_left.add(w_key) - -def inplace_or__Set_Set(space, w_left, w_other): - w_left.update(w_other) - return w_left +def inplace_or__Set_Set(space, self, w_other): + self.update(w_other) + return self inplace_or__Set_Frozenset = inplace_or__Set_Set -def set_add__Set_ANY(space, w_left, w_other): - """Add an element to a set. - - This has no effect if the element is already present. - """ - w_left.add(w_other) - -def set_copy__Set(space, w_set): - return w_set.copy_real() - -def frozenset_copy__Frozenset(space, w_left): - if type(w_left) is W_FrozensetObject: - return w_left - else: - return set_copy__Set(space, w_left) - -def set_clear__Set(space, w_left): - w_left.clear() - -def sub__Set_Set(space, w_left, w_other): - return w_left.difference(w_other) +def sub__Set_Set(space, self, w_other): + return self.difference(w_other) sub__Set_Frozenset = sub__Set_Set sub__Frozenset_Set = sub__Set_Set sub__Frozenset_Frozenset = sub__Set_Set -def set_difference__Set(space, w_left, others_w): - result = w_left.copy_real() - set_difference_update__Set(space, result, others_w) - return result - -frozenset_difference__Frozenset = set_difference__Set - - -def set_difference_update__Set(space, w_left, others_w): - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - # optimization only - w_left.difference_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - w_left.difference_update(w_other_as_set) - -def inplace_sub__Set_Set(space, w_left, w_other): - w_left.difference_update(w_other) - return w_left +def inplace_sub__Set_Set(space, self, w_other): + self.difference_update(w_other) + return self inplace_sub__Set_Frozenset = inplace_sub__Set_Set -def eq__Set_Set(space, w_left, w_other): - # optimization only (the general case is eq__Set_settypedef) - return space.wrap(w_left.equals(w_other)) - -eq__Set_Frozenset = eq__Set_Set -eq__Frozenset_Frozenset = eq__Set_Set -eq__Frozenset_Set = eq__Set_Set - -def eq__Set_settypedef(space, w_left, w_other): - # tested in test_buildinshortcut.py - #XXX do not make new setobject here - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(w_left.equals(w_other_as_set)) - -eq__Set_frozensettypedef = eq__Set_settypedef -eq__Frozenset_settypedef = eq__Set_settypedef -eq__Frozenset_frozensettypedef = eq__Set_settypedef - -def eq__Set_ANY(space, w_left, w_other): - # workaround to have "set() == 42" return False instead of falling - # back to cmp(set(), 42) because the latter raises a TypeError - return space.w_False - -eq__Frozenset_ANY = eq__Set_ANY - -def ne__Set_Set(space, w_left, w_other): - return space.wrap(not w_left.equals(w_other)) - -ne__Set_Frozenset = ne__Set_Set -ne__Frozenset_Frozenset = ne__Set_Set -ne__Frozenset_Set = ne__Set_Set - -def ne__Set_settypedef(space, w_left, w_other): - #XXX this is not tested - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(not w_left.equals(w_other_as_set)) - -ne__Set_frozensettypedef = ne__Set_settypedef -ne__Frozenset_settypedef = ne__Set_settypedef -ne__Frozenset_frozensettypedef = ne__Set_settypedef - - -def ne__Set_ANY(space, w_left, w_other): - # more workarounds - return space.w_True - -ne__Frozenset_ANY = ne__Set_ANY - -def contains__Set_ANY(space, w_left, w_other): +def contains__Set_ANY(space, self, w_other): try: - return space.newbool(w_left.has_key(w_other)) + return space.newbool(self.has_key(w_other)) except OperationError, e: if e.match(space, space.w_TypeError): w_f = _convert_set_to_frozenset(space, w_other) if w_f is not None: - return space.newbool(w_left.has_key(w_f)) + return space.newbool(self.has_key(w_f)) raise contains__Frozenset_ANY = contains__Set_ANY -def set_issubset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() > w_other.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other)) - -set_issubset__Set_Frozenset = set_issubset__Set_Set -frozenset_issubset__Frozenset_Set = set_issubset__Set_Set -frozenset_issubset__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issubset__Set_ANY(space, w_left, w_other): - # not checking whether w_left is w_other here, because if that were the - # case the more precise multimethod would have applied. - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() > w_other_as_set.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other_as_set)) - -frozenset_issubset__Frozenset_ANY = set_issubset__Set_ANY - -le__Set_Set = set_issubset__Set_Set -le__Set_Frozenset = set_issubset__Set_Set -le__Frozenset_Set = set_issubset__Set_Set -le__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issuperset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() < w_other.length(): - return space.w_False - return space.wrap(w_other.issubset(w_left)) - -set_issuperset__Set_Frozenset = set_issuperset__Set_Set -set_issuperset__Frozenset_Set = set_issuperset__Set_Set -set_issuperset__Frozenset_Frozenset = set_issuperset__Set_Set - -def set_issuperset__Set_ANY(space, w_left, w_other): - if space.is_w(w_left, w_other): - return space.w_True - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() < w_other_as_set.length(): - return space.w_False - return space.wrap(w_other_as_set.issubset(w_left)) - -frozenset_issuperset__Frozenset_ANY = set_issuperset__Set_ANY - -ge__Set_Set = set_issuperset__Set_Set -ge__Set_Frozenset = set_issuperset__Set_Set -ge__Frozenset_Set = set_issuperset__Set_Set -ge__Frozenset_Frozenset = set_issuperset__Set_Set - -# automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the -# correct answer here! -def lt__Set_Set(space, w_left, w_other): - if w_left.length() >= w_other.length(): - return space.w_False - else: - return le__Set_Set(space, w_left, w_other) - -lt__Set_Frozenset = lt__Set_Set -lt__Frozenset_Set = lt__Set_Set -lt__Frozenset_Frozenset = lt__Set_Set - -def gt__Set_Set(space, w_left, w_other): - if w_left.length() <= w_other.length(): - return space.w_False - else: - return ge__Set_Set(space, w_left, w_other) - -gt__Set_Frozenset = gt__Set_Set -gt__Frozenset_Set = gt__Set_Set -gt__Frozenset_Frozenset = gt__Set_Set - def _discard_from_set(space, w_left, w_item): """ Discard an element from a set, with automatic conversion to @@ -1309,13 +1473,6 @@ w_left.switch_to_empty_strategy() return deleted -def set_discard__Set_ANY(space, w_left, w_item): - _discard_from_set(space, w_left, w_item) - -def set_remove__Set_ANY(space, w_left, w_item): - if not _discard_from_set(space, w_left, w_item): - space.raise_key_error(w_item) - def hash__Frozenset(space, w_set): multi = r_uint(1822399083) + r_uint(1822399083) + 1 if w_set.hash != 0: @@ -1338,124 +1495,29 @@ return space.wrap(hash) -def set_pop__Set(space, w_left): - return w_left.popitem() -def and__Set_Set(space, w_left, w_other): - new_set = w_left.intersect(w_other) +def and__Set_Set(space, self, w_other): + new_set = self.intersect(w_other) return new_set and__Set_Frozenset = and__Set_Set and__Frozenset_Set = and__Set_Set and__Frozenset_Frozenset = and__Set_Set -def set_intersection__Set(space, w_left, others_w): - #XXX find smarter implementations - others_w = [w_left] + others_w - - # find smallest set in others_w to reduce comparisons - startindex, startlength = 0, -1 - for i in range(len(others_w)): - w_other = others_w[i] - try: - length = space.int_w(space.len(w_other)) - except OperationError, e: - if (e.match(space, space.w_TypeError) or - e.match(space, space.w_AttributeError)): - continue - raise - - if startlength == -1 or length < startlength: - startindex = i - startlength = length - - others_w[startindex], others_w[0] = others_w[0], others_w[startindex] - - result = w_left._newobj(space, others_w[0]) - for i in range(1,len(others_w)): - w_other = others_w[i] - if isinstance(w_other, W_BaseSetObject): - # optimization only - result.intersect_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - result.intersect_update(w_other_as_set) - return result - -frozenset_intersection__Frozenset = set_intersection__Set - -def set_intersection_update__Set(space, w_left, others_w): - result = set_intersection__Set(space, w_left, others_w) - w_left.strategy = result.strategy - w_left.sstorage = result.sstorage - return - -def inplace_and__Set_Set(space, w_left, w_other): - w_left.intersect_update(w_other) - return w_left +def inplace_and__Set_Set(space, self, w_other): + self.intersect_update(w_other) + return self inplace_and__Set_Frozenset = inplace_and__Set_Set -def set_isdisjoint__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - return space.newbool(w_left.isdisjoint(w_other)) - -set_isdisjoint__Set_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Set = set_isdisjoint__Set_Set - -def set_isdisjoint__Set_ANY(space, w_left, w_other): - #XXX may be optimized when other strategies are added - for w_key in space.listview(w_other): - if w_left.has_key(w_key): - return space.w_False - return space.w_True - -frozenset_isdisjoint__Frozenset_ANY = set_isdisjoint__Set_ANY - -def set_symmetric_difference__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_result = w_left.symmetric_difference(w_other) - return w_result - -set_symmetric_difference__Set_Frozenset = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Set = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Frozenset = \ - set_symmetric_difference__Set_Set - -xor__Set_Set = set_symmetric_difference__Set_Set -xor__Set_Frozenset = set_symmetric_difference__Set_Set -xor__Frozenset_Set = set_symmetric_difference__Set_Set -xor__Frozenset_Frozenset = set_symmetric_difference__Set_Set - - -def set_symmetric_difference__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_result = w_left.symmetric_difference(w_other_as_set) - return w_result - -frozenset_symmetric_difference__Frozenset_ANY = \ - set_symmetric_difference__Set_ANY - -def set_symmetric_difference_update__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_left.symmetric_difference_update(w_other) - -set_symmetric_difference_update__Set_Frozenset = \ - set_symmetric_difference_update__Set_Set - -def set_symmetric_difference_update__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_left.symmetric_difference_update(w_other_as_set) - -def inplace_xor__Set_Set(space, w_left, w_other): - set_symmetric_difference_update__Set_Set(space, w_left, w_other) - return w_left +def inplace_xor__Set_Set(space, self, w_other): + self.descr_symmetric_difference_update(space, w_other) + return self inplace_xor__Set_Frozenset = inplace_xor__Set_Set -def or__Set_Set(space, w_left, w_other): - w_copy = w_left.copy_real() +def or__Set_Set(space, self, w_other): + w_copy = self.copy_real() w_copy.update(w_other) return w_copy @@ -1463,29 +1525,25 @@ or__Frozenset_Set = or__Set_Set or__Frozenset_Frozenset = or__Set_Set -def set_union__Set(space, w_left, others_w): - result = w_left.copy_real() - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - result.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - result.add(w_key) - return result +def xor__Set_Set(space, self, w_other): + w_result = self.symmetric_difference(w_other) + return w_result -frozenset_union__Frozenset = set_union__Set +xor__Set_Frozenset = xor__Set_Set +xor__Frozenset_Set = xor__Set_Set +xor__Frozenset_Frozenset = xor__Set_Set -def len__Set(space, w_left): - return space.newint(w_left.length()) +def len__Set(space, self): + return space.newint(self.length()) len__Frozenset = len__Set -def iter__Set(space, w_left): - return W_SetIterObject(space, w_left.iter()) +def iter__Set(space, self): + return W_SetIterObject(space, self.iter()) iter__Frozenset = iter__Set -def cmp__Set_settypedef(space, w_left, w_other): +def cmp__Set_settypedef(space, self, w_other): # hack hack until we get the expected result raise OperationError(space.w_TypeError, space.wrap('cannot compare sets using cmp()')) @@ -1531,16 +1589,12 @@ repr__Frozenset = repr__Set app = gateway.applevel(""" - def reduce__Set(s): + def setreduce(s): dict = getattr(s,'__dict__', None) return (s.__class__, (tuple(s),), dict) """, filename=__file__) -set_reduce__Set = app.interphook('reduce__Set') -frozenset_reduce__Frozenset = app.interphook('reduce__Set') +setreduce = app.interphook('setreduce') -from pypy.objspace.std import frozensettype -from pypy.objspace.std import settype - -register_all(vars(), settype, frozensettype) +register_all(vars()) diff --git a/pypy/objspace/std/settype.py b/pypy/objspace/std/settype.py deleted file mode 100644 --- a/pypy/objspace/std/settype.py +++ /dev/null @@ -1,91 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -set_add = SMM('add', 2, - doc='Add an element to a set.\n\nThis' - ' has no effect if the element is' - ' already present.') -set_clear = SMM('clear', 1, - doc='Remove all elements from this set.') -set_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -set_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -set_difference_update = SMM('difference_update', 1, varargs_w=True, - doc='Update the set, removing elements' - ' found in others.') -set_discard = SMM('discard', 2, - doc='Remove an element from a set if it' - ' is a member.\n\nIf the element is' - ' not a member, do nothing.') -set_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -set_intersection_update = SMM('intersection_update', 1, varargs_w=True, - doc='Update the set, keeping only elements' - ' found in it and all others.') -set_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -set_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -set_pop = SMM('pop', 1, - doc='Remove and return an arbitrary set' - ' element.') -set_remove = SMM('remove', 2, - doc='Remove an element from a set; it' - ' must be a member.\n\nIf the' - ' element is not a member, raise a' - ' KeyError.') -set_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -set_symmetric_difference_update = SMM('symmetric_difference_update', 2, - doc='Update a set with the symmetric' - ' difference of itself and another.') -set_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -set_update = SMM('update', 1, varargs_w=True, - doc='Update the set, adding elements' - ' from all others.') -set_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -set_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__new__(space, w_settype, __args__): - from pypy.objspace.std.setobject import W_SetObject, newset - w_obj = space.allocate_instance(W_SetObject, w_settype) - W_SetObject.__init__(w_obj, space) - return w_obj - -set_typedef = StdTypeDef("set", - __doc__ = """set(iterable) --> set object - -Build an unordered collection.""", - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - ) - -set_typedef.registermethods(globals()) - -def descr_setiterator__length_hint__(space, w_self): - from pypy.objspace.std.setobject import W_SetIterObject - assert isinstance(w_self, W_SetIterObject) - return space.wrap(w_self.iterimplementation.length()) - -setiter_typedef = StdTypeDef("setiterator", - __length_hint__ = gateway.interp2app(descr_setiterator__length_hint__), - ) diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -12,11 +12,18 @@ from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject, IntegerSetStrategy from pypy.objspace.std.setobject import _initialize_set from pypy.objspace.std.setobject import newset -from pypy.objspace.std.setobject import and__Set_Set -from pypy.objspace.std.setobject import set_intersection__Set -from pypy.objspace.std.setobject import eq__Set_Set from pypy.objspace.std.listobject import W_ListObject +def and__Set_Set(space, w_left, w_right): + return w_left.descr_intersection(space, [w_right]) + +def set_intersection__Set(space, w_left, w_right): + return w_left.descr_intersection(space, w_right) + +def eq__Set_Set(space, w_left, w_right): + return w_left.descr_eq(space, w_right) + + letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' class W_SubSetObject(W_SetObject):pass From noreply at buildbot.pypy.org Wed May 15 14:00:59 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:00:59 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Move frozenset's hash method into W_FrozensetObject. Message-ID: <20130515120059.472EB1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64127:4ccda5e55e38 Date: 2013-05-15 11:00 +0200 http://bitbucket.org/pypy/pypy/changeset/4ccda5e55e38/ Log: Move frozenset's hash method into W_FrozensetObject. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -476,6 +476,28 @@ W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj + def descr_hash(self, space): + multi = r_uint(1822399083) + r_uint(1822399083) + 1 + if self.hash != 0: + return space.wrap(self.hash) + hash = r_uint(1927868237) + hash *= r_uint(self.length() + 1) + w_iterator = self.iter() + while True: + w_item = w_iterator.next_entry() + if w_item is None: + break + h = space.hash_w(w_item) + value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) + hash = hash ^ value + hash = hash * 69069 + 907133923 + if hash == 0: + hash = 590923713 + hash = intmask(hash) + self.hash = hash + + return space.wrap(hash) + def descr__frozenset__new__(space, w_frozensettype, w_iterable=None): if (space.is_w(w_frozensettype, space.w_frozenset) and w_iterable is not None and type(w_iterable) is W_FrozensetObject): @@ -489,6 +511,7 @@ Build an immutable unordered collection.""", __new__ = gateway.interp2app(descr__frozenset__new__), + __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), # comparison operators __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), @@ -1473,28 +1496,6 @@ w_left.switch_to_empty_strategy() return deleted -def hash__Frozenset(space, w_set): - multi = r_uint(1822399083) + r_uint(1822399083) + 1 - if w_set.hash != 0: - return space.wrap(w_set.hash) - hash = r_uint(1927868237) - hash *= r_uint(w_set.length() + 1) - w_iterator = w_set.iter() - while True: - w_item = w_iterator.next_entry() - if w_item is None: - break - h = space.hash_w(w_item) - value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) - hash = hash ^ value - hash = hash * 69069 + 907133923 - if hash == 0: - hash = 590923713 - hash = intmask(hash) - w_set.hash = hash - - return space.wrap(hash) - def and__Set_Set(space, self, w_other): new_set = self.intersect(w_other) From noreply at buildbot.pypy.org Wed May 15 14:01:00 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:00 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Move (frozen)set's allocators into W_(Frozen)SetObject. Message-ID: <20130515120100.700A41C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64128:d43e12bcb53a Date: 2013-05-15 11:06 +0200 http://bitbucket.org/pypy/pypy/changeset/d43e12bcb53a/ Log: Move (frozen)set's allocators into W_(Frozen)SetObject. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -412,16 +412,17 @@ W_SetObject.__init__(w_obj, space, w_iterable) return w_obj -def descr__new__(space, w_settype, __args__): - w_obj = space.allocate_instance(W_SetObject, w_settype) - W_SetObject.__init__(w_obj, space) - return w_obj + @staticmethod + def descr_new(space, w_settype, __args__): + w_obj = space.allocate_instance(W_SetObject, w_settype) + W_SetObject.__init__(w_obj, space) + return w_obj W_SetObject.typedef = StdTypeDef("set", __doc__ = """set(iterable) --> set object Build an unordered collection.""", - __new__ = gateway.interp2app(descr__new__), + __new__ = gateway.interp2app(W_SetObject.descr_new), __hash__ = None, # comparison operators @@ -476,6 +477,15 @@ W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj + @staticmethod + def descr_new(space, w_frozensettype, w_iterable=None): + if (space.is_w(w_frozensettype, space.w_frozenset) and + w_iterable is not None and type(w_iterable) is W_FrozensetObject): + return w_iterable + w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) + W_FrozensetObject.__init__(w_obj, space, w_iterable) + return w_obj + def descr_hash(self, space): multi = r_uint(1822399083) + r_uint(1822399083) + 1 if self.hash != 0: @@ -498,19 +508,11 @@ return space.wrap(hash) -def descr__frozenset__new__(space, w_frozensettype, w_iterable=None): - if (space.is_w(w_frozensettype, space.w_frozenset) and - w_iterable is not None and type(w_iterable) is W_FrozensetObject): - return w_iterable - w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) - W_FrozensetObject.__init__(w_obj, space, w_iterable) - return w_obj - W_FrozensetObject.typedef = StdTypeDef("frozenset", __doc__ = """frozenset(iterable) --> frozenset object Build an immutable unordered collection.""", - __new__ = gateway.interp2app(descr__frozenset__new__), + __new__ = gateway.interp2app(W_FrozensetObject.descr_new), __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), # comparison operators From noreply at buildbot.pypy.org Wed May 15 14:01:01 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:01 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__len__ multi-method. Message-ID: <20130515120101.96CD51C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64129:6f5738129e7b Date: 2013-05-15 11:12 +0200 http://bitbucket.org/pypy/pypy/changeset/6f5738129e7b/ Log: Remove set.__len__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -226,6 +226,9 @@ return space.w_False return space.wrap(w_other.issubset(self)) + def descr_len(self, space): + return space.newint(self.length()) + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -434,6 +437,7 @@ __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -524,6 +528,7 @@ __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -1536,11 +1541,6 @@ xor__Frozenset_Set = xor__Set_Set xor__Frozenset_Frozenset = xor__Set_Set -def len__Set(space, self): - return space.newint(self.length()) - -len__Frozenset = len__Set - def iter__Set(space, self): return W_SetIterObject(space, self.iter()) From noreply at buildbot.pypy.org Wed May 15 14:01:02 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:02 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__iter__ multi-method. Message-ID: <20130515120102.B4AE51C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64130:7ff94598f1e2 Date: 2013-05-15 11:15 +0200 http://bitbucket.org/pypy/pypy/changeset/7ff94598f1e2/ Log: Remove set.__iter__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -229,6 +229,9 @@ def descr_len(self, space): return space.newint(self.length()) + def descr_iter(self, space): + return W_SetIterObject(space, self.iter()) + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -438,6 +441,7 @@ # non-mutating operators __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -529,6 +533,7 @@ # non-mutating operators __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -1541,11 +1546,6 @@ xor__Frozenset_Set = xor__Set_Set xor__Frozenset_Frozenset = xor__Set_Set -def iter__Set(space, self): - return W_SetIterObject(space, self.iter()) - -iter__Frozenset = iter__Set - def cmp__Set_settypedef(space, self, w_other): # hack hack until we get the expected result raise OperationError(space.w_TypeError, From noreply at buildbot.pypy.org Wed May 15 14:01:03 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:03 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__contains__ multi-method. Message-ID: <20130515120103.F2F9C1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64131:676ca89b400f Date: 2013-05-15 11:18 +0200 http://bitbucket.org/pypy/pypy/changeset/676ca89b400f/ Log: Remove set.__contains__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -232,6 +232,16 @@ def descr_iter(self, space): return W_SetIterObject(space, self.iter()) + def descr_contains(self, space, w_other): + try: + return space.newbool(self.has_key(w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + w_f = _convert_set_to_frozenset(space, w_other) + if w_f is not None: + return space.newbool(self.has_key(w_f)) + raise + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -442,6 +452,7 @@ # non-mutating operators __len__ = gateway.interp2app(W_BaseSetObject.descr_len), __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -534,6 +545,7 @@ # non-mutating operators __len__ = gateway.interp2app(W_BaseSetObject.descr_len), __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -1475,18 +1487,6 @@ inplace_sub__Set_Frozenset = inplace_sub__Set_Set -def contains__Set_ANY(space, self, w_other): - try: - return space.newbool(self.has_key(w_other)) - except OperationError, e: - if e.match(space, space.w_TypeError): - w_f = _convert_set_to_frozenset(space, w_other) - if w_f is not None: - return space.newbool(self.has_key(w_f)) - raise - -contains__Frozenset_ANY = contains__Set_ANY - def _discard_from_set(space, w_left, w_item): """ Discard an element from a set, with automatic conversion to From noreply at buildbot.pypy.org Wed May 15 14:01:05 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:05 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__repr__ multi-method. Message-ID: <20130515120105.29D1C1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64132:c19c1e7f2798 Date: 2013-05-15 11:22 +0200 http://bitbucket.org/pypy/pypy/changeset/c19c1e7f2798/ Log: Remove set.__repr__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -242,6 +242,13 @@ return space.newbool(self.has_key(w_f)) raise + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return setrepr(space, w_currently_in_repr, self) + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -439,6 +446,7 @@ Build an unordered collection.""", __new__ = gateway.interp2app(W_SetObject.descr_new), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), __hash__ = None, # comparison operators @@ -532,6 +540,7 @@ Build an immutable unordered collection.""", __new__ = gateway.interp2app(W_FrozensetObject.descr_new), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), # comparison operators @@ -1582,15 +1591,6 @@ setrepr = app.interphook("setrepr") -def repr__Set(space, w_set): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return setrepr(space, w_currently_in_repr, w_set) - -repr__Frozenset = repr__Set - app = gateway.applevel(""" def setreduce(s): dict = getattr(s,'__dict__', None) From noreply at buildbot.pypy.org Wed May 15 14:01:06 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:06 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__and__ multi-method. Message-ID: <20130515120106.4BC1A1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64133:166b0bd43694 Date: 2013-05-15 11:26 +0200 http://bitbucket.org/pypy/pypy/changeset/166b0bd43694/ Log: Remove set.__and__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -249,6 +249,9 @@ w_currently_in_repr = ec._py_repr = space.newdict() return setrepr(space, w_currently_in_repr, self) + def descr_and(self, space, w_other): + return self.intersect(w_other) + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -461,7 +464,7 @@ __len__ = gateway.interp2app(W_BaseSetObject.descr_len), __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), - #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -555,7 +558,7 @@ __len__ = gateway.interp2app(W_BaseSetObject.descr_len), __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), - #__and__ = gateway.interp2app(W_BaseSetObject.descr_intersection), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), @@ -1517,15 +1520,6 @@ w_left.switch_to_empty_strategy() return deleted - -def and__Set_Set(space, self, w_other): - new_set = self.intersect(w_other) - return new_set - -and__Set_Frozenset = and__Set_Set -and__Frozenset_Set = and__Set_Set -and__Frozenset_Frozenset = and__Set_Set - def inplace_and__Set_Set(space, self, w_other): self.intersect_update(w_other) return self From noreply at buildbot.pypy.org Wed May 15 14:01:07 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:07 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Change comment. Move descr_repr up. Message-ID: <20130515120107.65ABA1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64134:f0181cff601c Date: 2013-05-15 11:28 +0200 http://bitbucket.org/pypy/pypy/changeset/f0181cff601c/ Log: Change comment. Move descr_repr up. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -161,7 +161,14 @@ """ Removes an arbitrary element from the set. May raise KeyError if set is empty.""" return self.strategy.popitem(self) - # app-level operations (non-mutating) + # app-level operations + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return setrepr(space, w_currently_in_repr, self) def descr_eq(self, space, w_other): if isinstance(w_other, W_BaseSetObject): @@ -242,13 +249,6 @@ return space.newbool(self.has_key(w_f)) raise - def descr_repr(self, space): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return setrepr(space, w_currently_in_repr, self) - def descr_and(self, space, w_other): return self.intersect(w_other) @@ -369,8 +369,6 @@ return space.w_False return space.w_True - # app-level operations (mutating) - def descr_add(self, space, w_other): """Add an element to a set.\n\nThis has no effect if the element is already present.""" self.add(w_other) From noreply at buildbot.pypy.org Wed May 15 14:01:08 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:08 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__or__ multi-method. Message-ID: <20130515120108.7F2881C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64135:6f82bbbacb6b Date: 2013-05-15 11:29 +0200 http://bitbucket.org/pypy/pypy/changeset/6f82bbbacb6b/ Log: Remove set.__or__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -252,6 +252,11 @@ def descr_and(self, space, w_other): return self.intersect(w_other) + def descr_or(self, space, w_other): + w_copy = self.copy_real() + w_copy.update(w_other) + return w_copy + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -463,7 +468,7 @@ __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), __and__ = gateway.interp2app(W_BaseSetObject.descr_and), - #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), # non-mutating methods @@ -557,7 +562,7 @@ __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), __and__ = gateway.interp2app(W_BaseSetObject.descr_and), - #__or__ = gateway.interp2app(W_BaseSetObject.descr_union), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), # non-mutating methods @@ -1530,15 +1535,6 @@ inplace_xor__Set_Frozenset = inplace_xor__Set_Set -def or__Set_Set(space, self, w_other): - w_copy = self.copy_real() - w_copy.update(w_other) - return w_copy - -or__Set_Frozenset = or__Set_Set -or__Frozenset_Set = or__Set_Set -or__Frozenset_Frozenset = or__Set_Set - def xor__Set_Set(space, self, w_other): w_result = self.symmetric_difference(w_other) return w_result From noreply at buildbot.pypy.org Wed May 15 14:01:09 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:09 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__xor__ multi-method. Message-ID: <20130515120109.A39F11C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64136:e9a41e2201c5 Date: 2013-05-15 11:31 +0200 http://bitbucket.org/pypy/pypy/changeset/e9a41e2201c5/ Log: Remove set.__xor__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -257,6 +257,9 @@ w_copy.update(w_other) return w_copy + def descr_xor(self, space, w_other): + return self.symmetric_difference(w_other) + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -469,7 +472,7 @@ __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), __and__ = gateway.interp2app(W_BaseSetObject.descr_and), __or__ = gateway.interp2app(W_BaseSetObject.descr_or), - #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), # non-mutating methods __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), @@ -563,7 +566,7 @@ __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), __and__ = gateway.interp2app(W_BaseSetObject.descr_and), __or__ = gateway.interp2app(W_BaseSetObject.descr_or), - #__xor__ = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), # non-mutating methods __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), @@ -1535,14 +1538,6 @@ inplace_xor__Set_Frozenset = inplace_xor__Set_Set -def xor__Set_Set(space, self, w_other): - w_result = self.symmetric_difference(w_other) - return w_result - -xor__Set_Frozenset = xor__Set_Set -xor__Frozenset_Set = xor__Set_Set -xor__Frozenset_Frozenset = xor__Set_Set - def cmp__Set_settypedef(space, self, w_other): # hack hack until we get the expected result raise OperationError(space.w_TypeError, From noreply at buildbot.pypy.org Wed May 15 14:01:10 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:10 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__sub__ multi-method. Message-ID: <20130515120110.D2C031C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64137:16d1f0e926fa Date: 2013-05-15 11:36 +0200 http://bitbucket.org/pypy/pypy/changeset/16d1f0e926fa/ Log: Remove set.__sub__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -249,6 +249,9 @@ return space.newbool(self.has_key(w_f)) raise + def descr_sub(self, space, w_other): + return self.difference(w_other) + def descr_and(self, space, w_other): return self.intersect(w_other) @@ -470,6 +473,7 @@ __len__ = gateway.interp2app(W_BaseSetObject.descr_len), __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), __and__ = gateway.interp2app(W_BaseSetObject.descr_and), __or__ = gateway.interp2app(W_BaseSetObject.descr_or), __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), @@ -564,6 +568,7 @@ __len__ = gateway.interp2app(W_BaseSetObject.descr_len), __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), __and__ = gateway.interp2app(W_BaseSetObject.descr_and), __or__ = gateway.interp2app(W_BaseSetObject.descr_or), __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), @@ -1492,13 +1497,6 @@ inplace_or__Set_Frozenset = inplace_or__Set_Set -def sub__Set_Set(space, self, w_other): - return self.difference(w_other) - -sub__Set_Frozenset = sub__Set_Set -sub__Frozenset_Set = sub__Set_Set -sub__Frozenset_Frozenset = sub__Set_Set - def inplace_sub__Set_Set(space, self, w_other): self.difference_update(w_other) return self From noreply at buildbot.pypy.org Wed May 15 14:01:12 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:12 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__i*__ multi-methods. Message-ID: <20130515120112.0C2641C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64138:47b6699cda78 Date: 2013-05-15 11:44 +0200 http://bitbucket.org/pypy/pypy/changeset/47b6699cda78/ Log: Remove set.__i*__ multi-methods. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -263,6 +263,22 @@ def descr_xor(self, space, w_other): return self.symmetric_difference(w_other) + def descr_inplace_sub(self, space, w_other): + self.difference_update(w_other) + return self + + def descr_inplace_and(self, space, w_other): + self.intersect_update(w_other) + return self + + def descr_inplace_or(self, space, w_other): + self.update(w_other) + return self + + def descr_inplace_xor(self, space, w_other): + self.descr_symmetric_difference_update(space, w_other) + return self + def descr_copy(self, space): """Return a shallow copy of a set.""" if type(self) is W_FrozensetObject: @@ -478,6 +494,12 @@ __or__ = gateway.interp2app(W_BaseSetObject.descr_or), __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), + # mutating operators + __isub__ = gateway.interp2app(W_BaseSetObject.descr_inplace_sub), + __iand__ = gateway.interp2app(W_BaseSetObject.descr_inplace_and), + __ior__ = gateway.interp2app(W_BaseSetObject.descr_inplace_or), + __ixor__ = gateway.interp2app(W_BaseSetObject.descr_inplace_xor), + # non-mutating methods __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), copy = gateway.interp2app(W_BaseSetObject.descr_copy), @@ -1491,18 +1513,6 @@ else: return None -def inplace_or__Set_Set(space, self, w_other): - self.update(w_other) - return self - -inplace_or__Set_Frozenset = inplace_or__Set_Set - -def inplace_sub__Set_Set(space, self, w_other): - self.difference_update(w_other) - return self - -inplace_sub__Set_Frozenset = inplace_sub__Set_Set - def _discard_from_set(space, w_left, w_item): """ Discard an element from a set, with automatic conversion to @@ -1524,18 +1534,6 @@ w_left.switch_to_empty_strategy() return deleted -def inplace_and__Set_Set(space, self, w_other): - self.intersect_update(w_other) - return self - -inplace_and__Set_Frozenset = inplace_and__Set_Set - -def inplace_xor__Set_Set(space, self, w_other): - self.descr_symmetric_difference_update(space, w_other) - return self - -inplace_xor__Set_Frozenset = inplace_xor__Set_Set - def cmp__Set_settypedef(space, self, w_other): # hack hack until we get the expected result raise OperationError(space.w_TypeError, From noreply at buildbot.pypy.org Wed May 15 14:01:13 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:13 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__cmp__ multi-method. Message-ID: <20130515120113.251151C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64139:915179d6e9c8 Date: 2013-05-15 11:47 +0200 http://bitbucket.org/pypy/pypy/changeset/915179d6e9c8/ Log: Remove set.__cmp__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -170,6 +170,11 @@ w_currently_in_repr = ec._py_repr = space.newdict() return setrepr(space, w_currently_in_repr, self) + def descr_cmp(self, space, w_other): + # hack hack until we get the expected result + raise OperationError(space.w_TypeError, + space.wrap('cannot compare sets using cmp()')) + def descr_eq(self, space, w_other): if isinstance(w_other, W_BaseSetObject): return space.wrap(self.equals(w_other)) @@ -476,6 +481,7 @@ __new__ = gateway.interp2app(W_SetObject.descr_new), __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), __hash__ = None, + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), # comparison operators __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), @@ -577,6 +583,7 @@ __new__ = gateway.interp2app(W_FrozensetObject.descr_new), __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), # comparison operators __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), @@ -1534,15 +1541,6 @@ w_left.switch_to_empty_strategy() return deleted -def cmp__Set_settypedef(space, self, w_other): - # hack hack until we get the expected result - raise OperationError(space.w_TypeError, - space.wrap('cannot compare sets using cmp()')) - -cmp__Set_frozensettypedef = cmp__Set_settypedef -cmp__Frozenset_settypedef = cmp__Set_settypedef -cmp__Frozenset_frozensettypedef = cmp__Set_settypedef - init_signature = Signature(['some_iterable'], None, None) init_defaults = [None] def init__Set(space, w_set, __args__): From noreply at buildbot.pypy.org Wed May 15 14:01:14 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:14 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove set.__init__ multi-method. Message-ID: <20130515120114.4990D1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64140:9350e2d381e3 Date: 2013-05-15 11:59 +0200 http://bitbucket.org/pypy/pypy/changeset/9350e2d381e3/ Log: Remove set.__init__ multi-method. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -163,6 +163,13 @@ # app-level operations + def descr_init(self, space, __args__): + w_iterable, = __args__.parse_obj( + None, 'set', + init_signature, + init_defaults) + _initialize_set(space, self, w_iterable) + def descr_repr(self, space): ec = space.getexecutioncontext() w_currently_in_repr = ec._py_repr @@ -479,6 +486,7 @@ Build an unordered collection.""", __new__ = gateway.interp2app(W_SetObject.descr_new), + __init__ = gateway.interp2app(W_BaseSetObject.descr_init), __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), __hash__ = None, __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), @@ -1503,6 +1511,8 @@ w_set.strategy = space.fromcache(ObjectSetStrategy) w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w) +init_signature = Signature(['some_iterable'], None, None) +init_defaults = [None] def _initialize_set(space, w_obj, w_iterable=None): w_obj.clear() set_strategy_and_setdata(space, w_obj, w_iterable) @@ -1541,15 +1551,6 @@ w_left.switch_to_empty_strategy() return deleted -init_signature = Signature(['some_iterable'], None, None) -init_defaults = [None] -def init__Set(space, w_set, __args__): - w_iterable, = __args__.parse_obj( - None, 'set', - init_signature, - init_defaults) - _initialize_set(space, w_set, w_iterable) - app = gateway.applevel(""" def setrepr(currently_in_repr, s): 'The app-level part of repr().' From noreply at buildbot.pypy.org Wed May 15 14:01:15 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:15 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Inline (temporary) wrappers in test_setobject. Message-ID: <20130515120115.7777D1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64141:a9d450829002 Date: 2013-05-15 12:04 +0200 http://bitbucket.org/pypy/pypy/changeset/a9d450829002/ Log: Inline (temporary) wrappers in test_setobject. diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -14,16 +14,6 @@ from pypy.objspace.std.setobject import newset from pypy.objspace.std.listobject import W_ListObject -def and__Set_Set(space, w_left, w_right): - return w_left.descr_intersection(space, [w_right]) - -def set_intersection__Set(space, w_left, w_right): - return w_left.descr_intersection(space, w_right) - -def eq__Set_Set(space, w_left, w_right): - return w_left.descr_eq(space, w_right) - - letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' class W_SubSetObject(W_SetObject):pass @@ -43,11 +33,11 @@ t0 = W_SetObject(self.space) _initialize_set(self.space, t0, self.otherword) t1 = W_FrozensetObject(self.space, self.otherword) - r0 = and__Set_Set(self.space, s, t0) - r1 = and__Set_Set(self.space, s, t1) - assert eq__Set_Set(self.space, r0, r1) == self.true - sr = set_intersection__Set(self.space, s, [self.otherword]) - assert eq__Set_Set(self.space, r0, sr) == self.true + r0 = s.descr_and(self.space, t0) + r1 = s.descr_and(self.space, t1) + assert r0.descr_eq(self.space, r1) == self.true + sr = s.descr_intersection(self.space, [self.otherword]) + assert r0.descr_eq(self.space, sr) == self.true def test_compare(self): s = W_SetObject(self.space) @@ -73,7 +63,7 @@ b = W_SetObject(self.space) _initialize_set(self.space, b, self.space.wrap("abc")) - result = set_intersection__Set(space, a, [b]) + result = a.descr_intersection(space, [b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("abc")))) c = W_SetObject(self.space) @@ -87,7 +77,7 @@ b.get_storage_copy = None d.get_storage_copy = None - result = set_intersection__Set(space, a, [d,c,b]) + result = a.descr_intersection(space, [d,c,b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("")))) def test_create_set_from_list(self): From noreply at buildbot.pypy.org Wed May 15 14:01:16 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:16 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove setiterator multi-methods. Message-ID: <20130515120116.961411C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64142:820d454b3e8b Date: 2013-05-15 12:09 +0200 http://bitbucket.org/pypy/pypy/changeset/820d454b3e8b/ Log: Remove setiterator multi-methods. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -1410,28 +1410,29 @@ w_self.space = space w_self.iterimplementation = iterimplementation -def descr_setiterator__length_hint__(space, w_self): - assert isinstance(w_self, W_SetIterObject) - return space.wrap(w_self.iterimplementation.length()) + def descr_length_hint(self, space): + return space.wrap(self.iterimplementation.length()) + + def descr_iter(self, space): + return self + + def descr_next(self, space): + iterimplementation = self.iterimplementation + w_key = iterimplementation.next() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) W_SetIterObject.typedef = StdTypeDef("setiterator", - __length_hint__ = gateway.interp2app(descr_setiterator__length_hint__), + __length_hint__ = gateway.interp2app(W_SetIterObject.descr_length_hint), + __iter__ = gateway.interp2app(W_SetIterObject.descr_iter), + next = gateway.interp2app(W_SetIterObject.descr_next) ) setiter_typedef = W_SetIterObject.typedef registerimplementation(W_SetIterObject) -def iter__SetIterObject(space, w_setiter): - return w_setiter - -def next__SetIterObject(space, w_setiter): - iterimplementation = w_setiter.iterimplementation - w_key = iterimplementation.next() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) - # some helper functions def newset(space): From noreply at buildbot.pypy.org Wed May 15 14:01:17 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:17 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove register_all() - all multi-methods removed. Message-ID: <20130515120117.B5E811C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64143:a40ba950694d Date: 2013-05-15 12:13 +0200 http://bitbucket.org/pypy/pypy/changeset/a40ba950694d/ Log: Remove register_all() - all multi-methods removed. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -1,5 +1,4 @@ from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all from pypy.interpreter.error import OperationError from pypy.interpreter import gateway from pypy.interpreter.signature import Signature @@ -1578,5 +1577,3 @@ """, filename=__file__) setreduce = app.interphook('setreduce') - -register_all(vars()) From noreply at buildbot.pypy.org Wed May 15 14:01:18 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:18 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Add type checks in operator implementations. Message-ID: <20130515120118.D50DB1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64144:47becb14728e Date: 2013-05-15 12:22 +0200 http://bitbucket.org/pypy/pypy/changeset/47becb14728e/ Log: Add type checks in operator implementations. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -261,32 +261,48 @@ raise def descr_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented return self.difference(w_other) def descr_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented return self.intersect(w_other) def descr_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented w_copy = self.copy_real() w_copy.update(w_other) return w_copy def descr_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented return self.symmetric_difference(w_other) def descr_inplace_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented self.difference_update(w_other) return self def descr_inplace_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented self.intersect_update(w_other) return self def descr_inplace_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented self.update(w_other) return self def descr_inplace_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented self.descr_symmetric_difference_update(space, w_other) return self From noreply at buildbot.pypy.org Wed May 15 14:01:19 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:19 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Fix translation. Message-ID: <20130515120119.F3B6D1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64145:dbdf8930ad7a Date: 2013-05-15 13:10 +0200 http://bitbucket.org/pypy/pypy/changeset/dbdf8930ad7a/ Log: Fix translation. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -569,7 +569,7 @@ return w_obj @staticmethod - def descr_new(space, w_frozensettype, w_iterable=None): + def descr_new2(space, w_frozensettype, w_iterable=None): if (space.is_w(w_frozensettype, space.w_frozenset) and w_iterable is not None and type(w_iterable) is W_FrozensetObject): return w_iterable @@ -603,7 +603,7 @@ __doc__ = """frozenset(iterable) --> frozenset object Build an immutable unordered collection.""", - __new__ = gateway.interp2app(W_FrozensetObject.descr_new), + __new__ = gateway.interp2app(W_FrozensetObject.descr_new2), __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), From noreply at buildbot.pypy.org Wed May 15 14:01:21 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:21 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Cleanup setobject.py. Message-ID: <20130515120121.54E601C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64146:210bf6bc49f3 Date: 2013-05-15 13:58 +0200 http://bitbucket.org/pypy/pypy/changeset/210bf6bc49f3/ Log: Cleanup setobject.py. diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -1,6 +1,6 @@ from pypy.objspace.std.model import registerimplementation, W_Object +from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway from pypy.interpreter.signature import Signature from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.stdtypedef import StdTypeDef @@ -11,20 +11,13 @@ from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit + UNROLL_CUTOFF = 5 + class W_BaseSetObject(W_Object): typedef = None - # make sure that Base is used for Set and Frozenset in multimethod - # declarations - @classmethod - def is_implementation_for(cls, typedef): - if typedef is W_FrozensetObject.typedef or typedef is settypedef: - assert cls is W_BaseSetObject - return True - return False - def __init__(w_self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" w_self.space = space @@ -62,7 +55,6 @@ # _____________ strategy methods ________________ - def clear(self): """ Removes all elements from the set. """ self.strategy.clear(self) @@ -188,8 +180,9 @@ if not space.isinstance_w(w_other, space.w_set): return space.w_False + # XXX there is no test_buildinshortcut.py # tested in test_buildinshortcut.py - #XXX do not make new setobject here + # XXX do not make new setobject here w_other_as_set = self._newobj(space, w_other) return space.wrap(self.equals(w_other_as_set)) @@ -200,7 +193,7 @@ if not space.isinstance_w(w_other, space.w_set): return space.w_True - #XXX this is not tested + # XXX this is not tested w_other_as_set = self._newobj(space, w_other) return space.wrap(not self.equals(w_other_as_set)) @@ -314,7 +307,8 @@ @gateway.unwrap_spec(others_w='args_w') def descr_difference(self, space, others_w): - """Return a new set with elements in the set that are not in the others.""" + """Return a new set with elements in the set that are not in the + others.""" result = self.copy_real() result.descr_difference_update(space, others_w) return result @@ -384,16 +378,15 @@ return space.wrap(w_other_as_set.issubset(self)) def descr_symmetric_difference(self, space, w_other): - """Return the symmetric difference of two sets as a new set.\n\n(i.e. - all elements that are in exactly one of the sets.)""" + """Return the symmetric difference of two sets as a new set. + + (i.e. all elements that are in exactly one of the sets.)""" if isinstance(w_other, W_BaseSetObject): - w_result = self.symmetric_difference(w_other) - return w_result + return self.symmetric_difference(w_other) w_other_as_set = self._newobj(space, w_other) - w_result = self.symmetric_difference(w_other_as_set) - return w_result + return self.symmetric_difference(w_other_as_set) @gateway.unwrap_spec(others_w='args_w') def descr_union(self, space, others_w): @@ -424,7 +417,9 @@ return space.w_True def descr_add(self, space, w_other): - """Add an element to a set.\n\nThis has no effect if the element is already present.""" + """Add an element to a set. + + This has no effect if the element is already present.""" self.add(w_other) def descr_clear(self, space): @@ -441,9 +436,32 @@ w_other_as_set = self._newobj(space, w_other) self.difference_update(w_other_as_set) + def _discard_from_set(self, space, w_item): + """ + Discard an element from a set, with automatic conversion to + frozenset if the argument is a set. + Returns True if successfully removed. + """ + try: + deleted = self.remove(w_item) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + else: + w_f = _convert_set_to_frozenset(space, w_item) + if w_f is None: + raise + deleted = self.remove(w_f) + + if self.length() == 0: + self.switch_to_empty_strategy() + return deleted + def descr_discard(self, space, w_item): - """Remove an element from a set if it is a member.\n\nIf the element is not a member, do nothing.""" - _discard_from_set(space, self, w_item) + """Remove an element from a set if it is a member. + + If the element is not a member, do nothing.""" + self._discard_from_set(space, w_item) @gateway.unwrap_spec(others_w='args_w') def descr_intersection_update(self, space, others_w): @@ -457,8 +475,10 @@ return self.popitem() def descr_remove(self, space, w_item): - """Remove an element from a set; it must be a member.\n\nIf the element is not a member, raise a KeyError.""" - if not _discard_from_set(space, self, w_item): + """Remove an element from a set; it must be a member. + + If the element is not a member, raise a KeyError.""" + if not self._discard_from_set(space, w_item): space.raise_key_error(w_item) def descr_symmetric_difference_update(self, space, w_other): @@ -551,9 +571,7 @@ symmetric_difference_update = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference_update), update = gateway.interp2app(W_BaseSetObject.descr_update) ) -W_SetObject.typedef.registermethods(globals()) set_typedef = W_SetObject.typedef -settypedef = W_SetObject.typedef class W_FrozensetObject(W_BaseSetObject): @@ -636,16 +654,14 @@ union = gateway.interp2app(W_BaseSetObject.descr_union), isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint) ) - -W_FrozensetObject.typedef.registermethods(globals()) frozenset_typedef = W_FrozensetObject.typedef -frozensettypedef = W_FrozensetObject.typedef registerimplementation(W_BaseSetObject) registerimplementation(W_SetObject) registerimplementation(W_FrozensetObject) + class SetStrategy(object): def __init__(self, space): self.space = space @@ -738,8 +754,8 @@ def popitem(self, w_set): raise NotImplementedError + class EmptySetStrategy(SetStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -830,6 +846,7 @@ raise OperationError(self.space.w_KeyError, self.space.wrap('pop from an empty set')) + class AbstractUnwrappedSetStrategy(object): _mixin_ = True @@ -1169,6 +1186,7 @@ self.space.wrap('pop from an empty set')) return self.wrap(result[0]) + class StringSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) @@ -1272,6 +1290,7 @@ def iter(self, w_set): return IntegerIteratorImplementation(self.space, self, w_set) + class ObjectSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) @@ -1316,6 +1335,7 @@ break d_obj[w_item] = None + class IteratorImplementation(object): def __init__(self, space, strategy, implementation): self.space = space @@ -1360,6 +1380,7 @@ return self.len - self.pos return 0 + class EmptyIteratorImplementation(IteratorImplementation): def next_entry(self): return None @@ -1377,6 +1398,7 @@ else: return None + class UnicodeIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -1389,6 +1411,7 @@ else: return None + class IntegerIteratorImplementation(IteratorImplementation): #XXX same implementation in dictmultiobject on dictstrategy-branch def __init__(self, space, strategy, w_set): @@ -1403,6 +1426,7 @@ else: return None + class RDictIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -1546,26 +1570,6 @@ else: return None -def _discard_from_set(space, w_left, w_item): - """ - Discard an element from a set, with automatic conversion to - frozenset if the argument is a set. - Returns True if successfully removed. - """ - try: - deleted = w_left.remove(w_item) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - else: - w_f = _convert_set_to_frozenset(space, w_item) - if w_f is None: - raise - deleted = w_left.remove(w_f) - - if w_left.length() == 0: - w_left.switch_to_empty_strategy() - return deleted app = gateway.applevel(""" def setrepr(currently_in_repr, s): From noreply at buildbot.pypy.org Wed May 15 14:01:22 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:01:22 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Let the missing ordering methods be filled in by __total_ordering__. Message-ID: <20130515120122.7C5B11C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64147:a7eae675b873 Date: 2013-05-15 12:30 +0200 http://bitbucket.org/pypy/pypy/changeset/a7eae675b873/ Log: Let the missing ordering methods be filled in by __total_ordering__. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -130,10 +130,6 @@ return space.w_False return space.w_True - def descr_ne(self, space, w_other): - # XXX automatize this - return space.not_(self.descr_eq(space, w_other)) - def descr_lt(self, space, w_other): if not isinstance(w_other, W_DictMultiObject): raise operationerrfmt(space.w_TypeError, @@ -393,9 +389,8 @@ __init__ = gateway.interp2app(W_DictMultiObject.descr_init), __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), - __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), - # XXX other comparison methods? + __total_ordering__ = 'auto', __len__ = gateway.interp2app(W_DictMultiObject.descr_len), __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -408,6 +408,24 @@ assert {'a': 1 } < { 'b': 1} assert {'a': 1, 'x': 2 } < { 'b': 1, 'x': 2} + def test_other_rich_cmp(self): + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} + + assert d1 <= d2 + assert d1 <= d3 + assert not d1 <= d4 + + assert not d1 > d2 + assert not d1 > d3 + assert d1 > d4 + + assert d1 >= d2 + assert not d1 >= d3 + assert d1 >= d4 + def test_str_repr(self): assert '{}' == str({}) assert '{1: 2}' == str({1: 2}) From noreply at buildbot.pypy.org Wed May 15 14:06:49 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 14:06:49 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed translation error in ContextPartShadow>>#print_stack Message-ID: <20130515120649.C84971C1106@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r390:f71c099e545b Date: 2013-05-15 14:06 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/f71c099e545b/ Log: fixed translation error in ContextPartShadow>>#print_stack diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -709,16 +709,17 @@ # Debugging printout def print_stack(self, method=True): - def print_padded_stack(s_context, method): - padding = ret_str = '' - if s_context.s_sender() is not None: - padding, ret_str = print_padded_stack(s_context.s_sender(), method) - if method: - desc = s_context.method_str() - else: - desc = s_context.short_str(0) - return padding + ' ', '%s\n%s%s' % (ret_str, padding, desc) - return print_padded_stack(self, method)[1] + return self.print_padded_stack(method)[1] + + def print_padded_stack(self, method): + padding = ret_str = '' + if self.s_sender() is not None: + padding, ret_str = self.s_sender().print_padded_stack(method) + if method: + desc = self.method_str() + else: + desc = self.short_str(0) + return padding + ' ', '%s\n%s%s' % (ret_str, padding, desc) class BlockContextShadow(ContextPartShadow): diff --git a/spyvm/test/test_bootstrappedimage.py b/spyvm/test/test_bootstrappedimage.py --- a/spyvm/test/test_bootstrappedimage.py +++ b/spyvm/test/test_bootstrappedimage.py @@ -6,6 +6,7 @@ def setup(): tools.setup_module(tools, filename='bootstrapped.image') + test_initialize_string_class() def find_symbol_in_methoddict_of(string, s_class): s_methoddict = s_class.s_methoddict() From noreply at buildbot.pypy.org Wed May 15 14:12:36 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 14:12:36 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: readded someInstance, etc. tests Message-ID: <20130515121236.1E77C1C009D@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r391:9aacc7bd6402 Date: 2013-05-15 14:12 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/9aacc7bd6402/ Log: readded someInstance, etc. tests diff --git a/spyvm/plugins/vmdebugging.py b/spyvm/plugins/vmdebugging.py --- a/spyvm/plugins/vmdebugging.py +++ b/spyvm/plugins/vmdebugging.py @@ -23,7 +23,7 @@ if not we_are_translated(): import pdb; pdb.set_trace() else: - print s_frame.print_stack()[1] + print s_frame.print_stack() print s_frame raise Exit('Halt is not well defined when translated.') return w_rcvr diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py --- a/spyvm/test/test_primitives.py +++ b/spyvm/test/test_primitives.py @@ -616,14 +616,12 @@ assert s_new_context.gettemp(2).as_string() == "some value" def test_primitive_some_instance(): - py.test.skip('Takes too long.') import gc; gc.collect() someInstance = map(space.wrap_list, [[1], [2]]) w_r = prim(primitives.SOME_INSTANCE, [space.w_Array]) assert w_r.getclass(space) is space.w_Array def test_primitive_next_instance(): - py.test.skip('Takes too long.') someInstances = map(space.wrap_list, [[2], [3]]) from test_interpreter import new_frame w_frame, s_context = new_frame("", From noreply at buildbot.pypy.org Wed May 15 14:21:38 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:21:38 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: hg merge default Message-ID: <20130515122138.D6DFC1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64148:80e595ef01f2 Date: 2013-05-15 14:16 +0200 http://bitbucket.org/pypy/pypy/changeset/80e595ef01f2/ Log: hg merge default diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -666,7 +666,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -55,6 +55,7 @@ 'validate_fd' : 'interp_magic.validate_fd', 'resizelist_hint' : 'interp_magic.resizelist_hint', 'newlist_hint' : 'interp_magic.newlist_hint', + 'add_memory_pressure' : 'interp_magic.add_memory_pressure', 'newdict' : 'interp_dict.newdict', 'dictstrategy' : 'interp_dict.dictstrategy', } diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -4,7 +4,7 @@ from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.typeobject import MethodCache from pypy.objspace.std.mapdict import IndexCache -from rpython.rlib import rposix +from rpython.rlib import rposix, rgc def internal_repr(space, w_object): @@ -100,3 +100,7 @@ @unwrap_spec(sizehint=int) def newlist_hint(space, sizehint): return space.newlist_hint(sizehint) + + at unwrap_spec(estimate=int) +def add_memory_pressure(estimate): + rgc.add_memory_pressure(estimate) diff --git a/rpython/jit/backend/x86/test/test_del.py b/rpython/jit/backend/arm/test/test_del.py copy from rpython/jit/backend/x86/test/test_del.py copy to rpython/jit/backend/arm/test/test_del.py --- a/rpython/jit/backend/x86/test/test_del.py +++ b/rpython/jit/backend/arm/test/test_del.py @@ -1,8 +1,8 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_del import DelTests -class TestDel(Jit386Mixin, DelTests): +class TestDel(JitARMMixin, DelTests): # for the individual tests see # ====> ../../../metainterp/test/test_del.py pass diff --git a/rpython/jit/backend/x86/test/test_dict.py b/rpython/jit/backend/arm/test/test_dict.py copy from rpython/jit/backend/x86/test/test_dict.py copy to rpython/jit/backend/arm/test/test_dict.py --- a/rpython/jit/backend/x86/test/test_dict.py +++ b/rpython/jit/backend/arm/test/test_dict.py @@ -1,9 +1,9 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_dict import DictTests -class TestDict(Jit386Mixin, DictTests): +class TestDict(JitARMMixin, DictTests): # for the individual tests see # ====> ../../../metainterp/test/test_dict.py pass diff --git a/rpython/jit/backend/x86/test/test_quasiimmut.py b/rpython/jit/backend/arm/test/test_quasiimmut.py copy from rpython/jit/backend/x86/test/test_quasiimmut.py copy to rpython/jit/backend/arm/test/test_quasiimmut.py --- a/rpython/jit/backend/x86/test/test_quasiimmut.py +++ b/rpython/jit/backend/arm/test/test_quasiimmut.py @@ -1,9 +1,9 @@ import py -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test import test_quasiimmut -class TestLoopSpec(Jit386Mixin, test_quasiimmut.QuasiImmutTests): +class TestLoopSpec(JitARMMixin, test_quasiimmut.QuasiImmutTests): # for the individual tests see # ====> ../../../metainterp/test/test_loop.py pass diff --git a/rpython/jit/backend/x86/test/test_rawmem.py b/rpython/jit/backend/arm/test/test_rawmem.py copy from rpython/jit/backend/x86/test/test_rawmem.py copy to rpython/jit/backend/arm/test/test_rawmem.py --- a/rpython/jit/backend/x86/test/test_rawmem.py +++ b/rpython/jit/backend/arm/test/test_rawmem.py @@ -1,9 +1,9 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_rawmem import RawMemTests -class TestRawMem(Jit386Mixin, RawMemTests): +class TestRawMem(JitARMMixin, RawMemTests): # for the individual tests see # ====> ../../../metainterp/test/test_rawmem.py pass diff --git a/rpython/jit/backend/x86/test/test_send.py b/rpython/jit/backend/arm/test/test_send.py copy from rpython/jit/backend/x86/test/test_send.py copy to rpython/jit/backend/arm/test/test_send.py --- a/rpython/jit/backend/x86/test/test_send.py +++ b/rpython/jit/backend/arm/test/test_send.py @@ -1,10 +1,10 @@ import py from rpython.jit.metainterp.test.test_send import SendTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.rlib import jit -class TestSend(Jit386Mixin, SendTests): +class TestSend(JitARMMixin, SendTests): # for the individual tests see # ====> ../../../metainterp/test/test_send.py def test_call_with_additional_args(self): diff --git a/rpython/jit/backend/x86/test/test_slist.py b/rpython/jit/backend/arm/test/test_slist.py copy from rpython/jit/backend/x86/test/test_slist.py copy to rpython/jit/backend/arm/test/test_slist.py --- a/rpython/jit/backend/x86/test/test_slist.py +++ b/rpython/jit/backend/arm/test/test_slist.py @@ -1,8 +1,8 @@ import py from rpython.jit.metainterp.test import test_slist -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestSList(Jit386Mixin, test_slist.ListTests): +class TestSList(JitARMMixin, test_slist.ListTests): # for the individual tests see # ====> ../../../metainterp/test/test_slist.py def test_list_of_voids(self): diff --git a/rpython/jit/backend/x86/test/test_tl.py b/rpython/jit/backend/arm/test/test_tl.py copy from rpython/jit/backend/x86/test/test_tl.py copy to rpython/jit/backend/arm/test/test_tl.py --- a/rpython/jit/backend/x86/test/test_tl.py +++ b/rpython/jit/backend/arm/test/test_tl.py @@ -1,9 +1,9 @@ import py from rpython.jit.metainterp.test.test_tl import ToyLanguageTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestTL(Jit386Mixin, ToyLanguageTests): +class TestTL(JitARMMixin, ToyLanguageTests): # for the individual tests see # ====> ../../../metainterp/test/test_tl.py pass diff --git a/rpython/jit/backend/x86/test/test_tlc.py b/rpython/jit/backend/arm/test/test_tlc.py copy from rpython/jit/backend/x86/test/test_tlc.py copy to rpython/jit/backend/arm/test/test_tlc.py --- a/rpython/jit/backend/x86/test/test_tlc.py +++ b/rpython/jit/backend/arm/test/test_tlc.py @@ -1,10 +1,10 @@ import py -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_tlc import TLCTests from rpython.jit.tl import tlc -class TestTL(Jit386Mixin, TLCTests): +class TestTL(JitARMMixin, TLCTests): # for the individual tests see # ====> ../../test/test_tlc.py diff --git a/rpython/jit/backend/x86/test/test_virtual.py b/rpython/jit/backend/arm/test/test_virtual.py copy from rpython/jit/backend/x86/test/test_virtual.py copy to rpython/jit/backend/arm/test/test_virtual.py --- a/rpython/jit/backend/x86/test/test_virtual.py +++ b/rpython/jit/backend/arm/test/test_virtual.py @@ -1,10 +1,10 @@ from rpython.jit.metainterp.test.test_virtual import VirtualTests, VirtualMiscTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin class MyClass: pass -class TestsVirtual(Jit386Mixin, VirtualTests): +class TestsVirtual(JitARMMixin, VirtualTests): # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py _new_op = 'new_with_vtable' @@ -14,7 +14,7 @@ def _new(): return MyClass() -class TestsVirtualMisc(Jit386Mixin, VirtualMiscTests): +class TestsVirtualMisc(JitARMMixin, VirtualMiscTests): # for the individual tests see # ====> ../../../metainterp/test/test_virtual.py pass diff --git a/rpython/jit/backend/x86/test/test_virtualizable.py b/rpython/jit/backend/arm/test/test_virtualizable.py copy from rpython/jit/backend/x86/test/test_virtualizable.py copy to rpython/jit/backend/arm/test/test_virtualizable.py --- a/rpython/jit/backend/x86/test/test_virtualizable.py +++ b/rpython/jit/backend/arm/test/test_virtualizable.py @@ -1,8 +1,8 @@ import py from rpython.jit.metainterp.test.test_virtualizable import ImplicitVirtualizableTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestVirtualizable(Jit386Mixin, ImplicitVirtualizableTests): +class TestVirtualizable(JitARMMixin, ImplicitVirtualizableTests): def test_blackhole_should_not_reenter(self): py.test.skip("Assertion error & llinterp mess") diff --git a/rpython/jit/backend/x86/test/test_virtualref.py b/rpython/jit/backend/arm/test/test_virtualref.py copy from rpython/jit/backend/x86/test/test_virtualref.py copy to rpython/jit/backend/arm/test/test_virtualref.py --- a/rpython/jit/backend/x86/test/test_virtualref.py +++ b/rpython/jit/backend/arm/test/test_virtualref.py @@ -1,8 +1,8 @@ from rpython.jit.metainterp.test.test_virtualref import VRefTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestVRef(Jit386Mixin, VRefTests): +class TestVRef(JitARMMixin, VRefTests): # for the individual tests see # ====> ../../../metainterp/test/test_virtualref.py pass diff --git a/rpython/jit/metainterp/test/test_rawmem.py b/rpython/jit/metainterp/test/test_rawmem.py --- a/rpython/jit/metainterp/test/test_rawmem.py +++ b/rpython/jit/metainterp/test/test_rawmem.py @@ -48,8 +48,8 @@ def test_raw_storage_float(self): def f(): p = alloc_raw_storage(15) - raw_storage_setitem(p, 3, 2.4e15) - res = raw_storage_getitem(lltype.Float, p, 3) + raw_storage_setitem(p, 4, 2.4e15) + res = raw_storage_getitem(lltype.Float, p, 4) free_raw_storage(p) return res res = self.interp_operations(f, []) diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -458,10 +458,6 @@ if (self.sign != other.sign or self.numdigits() != other.numdigits()): return False - - # Fast path. - if len(self._digits) == len(other._digits): - return self._digits == other._digits i = 0 ld = self.numdigits() diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -259,7 +259,7 @@ if self.config.translation.shared: defines['PYPY_MAIN_FUNCTION'] = "pypy_main_startup" self.eci = self.eci.merge(ExternalCompilationInfo( - export_symbols=["pypy_main_startup"])) + export_symbols=["pypy_main_startup", "pypy_debug_file"])) self.eci, cfile, extra = gen_source(db, modulename, targetdir, self.eci, defines=defines, split=self.split) From noreply at buildbot.pypy.org Wed May 15 14:21:40 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 14:21:40 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Document branch in whatsnew-head.rst. Message-ID: <20130515122140.1EF831C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64149:54393d9aac7c Date: 2013-05-15 14:19 +0200 http://bitbucket.org/pypy/pypy/changeset/54393d9aac7c/ Log: Document branch in whatsnew-head.rst. 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 @@ -7,3 +7,6 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) + + +.. branch: remove-set-smm From noreply at buildbot.pypy.org Wed May 15 14:37:52 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 14:37:52 +0200 (CEST) Subject: [pypy-commit] pypy callback-stacklet: Raaah. That's far, far, far more messy than it looks. Message-ID: <20130515123752.DD12A1C1306@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: callback-stacklet Changeset: r64150:392c42ce5054 Date: 2013-05-15 14:37 +0200 http://bitbucket.org/pypy/pypy/changeset/392c42ce5054/ Log: Raaah. That's far, far, far more messy than it looks. diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -189,16 +189,26 @@ initialframedata.address[0] = llmemory.NULL anchor.address[0] = anchor anchor.address[1] = anchor + # + c = initialframedata + while c: + rffi.stackcounter.stacks_counter -= 1 + c = c.address[1] + ll_assert(rffi.stackcounter.stacks_counter == 1, + "detach_callback_pieces: hum") return initialframedata # def gc_reattach_callback_pieces(pieces): - ll_assert(pieces != llmemory.NULL, "should not be called if NULL") + if pieces == llmemory.NULL: + return ll_assert(pieces.address[0] == llmemory.NULL, "not a correctly detached stack piece") anchor = llmemory.cast_ptr_to_adr(gcrootanchor) lastpiece = pieces + rffi.stackcounter.stacks_counter += 1 while lastpiece.address[1]: lastpiece = lastpiece.address[1] + rffi.stackcounter.stacks_counter += 1 anchor_next = anchor.address[1] lastpiece.address[1] = anchor_next pieces.address[0] = anchor diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -59,7 +59,9 @@ return False else: anchor = self.next_callback_piece - self.next_callback_piece = anchor.address[1] # next + nextaddr = anchor + sizeofaddr + nextaddr = self.translateptr(nextaddr) + self.next_callback_piece = nextaddr.address[0] self.fill_initial_frame(self.curframe, anchor) return True @@ -196,6 +198,7 @@ # stacklet with stacklet_new(). If this call fails, then we # are just returning NULL. _stack_just_closed() + # return _c.new(gcrootfinder.newthrd, llhelper(_c.run_fn, _new_runfn), llmemory.NULL) @@ -208,8 +211,6 @@ gcrootfinder.suspstack.anchor = stackanchor alternateanchor.prev = alternateanchor alternateanchor.next = alternateanchor - gcrootfinder.suspstack.callback_pieces = ( - llop.gc_detach_callback_pieces(llmemory.Address)) def _new_runfn(h, _): # Here, we are in a fresh new stacklet. @@ -263,17 +264,38 @@ # make a fresh new clean SUSPSTACK newsuspstack = lltype.malloc(SUSPSTACK) newsuspstack.handle = _c.null_handle - newsuspstack.callback_pieces = llmemory.NULL self.suspstack = newsuspstack # Invoke '_new_callback' by closing the stack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + newsuspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) return self.get_result_suspstack(h) def switch(self, suspstack): + # Immediately before the switch, 'suspstack' describes the suspended + # state of the *target* of the switch. Then it is theoretically + # freed. In fact what occurs is that we reuse the same 'suspstack' + # object in the target, just after the switch, to store the + # description of where we came from. Then that "other" 'suspstack' + # object is returned. self.suspstack = suspstack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + old_callback_pieces = suspstack.callback_pieces + suspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) + if not h: + self.suspstack.callback_pieces = old_callback_pieces + # return self.get_result_suspstack(h) def attach_handle_on_suspstack(self, handle): @@ -288,10 +310,6 @@ # # Return from a new() or a switch(): 'h' is a handle, possibly # an empty one, that says from where we switched to. - if self.suspstack and self.suspstack.callback_pieces: - llop.gc_reattach_callback_pieces(lltype.Void, - self.suspstack.callback_pieces) - self.suspstack.callback_pieces = llmemory.NULL if not h: raise MemoryError elif _c.is_empty_handle(h): From noreply at buildbot.pypy.org Wed May 15 14:48:29 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 14:48:29 +0200 (CEST) Subject: [pypy-commit] pypy callback-stacklet: (Probable) fix for multi-thread. Message-ID: <20130515124829.395861C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: callback-stacklet Changeset: r64151:1de6e8c03023 Date: 2013-05-15 14:47 +0200 http://bitbucket.org/pypy/pypy/changeset/1de6e8c03023/ Log: (Probable) fix for multi-thread. diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -170,6 +170,9 @@ jit2gc = gctransformer.translator._jit2gc self.frame_tid = jit2gc['frame_tid'] self.gctransformer = gctransformer + # + # unless overridden in need_thread_support(): + self.belongs_to_current_thread = lambda framedata: True def need_stacklet_support(self, gctransformer, getfn): from rpython.annotator import model as annmodel @@ -179,41 +182,38 @@ _stacklet_asmgcc.complete_destrptr(gctransformer) # def gc_detach_callback_pieces(): - # XXX use belongs_to_current_thread() below anchor = llmemory.cast_ptr_to_adr(gcrootanchor) - initialframedata = anchor.address[1] - if initialframedata == anchor: - return llmemory.NULL # empty - lastframedata = anchor.address[0] - lastframedata.address[1] = llmemory.NULL - initialframedata.address[0] = llmemory.NULL - anchor.address[0] = anchor - anchor.address[1] = anchor - # - c = initialframedata - while c: - rffi.stackcounter.stacks_counter -= 1 - c = c.address[1] - ll_assert(rffi.stackcounter.stacks_counter == 1, - "detach_callback_pieces: hum") - return initialframedata + result = llmemory.NULL + framedata = anchor.address[1] + while framedata != anchor: + next = framedata.address[1] + if self.belongs_to_current_thread(framedata): + # detach it + prev = framedata.address[0] + prev.address[1] = next + next.address[0] = prev + # update the global stack counter + rffi.stackcounter.stacks_counter -= 1 + # reattach framedata into the singly-linked list 'result' + framedata.address[0] = rffi.cast(llmemory.Address, -1) + framedata.address[1] = result + result = framedata + framedata = next + return result # def gc_reattach_callback_pieces(pieces): - if pieces == llmemory.NULL: - return - ll_assert(pieces.address[0] == llmemory.NULL, - "not a correctly detached stack piece") anchor = llmemory.cast_ptr_to_adr(gcrootanchor) - lastpiece = pieces - rffi.stackcounter.stacks_counter += 1 - while lastpiece.address[1]: - lastpiece = lastpiece.address[1] + while pieces != llmemory.NULL: + framedata = pieces + pieces = pieces.address[1] + # attach 'framedata' into the normal doubly-linked list + following = anchor.address[1] + following.address[0] = framedata + framedata.address[1] = following + anchor.address[1] = framedata + framedata.address[0] = anchor + # update the global stack counter rffi.stackcounter.stacks_counter += 1 - anchor_next = anchor.address[1] - lastpiece.address[1] = anchor_next - pieces.address[0] = anchor - anchor.address[1] = pieces - anchor_next.address[0] = lastpiece # s_addr = annmodel.SomeAddress() s_None = annmodel.s_None @@ -272,6 +272,7 @@ stack_stop = llop.stack_current(llmemory.Address) return (stack_start <= framedata <= stack_stop or stack_start >= framedata >= stack_stop) + self.belongs_to_current_thread = belongs_to_current_thread def thread_before_fork(): # before fork(): collect all ASM_FRAMEDATA structures that do From noreply at buildbot.pypy.org Wed May 15 15:10:59 2013 From: noreply at buildbot.pypy.org (rlamy) Date: Wed, 15 May 2013 15:10:59 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix for compatibility with CPython 2.7.4 Message-ID: <20130515131059.8D3EE1C009D@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: Changeset: r64152:511204307897 Date: 2013-05-15 14:09 +0100 http://bitbucket.org/pypy/pypy/changeset/511204307897/ Log: Fix for compatibility with CPython 2.7.4 In 2.7.4, sre_compile imports MAX_REPEAT from _sre, so add it to sre_hacked. diff --git a/rpython/rlib/rsre/rpy.py b/rpython/rlib/rsre/rpy.py --- a/rpython/rlib/rsre/rpy.py +++ b/rpython/rlib/rsre/rpy.py @@ -8,11 +8,12 @@ module is a custom module that has _sre.compile == my_compile and CODESIZE == rsre_char.CODESIZE. """ - import sre_compile, __builtin__, new + import sre_compile, sre_constants, __builtin__, new sre_hacked = new.module("_sre_hacked") sre_hacked.compile = my_compile sre_hacked.MAGIC = sre_compile.MAGIC sre_hacked.CODESIZE = rsre_char.CODESIZE + sre_hacked.MAXREPEAT = sre_constants.MAX_REPEAT sre_hacked.getlower = rsre_char.getlower def my_import(name, *args): if name == '_sre': diff --git a/rpython/rlib/rsre/rsre_re.py b/rpython/rlib/rsre/rsre_re.py --- a/rpython/rlib/rsre/rsre_re.py +++ b/rpython/rlib/rsre/rsre_re.py @@ -4,7 +4,7 @@ """ import re, sys from rpython.rlib.rsre import rsre_core, rsre_char -from rpython.rlib.rsre.test.test_match import get_code as _get_code +from rpython.rlib.rsre.rpy import get_code as _get_code from rpython.rlib.unicodedata import unicodedb from rpython.rlib.objectmodel import specialize rsre_char.set_unicode_db(unicodedb) @@ -176,7 +176,7 @@ def span(self, groupnum=0): # if not isinstance(groupnum, (int, long)): # groupnum = self.re.groupindex[groupnum] - + return self._ctx.span(groupnum) def start(self, groupnum=0): From noreply at buildbot.pypy.org Wed May 15 15:19:02 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 15:19:02 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Return NotImplemented instead of raising a TypeError. Message-ID: <20130515131902.982A81C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64153:396dfccfd7be Date: 2013-05-15 14:35 +0200 http://bitbucket.org/pypy/pypy/changeset/396dfccfd7be/ Log: Return NotImplemented instead of raising a TypeError. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -112,9 +112,7 @@ if space.is_w(self, w_other): return space.w_True if not isinstance(w_other, W_DictMultiObject): - raise operationerrfmt(space.w_TypeError, - "Expected dict object, got %s", - space.type(w_other).getname(space)) + return space.w_NotImplemented if self.length() != w_other.length(): return space.w_False @@ -132,9 +130,7 @@ def descr_lt(self, space, w_other): if not isinstance(w_other, W_DictMultiObject): - raise operationerrfmt(space.w_TypeError, - "Expected dict object, got %s", - space.type(w_other).getname(space)) + return space.w_NotImplemented # Different sizes, no problem if self.length() < w_other.length(): From noreply at buildbot.pypy.org Wed May 15 15:19:03 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 15:19:03 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: This is not needed anymore. Message-ID: <20130515131903.E51711C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64154:aeee76c41dad Date: 2013-05-15 14:38 +0200 http://bitbucket.org/pypy/pypy/changeset/aeee76c41dad/ Log: This is not needed anymore. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -416,7 +416,6 @@ setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), update = gateway.interp2app(W_DictMultiObject.descr_update), ) -W_DictMultiObject.typedef.registermethods(globals()) dict_typedef = W_DictMultiObject.typedef From noreply at buildbot.pypy.org Wed May 15 15:19:05 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 15:19:05 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Make __new__, __repr__, and fromkeys (static) methods of W_DictMultiObject. Message-ID: <20130515131905.2DBAD1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64155:5661e54edf85 Date: 2013-05-15 14:55 +0200 http://bitbucket.org/pypy/pypy/changeset/5661e54edf85/ Log: Make __new__, __repr__, and fromkeys (static) methods of W_DictMultiObject. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -105,9 +105,41 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + @staticmethod + def descr_new(space, w_dicttype, __args__): + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + + @staticmethod + def descr_fromkeys(space, w_type, w_keys, w_fill=None): + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + def descr_init(self, space, __args__): init_or_update(space, self, __args__, 'dict') + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, self) + def descr_eq(self, space, w_other): if space.is_w(self, w_other): return space.w_True @@ -307,25 +339,6 @@ _add_indirections() -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - app = gateway.applevel(''' def dictrepr(currently_in_repr, d): @@ -353,22 +366,6 @@ dictrepr = app.interphook("dictrepr") -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - W_DictMultiObject.typedef = StdTypeDef("dict", __doc__ = '''dict() -> new empty dictionary. dict(mapping) -> new dictionary initialized from a mapping object\'s @@ -379,9 +376,11 @@ d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), + __new__ = gateway.interp2app(W_DictMultiObject.descr_new), + fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), + __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), __init__ = gateway.interp2app(W_DictMultiObject.descr_init), __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), @@ -397,7 +396,6 @@ __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), copy = gateway.interp2app(W_DictMultiObject.descr_copy), items = gateway.interp2app(W_DictMultiObject.descr_items), keys = gateway.interp2app(W_DictMultiObject.descr_keys), From noreply at buildbot.pypy.org Wed May 15 15:19:06 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 15:19:06 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Cleanup dictmultiobject.py. Message-ID: <20130515131906.52EF51C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64156:0cd0e3db9235 Date: 2013-05-15 15:12 +0200 http://bitbucket.org/pypy/pypy/changeset/0cd0e3db9235/ Log: Cleanup dictmultiobject.py. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,18 +1,19 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.interpreter import gateway from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature +from pypy.objspace.std.model import registerimplementation, W_Object +from pypy.objspace.std.stdtypedef import StdTypeDef +from rpython.rlib import rerased, jit +from rpython.rlib.debug import mark_dict_non_null from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint -from rpython.rlib.debug import mark_dict_non_null from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib import rerased, jit UNROLL_CUTOFF = 5 + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -261,7 +262,6 @@ def descr_has_key(self, space, w_key): """D.has_key(k) -> True if D has a key k, else False""" - # XXX duplication with contains return space.newbool(self.getitem(w_key) is not None) def descr_clear(self, space): @@ -416,9 +416,10 @@ ) dict_typedef = W_DictMultiObject.typedef +registerimplementation(W_DictMultiObject) + class DictStrategy(object): - def __init__(self, space): self.space = space @@ -483,8 +484,8 @@ def view_as_kwargs(self, w_dict): return (None, None) + class EmptyDictStrategy(DictStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -589,6 +590,7 @@ def getiteritems(self, w_dict): return iter([(None, None)]) + # Iterator Implementation base classes def _new_next(TP): @@ -596,7 +598,7 @@ EMPTY = None else: EMPTY = None, None - + def next(self): if self.dictimplementation is None: return EMPTY @@ -660,7 +662,7 @@ wrapvalue = lambda space, key : key else: wrapvalue = dictimpl.wrapvalue.im_func - + class IterClassKeys(BaseKeyIterator): def __init__(self, space, strategy, impl): self.iterator = strategy.getiterkeys(impl) @@ -712,11 +714,6 @@ create_iterator_classes(EmptyDictStrategy) -registerimplementation(W_DictMultiObject) - -# DictImplementation lattice -# XXX fix me - # concrete subclasses of the above @@ -831,7 +828,6 @@ class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -864,8 +860,8 @@ create_iterator_classes(ObjectDictStrategy) + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -930,7 +926,6 @@ class UnicodeDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("unicode") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -1032,9 +1027,6 @@ create_iterator_classes(IntDictStrategy) -init_signature = Signature(['seq_or_map'], None, 'kwargs') -init_defaults = [None] - def update1(space, w_dict, w_data): if space.findattr(w_data, space.wrap("keys")) is None: @@ -1076,6 +1068,9 @@ w_dict.setitem(w_key, w_value) +init_signature = Signature(['seq_or_map'], None, 'kwargs') +init_defaults = [None] + def init_or_update(space, w_dict, __args__, funcname): w_src, w_kwds = __args__.parse_obj( None, funcname, @@ -1111,7 +1106,6 @@ # ____________________________________________________________ # Iteration - class W_BaseDictMultiIterObject(W_Object): _immutable_fields_ = ["iteratorimplementation"] @@ -1179,12 +1173,12 @@ w_ret = space.newtuple([new_inst, space.newtuple(tup)]) return w_ret - W_BaseDictMultiIterObject.typedef = StdTypeDef("dictionaryiterator", __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint), __reduce__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_reduce), ) + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): def descr_next(self, space): iteratorimplementation = self.iteratorimplementation @@ -1231,6 +1225,7 @@ next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next) ) + # ____________________________________________________________ # Views @@ -1244,7 +1239,6 @@ return space.wrap("%s(%s)" % (space.type(self).getname(space), space.str_w(w_repr))) - def descr_eq(self, space, w_otherview): if not space.eq_w(space.len(self), space.len(w_otherview)): return space.w_False From noreply at buildbot.pypy.org Wed May 15 15:44:02 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 15:44:02 +0200 (CEST) Subject: [pypy-commit] pypy default: test and fix uneven comparisons Message-ID: <20130515134402.CED881C146E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64157:d36d874c476a Date: 2013-05-15 15:43 +0200 http://bitbucket.org/pypy/pypy/changeset/d36d874c476a/ Log: test and fix uneven comparisons 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 @@ -100,11 +100,11 @@ return space.w_True if comp_op == LT or comp_op == LE: if arr1.len < arr2.len: - return space.w_False + return space.w_True + return space.w_False + if arr1.len > arr2.len: return space.w_True - if arr1.len > arr2.len: - return space.w_False - return space.w_True + return space.w_False UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True})) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -552,6 +552,15 @@ assert (a >= c) is False assert (c >= a) is True + a = self.array('i', [-1, 0, 1, 42, 0x7f]) + assert not a == 2*a + assert a != 2*a + assert a < 2*a + assert a <= 2*a + assert not a > 2*a + assert not a >= 2*a + + def test_reduce(self): import pickle a = self.array('i', [1, 2, 3]) From noreply at buildbot.pypy.org Wed May 15 15:46:51 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 15:46:51 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Implement reading subarrays Message-ID: <20130515134651.D3FD51C146E@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64158:3d2788d2e2dd Date: 2013-05-15 15:46 +0200 http://bitbucket.org/pypy/pypy/changeset/3d2788d2e2dd/ Log: Implement reading subarrays diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -324,6 +323,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py --- a/pypy/module/micronumpy/arrayimpl/sort.py +++ b/pypy/module/micronumpy/arrayimpl/sort.py @@ -12,7 +12,7 @@ from rpython.rlib.objectmodel import specialize from pypy.interpreter.error import OperationError from pypy.module.micronumpy.base import W_NDimArray -from pypy.module.micronumpy import interp_dtype, types +from pypy.module.micronumpy import types from pypy.module.micronumpy.iter import AxisIterator INT_SIZE = rffi.sizeof(lltype.Signed) @@ -20,7 +20,7 @@ def make_sort_function(space, itemtype, comp_type, count=1): TP = itemtype.T step = rffi.sizeof(TP) - + class Repr(object): def __init__(self, index_stride_size, stride_size, size, values, indexes, index_start, start): @@ -69,12 +69,13 @@ class ArgArrayRepWithStorage(Repr): def __init__(self, index_stride_size, stride_size, size): + from pypy.module.micronumpy import interp_dtype start = 0 dtype = interp_dtype.get_dtype_cache(space).w_longdtype self.indexes = dtype.itemtype.malloc(size*dtype.get_size()) - self.values = alloc_raw_storage(size * stride_size, + self.values = alloc_raw_storage(size * stride_size, track_allocation=False) - Repr.__init__(self, index_stride_size, stride_size, + Repr.__init__(self, index_stride_size, stride_size, size, self.values, self.indexes, start, start) def __del__(self): @@ -96,7 +97,7 @@ for i in range(stop-start): retval.setitem(i, lst.getitem(i+start)) return retval - + if count < 2: def arg_lt(a, b): # Does numpy do <= ? @@ -108,13 +109,14 @@ return True elif a[0][i] > b[0][i]: return False - # Does numpy do True? + # Does numpy do True? return False ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length, arg_getitem_slice, arg_lt) def argsort(arr, space, w_axis, itemsize): + from pypy.module.micronumpy import interp_dtype if w_axis is space.w_None: # note that it's fine ot pass None here as we're not going # to pass the result around (None is the link to base in slices) @@ -180,7 +182,7 @@ class SortCache(object): built = False - + def __init__(self, space): if self.built: return diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -355,9 +355,11 @@ size = 1 if space.isinstance_w(w_shape, space.w_int): w_shape = space.newtuple([w_shape]) - shape = space.listview(w_shape) - for dim in shape: - size *= space.int_w(dim) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2703,10 +2703,12 @@ from numpypy import dtype, array d = dtype([("x", "int", 3), ("y", "float", 5)]) - a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5])], dtype=d) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) assert (a[0]["x"] == [1, 2, 3]).all() - assert (a[1]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() class AppTestPyPy(BaseNumpyAppTest): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1718,6 +1720,14 @@ for k in range(self.get_element_size()): arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + def read(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, dtype.shape, arr, arr, dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType From noreply at buildbot.pypy.org Wed May 15 15:59:20 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 15:59:20 +0200 (CEST) Subject: [pypy-commit] pypy callback-stacklet: Close branch, ready to merge Message-ID: <20130515135920.0E14D1C14F7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: callback-stacklet Changeset: r64159:917e17ea05f7 Date: 2013-05-15 15:54 +0200 http://bitbucket.org/pypy/pypy/changeset/917e17ea05f7/ Log: Close branch, ready to merge From noreply at buildbot.pypy.org Wed May 15 15:59:21 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 15:59:21 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge callback-stacklet: fixes stacklet when we run with asmgcc and the Message-ID: <20130515135921.B3A7D1C14F7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64160:16589a93fc92 Date: 2013-05-15 15:54 +0200 http://bitbucket.org/pypy/pypy/changeset/16589a93fc92/ Log: Merge callback-stacklet: fixes stacklet when we run with asmgcc and the stack contains C callbacks. diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -170,12 +170,57 @@ jit2gc = gctransformer.translator._jit2gc self.frame_tid = jit2gc['frame_tid'] self.gctransformer = gctransformer + # + # unless overridden in need_thread_support(): + self.belongs_to_current_thread = lambda framedata: True def need_stacklet_support(self, gctransformer, getfn): + from rpython.annotator import model as annmodel + from rpython.rlib import _stacklet_asmgcc # stacklet support: BIG HACK for rlib.rstacklet - from rpython.rlib import _stacklet_asmgcc _stacklet_asmgcc._asmstackrootwalker = self # as a global! argh _stacklet_asmgcc.complete_destrptr(gctransformer) + # + def gc_detach_callback_pieces(): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + result = llmemory.NULL + framedata = anchor.address[1] + while framedata != anchor: + next = framedata.address[1] + if self.belongs_to_current_thread(framedata): + # detach it + prev = framedata.address[0] + prev.address[1] = next + next.address[0] = prev + # update the global stack counter + rffi.stackcounter.stacks_counter -= 1 + # reattach framedata into the singly-linked list 'result' + framedata.address[0] = rffi.cast(llmemory.Address, -1) + framedata.address[1] = result + result = framedata + framedata = next + return result + # + def gc_reattach_callback_pieces(pieces): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + while pieces != llmemory.NULL: + framedata = pieces + pieces = pieces.address[1] + # attach 'framedata' into the normal doubly-linked list + following = anchor.address[1] + following.address[0] = framedata + framedata.address[1] = following + anchor.address[1] = framedata + framedata.address[0] = anchor + # update the global stack counter + rffi.stackcounter.stacks_counter += 1 + # + s_addr = annmodel.SomeAddress() + s_None = annmodel.s_None + self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces, + [], s_addr) + self.gc_reattach_callback_pieces_ptr=getfn(gc_reattach_callback_pieces, + [s_addr], s_None) def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. @@ -227,6 +272,7 @@ stack_stop = llop.stack_current(llmemory.Address) return (stack_start <= framedata <= stack_stop or stack_start >= framedata >= stack_stop) + self.belongs_to_current_thread = belongs_to_current_thread def thread_before_fork(): # before fork(): collect all ASM_FRAMEDATA structures that do diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -800,6 +800,21 @@ def gct_gc_adr_of_root_stack_top(self, hop): self._gc_adr_of_gcdata_attr(hop, 'root_stack_top') + def gct_gc_detach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 0 + hop.genop("direct_call", + [self.root_walker.gc_detach_callback_pieces_ptr], + resultvar=op.result) + + def gct_gc_reattach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 1 + hop.genop("direct_call", + [self.root_walker.gc_reattach_callback_pieces_ptr, + op.args[0]], + resultvar=op.result) + def gct_gc_shadowstackref_new(self, hop): op = hop.spaceop livevars = self.push_roots(hop) diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -32,6 +32,7 @@ if not p.handle: return False self.context = llmemory.cast_ptr_to_adr(p.handle) + self.next_callback_piece = p.callback_pieces anchor = p.anchor del p self.curframe = lltype.malloc(WALKFRAME, flavor='raw') @@ -50,11 +51,19 @@ retaddraddr = self.translateptr(retaddraddr) curframe.frame_address = retaddraddr.address[0] - def teardown(self): - lltype.free(self.curframe, flavor='raw') - lltype.free(self.otherframe, flavor='raw') - self.context = llmemory.NULL - return llmemory.NULL + def fetch_next_stack_piece(self): + if self.next_callback_piece == llmemory.NULL: + lltype.free(self.curframe, flavor='raw') + lltype.free(self.otherframe, flavor='raw') + self.context = llmemory.NULL + return False + else: + anchor = self.next_callback_piece + nextaddr = anchor + sizeofaddr + nextaddr = self.translateptr(nextaddr) + self.next_callback_piece = nextaddr.address[0] + self.fill_initial_frame(self.curframe, anchor) + return True def next(self, obj, prev): # @@ -117,7 +126,10 @@ location) # ^^^ non-translated if caller.frame_address == llmemory.NULL: - return self.teardown() # completely done with this stack + # completely done with this piece of stack + if not self.fetch_next_stack_piece(): + return llmemory.NULL + continue # self.otherframe = callee self.curframe = caller @@ -154,6 +166,7 @@ SUSPSTACK = lltype.GcStruct('SuspStack', ('handle', _c.handle), ('anchor', llmemory.Address), + ('callback_pieces', llmemory.Address), rtti=True) NULL_SUSPSTACK = lltype.nullptr(SUSPSTACK) CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], @@ -185,6 +198,7 @@ # stacklet with stacklet_new(). If this call fails, then we # are just returning NULL. _stack_just_closed() + # return _c.new(gcrootfinder.newthrd, llhelper(_c.run_fn, _new_runfn), llmemory.NULL) @@ -252,14 +266,36 @@ newsuspstack.handle = _c.null_handle self.suspstack = newsuspstack # Invoke '_new_callback' by closing the stack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + newsuspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) return self.get_result_suspstack(h) def switch(self, suspstack): + # Immediately before the switch, 'suspstack' describes the suspended + # state of the *target* of the switch. Then it is theoretically + # freed. In fact what occurs is that we reuse the same 'suspstack' + # object in the target, just after the switch, to store the + # description of where we came from. Then that "other" 'suspstack' + # object is returned. self.suspstack = suspstack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + old_callback_pieces = suspstack.callback_pieces + suspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) + if not h: + self.suspstack.callback_pieces = old_callback_pieces + # return self.get_result_suspstack(h) def attach_handle_on_suspstack(self, handle): diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -82,6 +82,29 @@ return True return False + @here_is_a_test + def test_c_callback(self): + # + self.steps = [0] + self.main_h = self.sthread.new(cb_stacklet_callback, llmemory.NULL) + self.steps.append(2) + call_qsort_rec(10) + self.steps.append(9) + assert not self.sthread.is_empty_handle(self.main_h) + self.main_h = self.sthread.switch(self.main_h) + assert self.sthread.is_empty_handle(self.main_h) + # + # check that self.steps == [0,1,2, 3,4,5,6, 3,4,5,6, 3,4,5,6,..., 9] + print self.steps + expected = 0 + assert self.steps[-1] == 9 + for i in range(len(self.steps)-1): + if expected == 7: + expected = 3 + assert self.steps[i] == expected + expected += 1 + assert expected == 7 + class FooObj: def __init__(self, n, d, next=None): @@ -211,6 +234,43 @@ print "LEAVING %d to go to %d" % (self.n, n) return h +QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType( + [llmemory.Address, llmemory.Address], rffi.INT)) +qsort = rffi.llexternal('qsort', + [llmemory.Address, rffi.SIZE_T, rffi.SIZE_T, + QSORT_CALLBACK_PTR], + lltype.Void) +def cb_compare_callback(a, b): + runner.steps.append(3) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.main_h = runner.sthread.switch(runner.main_h) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.steps.append(6) + return rffi.cast(rffi.INT, 1) +def cb_stacklet_callback(h, arg): + runner.steps.append(1) + while True: + assert not runner.sthread.is_empty_handle(h) + h = runner.sthread.switch(h) + assert not runner.sthread.is_empty_handle(h) + if runner.steps[-1] == 9: + return h + runner.steps.append(4) + rgc.collect() + runner.steps.append(5) +class GcObject(object): + num = 1234 +def call_qsort_rec(r): + if r > 0: + g = GcObject() + g.num += r + call_qsort_rec(r - 1) + assert g.num == 1234 + r + else: + raw = llmemory.raw_malloc(5) + qsort(raw, 5, 1, cb_compare_callback) + llmemory.raw_free(raw) + def entry_point(argv): seed = 0 diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -886,6 +886,11 @@ def op_gc_stack_bottom(self): pass # marker for trackgcroot.py + def op_gc_detach_callback_pieces(self): + raise NotImplementedError("gc_detach_callback_pieces") + def op_gc_reattach_callback_pieces(self): + raise NotImplementedError("gc_reattach_callback_pieces") + def op_gc_shadowstackref_new(self): # stacklet+shadowstack raise NotImplementedError("gc_shadowstackref_new") def op_gc_shadowstackref_context(self): diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py --- a/rpython/rtyper/lltypesystem/lloperation.py +++ b/rpython/rtyper/lltypesystem/lloperation.py @@ -516,6 +516,10 @@ 'gc_asmgcroot_static': LLOp(sideeffects=False), 'gc_stack_bottom': LLOp(canrun=True), + # for stacklet+asmgcroot support + 'gc_detach_callback_pieces': LLOp(), + 'gc_reattach_callback_pieces': LLOp(), + # for stacklet+shadowstack support 'gc_shadowstackref_new': LLOp(canmallocgc=True), 'gc_shadowstackref_context': LLOp(), From noreply at buildbot.pypy.org Wed May 15 15:59:23 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 15:59:23 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: callback-stacklet: merge it manually in release-2.0.x. Message-ID: <20130515135923.17D191C14F7@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64161:1a64ef0e9672 Date: 2013-05-15 15:58 +0200 http://bitbucket.org/pypy/pypy/changeset/1a64ef0e9672/ Log: callback-stacklet: merge it manually in release-2.0.x. diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -170,12 +170,57 @@ jit2gc = gctransformer.translator._jit2gc self.frame_tid = jit2gc['frame_tid'] self.gctransformer = gctransformer + # + # unless overridden in need_thread_support(): + self.belongs_to_current_thread = lambda framedata: True def need_stacklet_support(self, gctransformer, getfn): + from rpython.annotator import model as annmodel + from rpython.rlib import _stacklet_asmgcc # stacklet support: BIG HACK for rlib.rstacklet - from rpython.rlib import _stacklet_asmgcc _stacklet_asmgcc._asmstackrootwalker = self # as a global! argh _stacklet_asmgcc.complete_destrptr(gctransformer) + # + def gc_detach_callback_pieces(): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + result = llmemory.NULL + framedata = anchor.address[1] + while framedata != anchor: + next = framedata.address[1] + if self.belongs_to_current_thread(framedata): + # detach it + prev = framedata.address[0] + prev.address[1] = next + next.address[0] = prev + # update the global stack counter + rffi.stackcounter.stacks_counter -= 1 + # reattach framedata into the singly-linked list 'result' + framedata.address[0] = rffi.cast(llmemory.Address, -1) + framedata.address[1] = result + result = framedata + framedata = next + return result + # + def gc_reattach_callback_pieces(pieces): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + while pieces != llmemory.NULL: + framedata = pieces + pieces = pieces.address[1] + # attach 'framedata' into the normal doubly-linked list + following = anchor.address[1] + following.address[0] = framedata + framedata.address[1] = following + anchor.address[1] = framedata + framedata.address[0] = anchor + # update the global stack counter + rffi.stackcounter.stacks_counter += 1 + # + s_addr = annmodel.SomeAddress() + s_None = annmodel.s_None + self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces, + [], s_addr) + self.gc_reattach_callback_pieces_ptr=getfn(gc_reattach_callback_pieces, + [s_addr], s_None) def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. @@ -227,6 +272,7 @@ stack_stop = llop.stack_current(llmemory.Address) return (stack_start <= framedata <= stack_stop or stack_start >= framedata >= stack_stop) + self.belongs_to_current_thread = belongs_to_current_thread def thread_before_fork(): # before fork(): collect all ASM_FRAMEDATA structures that do diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -800,6 +800,21 @@ def gct_gc_adr_of_root_stack_top(self, hop): self._gc_adr_of_gcdata_attr(hop, 'root_stack_top') + def gct_gc_detach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 0 + hop.genop("direct_call", + [self.root_walker.gc_detach_callback_pieces_ptr], + resultvar=op.result) + + def gct_gc_reattach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 1 + hop.genop("direct_call", + [self.root_walker.gc_reattach_callback_pieces_ptr, + op.args[0]], + resultvar=op.result) + def gct_gc_shadowstackref_new(self, hop): op = hop.spaceop livevars = self.push_roots(hop) diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -32,6 +32,7 @@ if not p.handle: return False self.context = llmemory.cast_ptr_to_adr(p.handle) + self.next_callback_piece = p.callback_pieces anchor = p.anchor del p self.curframe = lltype.malloc(WALKFRAME, flavor='raw') @@ -50,11 +51,19 @@ retaddraddr = self.translateptr(retaddraddr) curframe.frame_address = retaddraddr.address[0] - def teardown(self): - lltype.free(self.curframe, flavor='raw') - lltype.free(self.otherframe, flavor='raw') - self.context = llmemory.NULL - return llmemory.NULL + def fetch_next_stack_piece(self): + if self.next_callback_piece == llmemory.NULL: + lltype.free(self.curframe, flavor='raw') + lltype.free(self.otherframe, flavor='raw') + self.context = llmemory.NULL + return False + else: + anchor = self.next_callback_piece + nextaddr = anchor + sizeofaddr + nextaddr = self.translateptr(nextaddr) + self.next_callback_piece = nextaddr.address[0] + self.fill_initial_frame(self.curframe, anchor) + return True def next(self, obj, prev): # @@ -117,7 +126,10 @@ location) # ^^^ non-translated if caller.frame_address == llmemory.NULL: - return self.teardown() # completely done with this stack + # completely done with this piece of stack + if not self.fetch_next_stack_piece(): + return llmemory.NULL + continue # self.otherframe = callee self.curframe = caller @@ -154,6 +166,7 @@ SUSPSTACK = lltype.GcStruct('SuspStack', ('handle', _c.handle), ('anchor', llmemory.Address), + ('callback_pieces', llmemory.Address), rtti=True) NULL_SUSPSTACK = lltype.nullptr(SUSPSTACK) CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], @@ -185,6 +198,7 @@ # stacklet with stacklet_new(). If this call fails, then we # are just returning NULL. _stack_just_closed() + # return _c.new(gcrootfinder.newthrd, llhelper(_c.run_fn, _new_runfn), llmemory.NULL) @@ -252,14 +266,36 @@ newsuspstack.handle = _c.null_handle self.suspstack = newsuspstack # Invoke '_new_callback' by closing the stack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + newsuspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) return self.get_result_suspstack(h) def switch(self, suspstack): + # Immediately before the switch, 'suspstack' describes the suspended + # state of the *target* of the switch. Then it is theoretically + # freed. In fact what occurs is that we reuse the same 'suspstack' + # object in the target, just after the switch, to store the + # description of where we came from. Then that "other" 'suspstack' + # object is returned. self.suspstack = suspstack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + old_callback_pieces = suspstack.callback_pieces + suspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) + if not h: + self.suspstack.callback_pieces = old_callback_pieces + # return self.get_result_suspstack(h) def attach_handle_on_suspstack(self, handle): diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -82,6 +82,29 @@ return True return False + @here_is_a_test + def test_c_callback(self): + # + self.steps = [0] + self.main_h = self.sthread.new(cb_stacklet_callback, llmemory.NULL) + self.steps.append(2) + call_qsort_rec(10) + self.steps.append(9) + assert not self.sthread.is_empty_handle(self.main_h) + self.main_h = self.sthread.switch(self.main_h) + assert self.sthread.is_empty_handle(self.main_h) + # + # check that self.steps == [0,1,2, 3,4,5,6, 3,4,5,6, 3,4,5,6,..., 9] + print self.steps + expected = 0 + assert self.steps[-1] == 9 + for i in range(len(self.steps)-1): + if expected == 7: + expected = 3 + assert self.steps[i] == expected + expected += 1 + assert expected == 7 + class FooObj: def __init__(self, n, d, next=None): @@ -211,6 +234,43 @@ print "LEAVING %d to go to %d" % (self.n, n) return h +QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType( + [llmemory.Address, llmemory.Address], rffi.INT)) +qsort = rffi.llexternal('qsort', + [llmemory.Address, rffi.SIZE_T, rffi.SIZE_T, + QSORT_CALLBACK_PTR], + lltype.Void) +def cb_compare_callback(a, b): + runner.steps.append(3) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.main_h = runner.sthread.switch(runner.main_h) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.steps.append(6) + return rffi.cast(rffi.INT, 1) +def cb_stacklet_callback(h, arg): + runner.steps.append(1) + while True: + assert not runner.sthread.is_empty_handle(h) + h = runner.sthread.switch(h) + assert not runner.sthread.is_empty_handle(h) + if runner.steps[-1] == 9: + return h + runner.steps.append(4) + rgc.collect() + runner.steps.append(5) +class GcObject(object): + num = 1234 +def call_qsort_rec(r): + if r > 0: + g = GcObject() + g.num += r + call_qsort_rec(r - 1) + assert g.num == 1234 + r + else: + raw = llmemory.raw_malloc(5) + qsort(raw, 5, 1, cb_compare_callback) + llmemory.raw_free(raw) + def entry_point(argv): seed = 0 diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -886,6 +886,11 @@ def op_gc_stack_bottom(self): pass # marker for trackgcroot.py + def op_gc_detach_callback_pieces(self): + raise NotImplementedError("gc_detach_callback_pieces") + def op_gc_reattach_callback_pieces(self): + raise NotImplementedError("gc_reattach_callback_pieces") + def op_gc_shadowstackref_new(self): # stacklet+shadowstack raise NotImplementedError("gc_shadowstackref_new") def op_gc_shadowstackref_context(self): diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py --- a/rpython/rtyper/lltypesystem/lloperation.py +++ b/rpython/rtyper/lltypesystem/lloperation.py @@ -516,6 +516,10 @@ 'gc_asmgcroot_static': LLOp(sideeffects=False), 'gc_stack_bottom': LLOp(canrun=True), + # for stacklet+asmgcroot support + 'gc_detach_callback_pieces': LLOp(), + 'gc_reattach_callback_pieces': LLOp(), + # for stacklet+shadowstack support 'gc_shadowstackref_new': LLOp(canmallocgc=True), 'gc_shadowstackref_context': LLOp(), From noreply at buildbot.pypy.org Wed May 15 16:02:21 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 16:02:21 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Add a test case Message-ID: <20130515140221.25B151C15CC@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64162:3cb776037bac Date: 2013-05-15 16:00 +0200 http://bitbucket.org/pypy/pypy/changeset/3cb776037bac/ Log: Add a test case diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2710,6 +2710,9 @@ assert (a[1]["x"] == [4, 5, 6]).all() assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): From noreply at buildbot.pypy.org Wed May 15 16:02:22 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 16:02:22 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Fix dtype test Message-ID: <20130515140222.4A5B41C15CC@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64163:217977b64ee9 Date: 2013-05-15 16:00 +0200 http://bitbucket.org/pypy/pypy/changeset/217977b64ee9/ Log: Fix dtype test diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -114,10 +114,11 @@ return space.wrap(self.itemtype.alignment) def descr_get_subdtype(self, space): - return space.newtuple([space.wrap(self.subdtype), space.newtuple(self.shape)]) + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) def descr_get_shape(self, space): - return space.newtuple(self.shape) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) From noreply at buildbot.pypy.org Wed May 15 16:10:33 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 16:10:33 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Update what's new Message-ID: <20130515141033.F20BD1C1106@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64164:b9472c2ddba2 Date: 2013-05-15 16:05 +0200 http://bitbucket.org/pypy/pypy/changeset/b9472c2ddba2/ Log: Update what's new 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 @@ -7,3 +7,6 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) + +.. branch: numpy-subarrays +It is now possible to create arrays and dtypes that use subarrays From noreply at buildbot.pypy.org Wed May 15 16:10:35 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 16:10:35 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Close branch Message-ID: <20130515141035.2896C1C1106@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64165:fb172a8e9a67 Date: 2013-05-15 16:05 +0200 http://bitbucket.org/pypy/pypy/changeset/fb172a8e9a67/ Log: Close branch From noreply at buildbot.pypy.org Wed May 15 16:10:36 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 16:10:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge numpy-subarrays Message-ID: <20130515141036.8F6DD1C1106@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: Changeset: r64166:1168b982d455 Date: 2013-05-15 16:06 +0200 http://bitbucket.org/pypy/pypy/changeset/1168b982d455/ Log: Merge numpy-subarrays 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 @@ -7,3 +7,6 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) + +.. branch: numpy-subarrays +It is now possible to create arrays and dtypes that use subarrays diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -324,6 +323,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py --- a/pypy/module/micronumpy/arrayimpl/sort.py +++ b/pypy/module/micronumpy/arrayimpl/sort.py @@ -12,7 +12,7 @@ from rpython.rlib.objectmodel import specialize from pypy.interpreter.error import OperationError from pypy.module.micronumpy.base import W_NDimArray -from pypy.module.micronumpy import interp_dtype, types +from pypy.module.micronumpy import types from pypy.module.micronumpy.iter import AxisIterator INT_SIZE = rffi.sizeof(lltype.Signed) @@ -20,7 +20,7 @@ def make_sort_function(space, itemtype, comp_type, count=1): TP = itemtype.T step = rffi.sizeof(TP) - + class Repr(object): def __init__(self, index_stride_size, stride_size, size, values, indexes, index_start, start): @@ -69,12 +69,13 @@ class ArgArrayRepWithStorage(Repr): def __init__(self, index_stride_size, stride_size, size): + from pypy.module.micronumpy import interp_dtype start = 0 dtype = interp_dtype.get_dtype_cache(space).w_longdtype self.indexes = dtype.itemtype.malloc(size*dtype.get_size()) - self.values = alloc_raw_storage(size * stride_size, + self.values = alloc_raw_storage(size * stride_size, track_allocation=False) - Repr.__init__(self, index_stride_size, stride_size, + Repr.__init__(self, index_stride_size, stride_size, size, self.values, self.indexes, start, start) def __del__(self): @@ -96,7 +97,7 @@ for i in range(stop-start): retval.setitem(i, lst.getitem(i+start)) return retval - + if count < 2: def arg_lt(a, b): # Does numpy do <= ? @@ -108,13 +109,14 @@ return True elif a[0][i] > b[0][i]: return False - # Does numpy do True? + # Does numpy do True? return False ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length, arg_getitem_slice, arg_lt) def argsort(arr, space, w_axis, itemsize): + from pypy.module.micronumpy import interp_dtype if w_axis is space.w_None: # note that it's fine ot pass None here as we're not going # to pass the result around (None is the link to base in slices) @@ -180,7 +182,7 @@ class SortCache(object): built = False - + def __init__(self, space): if self.built: return diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,8 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype @specialize.argtype(1) def box(self, value): @@ -111,8 +113,12 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -279,15 +285,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -333,10 +346,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +382,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +420,7 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -723,7 +723,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -790,6 +790,26 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype("float64"), (10,)) + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2699,6 +2699,20 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1696,10 +1698,36 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def coerce(self, space, dtype, w_items): + items_w = space.fixedview(w_items) + arr = VoidBoxStorage(self.size, dtype) + ofs = 0 + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + + def read(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, dtype.shape, arr, arr, dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1733,7 +1761,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) From noreply at buildbot.pypy.org Wed May 15 16:55:58 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 16:55:58 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Remove setobject/frozensetobject from multimethod table Message-ID: <20130515145558.D17471C14F7@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-set-smm Changeset: r64167:9ebc7d2a3cd7 Date: 2013-05-15 16:47 +0200 http://bitbucket.org/pypy/pypy/changeset/9ebc7d2a3cd7/ Log: Remove setobject/frozensetobject from multimethod table diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -38,8 +38,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.setobject import set_typedef - from pypy.objspace.std.setobject import frozenset_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.dicttype import dict_typedef @@ -63,10 +61,10 @@ from pypy.objspace.std import intobject from pypy.objspace.std import floatobject from pypy.objspace.std import complexobject - from pypy.objspace.std import setobject from pypy.objspace.std import tupleobject from pypy.objspace.std import listobject from pypy.objspace.std import dictmultiobject + from pypy.objspace.std import setobject from pypy.objspace.std import stringobject from pypy.objspace.std import bytearrayobject from pypy.objspace.std import typeobject @@ -81,6 +79,11 @@ import pypy.objspace.std.marshal_impl # install marshal multimethods + # not-multimethod based types + + self.pythontypes.append(setobject.W_SetObject.typedef) + self.pythontypes.append(setobject.W_FrozensetObject.typedef) + # the set of implementation types self.typeorder = { objectobject.W_ObjectObject: [], @@ -100,10 +103,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - setobject.W_BaseSetObject: [], - setobject.W_SetObject: [], - setobject.W_FrozensetObject: [], - setobject.W_SetIterObject: [], iterobject.W_SeqIterObject: [], iterobject.W_FastListIterObject: [], iterobject.W_FastTupleIterObject: [], @@ -192,12 +191,7 @@ (complexobject.W_ComplexObject, complexobject.delegate_Float2Complex), ] - self.typeorder[setobject.W_SetObject] += [ - (setobject.W_BaseSetObject, None) - ] - self.typeorder[setobject.W_FrozensetObject] += [ - (setobject.W_BaseSetObject, None) - ] + self.typeorder[stringobject.W_StringObject] += [ (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode), ] diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -1,7 +1,7 @@ -from pypy.objspace.std.model import registerimplementation, W_Object from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.interpreter.signature import Signature +from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringobject import W_StringObject @@ -15,7 +15,7 @@ UNROLL_CUTOFF = 5 -class W_BaseSetObject(W_Object): +class W_BaseSetObject(W_Root): typedef = None def __init__(w_self, space, w_iterable=None): @@ -657,10 +657,6 @@ frozenset_typedef = W_FrozensetObject.typedef -registerimplementation(W_BaseSetObject) -registerimplementation(W_SetObject) -registerimplementation(W_FrozensetObject) - class SetStrategy(object): def __init__(self, space): @@ -1441,9 +1437,7 @@ return None -class W_SetIterObject(W_Object): - # XXX this class should be killed, and the various - # iterimplementations should be W_Objects directly. +class W_SetIterObject(W_Root): def __init__(w_self, space, iterimplementation): w_self.space = space @@ -1469,7 +1463,6 @@ ) setiter_typedef = W_SetIterObject.typedef -registerimplementation(W_SetIterObject) # some helper functions From noreply at buildbot.pypy.org Wed May 15 17:02:13 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 15 May 2013 17:02:13 +0200 (CEST) Subject: [pypy-commit] pypy default: some random cleanups Message-ID: <20130515150213.73FEF1C1106@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64168:46a67ac72e3b Date: 2013-05-15 07:53 -0700 http://bitbucket.org/pypy/pypy/changeset/46a67ac72e3b/ Log: some random cleanups diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -339,8 +339,9 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(w_self, space): - raise UnwrapError, 'cannot unwrap %r' % (w_self,) + def unwrap(self, space): + raise UnwrapError('cannot unwrap %r' % self) + class UnwrapError(Exception): pass @@ -405,7 +406,7 @@ mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree) return mm -NOT_MULTIMETHODS = dict.fromkeys( +NOT_MULTIMETHODS = set( ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv', 'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift', 'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel', From noreply at buildbot.pypy.org Wed May 15 17:02:15 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 15 May 2013 17:02:15 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20130515150215.404191C1106@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64169:3fcecc6975a6 Date: 2013-05-15 07:53 -0700 http://bitbucket.org/pypy/pypy/changeset/3fcecc6975a6/ Log: merged upstream 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 @@ -7,3 +7,6 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) + +.. branch: numpy-subarrays +It is now possible to create arrays and dtypes that use subarrays diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -324,6 +323,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py --- a/pypy/module/micronumpy/arrayimpl/sort.py +++ b/pypy/module/micronumpy/arrayimpl/sort.py @@ -12,7 +12,7 @@ from rpython.rlib.objectmodel import specialize from pypy.interpreter.error import OperationError from pypy.module.micronumpy.base import W_NDimArray -from pypy.module.micronumpy import interp_dtype, types +from pypy.module.micronumpy import types from pypy.module.micronumpy.iter import AxisIterator INT_SIZE = rffi.sizeof(lltype.Signed) @@ -20,7 +20,7 @@ def make_sort_function(space, itemtype, comp_type, count=1): TP = itemtype.T step = rffi.sizeof(TP) - + class Repr(object): def __init__(self, index_stride_size, stride_size, size, values, indexes, index_start, start): @@ -69,12 +69,13 @@ class ArgArrayRepWithStorage(Repr): def __init__(self, index_stride_size, stride_size, size): + from pypy.module.micronumpy import interp_dtype start = 0 dtype = interp_dtype.get_dtype_cache(space).w_longdtype self.indexes = dtype.itemtype.malloc(size*dtype.get_size()) - self.values = alloc_raw_storage(size * stride_size, + self.values = alloc_raw_storage(size * stride_size, track_allocation=False) - Repr.__init__(self, index_stride_size, stride_size, + Repr.__init__(self, index_stride_size, stride_size, size, self.values, self.indexes, start, start) def __del__(self): @@ -96,7 +97,7 @@ for i in range(stop-start): retval.setitem(i, lst.getitem(i+start)) return retval - + if count < 2: def arg_lt(a, b): # Does numpy do <= ? @@ -108,13 +109,14 @@ return True elif a[0][i] > b[0][i]: return False - # Does numpy do True? + # Does numpy do True? return False ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length, arg_getitem_slice, arg_lt) def argsort(arr, space, w_axis, itemsize): + from pypy.module.micronumpy import interp_dtype if w_axis is space.w_None: # note that it's fine ot pass None here as we're not going # to pass the result around (None is the link to base in slices) @@ -180,7 +182,7 @@ class SortCache(object): built = False - + def __init__(self, space): if self.built: return diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,8 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype @specialize.argtype(1) def box(self, value): @@ -111,8 +113,12 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -279,15 +285,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -333,10 +346,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +382,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +420,7 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -723,7 +723,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -790,6 +790,26 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype("float64"), (10,)) + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2699,6 +2699,20 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1696,10 +1698,36 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def coerce(self, space, dtype, w_items): + items_w = space.fixedview(w_items) + arr = VoidBoxStorage(self.size, dtype) + ofs = 0 + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + + def read(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, dtype.shape, arr, arr, dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1733,7 +1761,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) From noreply at buildbot.pypy.org Wed May 15 17:08:34 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 17:08:34 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Merge default Message-ID: <20130515150834.C72051C3000@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64170:3cc58301a108 Date: 2013-05-15 16:11 +0200 http://bitbucket.org/pypy/pypy/changeset/3cc58301a108/ Log: Merge default diff too long, truncating to 2000 out of 6616 lines 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 @@ -119,13 +119,13 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: - cflags = os.environ["CFLAGS"] - compiler.compiler.append(cflags) - compiler.compiler_so.append(cflags) - compiler.linker_so.append(cflags) + cflags = os.environ["CFLAGS"].split() + compiler.compiler.extend(cflags) + compiler.compiler_so.extend(cflags) + compiler.linker_so.extend(cflags) from sysconfig_cpython import ( diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,10 +32,11 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", - "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", + "thread", "itertools", "pyexpat", "_ssl", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_ffi", - "_continuation", "_cffi_backend", "_csv", "cppyy"] + "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"] +# disabled until problems are fixed )) translation_modules = default_modules.copy() @@ -91,7 +92,7 @@ # itself needs the interp-level struct module # because 'P' is missing from the app-level one "_rawffi": [("objspace.usemodules.struct", True)], - "cpyext": [("translation.secondaryentrypoints", "cpyext"), + "cpyext": [("translation.secondaryentrypoints", "cpyext,main"), ("translation.shared", sys.platform == "win32")], } diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0-beta1' +release = '2.0.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -105,7 +105,7 @@ $ ./pypy-c Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``RPython magically makes you rich and famous (says so on the tin)'' @@ -235,7 +235,7 @@ the ``bin/pypy`` executable. To install PyPy system wide on unix-like systems, it is recommended to put the -whole hierarchy alone (e.g. in ``/opt/pypy2.0-beta1``) and put a symlink to the +whole hierarchy alone (e.g. in ``/opt/pypy2.0``) and put a symlink to the ``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -53,10 +53,10 @@ PyPy is ready to be executed as soon as you unpack the tarball or the zip file, with no need to install it in any specific location:: - $ tar xf pypy-2.0-beta1-linux.tar.bz2 - $ ./pypy-2.0-beta1/bin/pypy + $ tar xf pypy-2.0.tar.bz2 + $ ./pypy-2.0/bin/pypy Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``PyPy is an exciting technology that lets you to write fast, portable, multi-platform interpreters with less @@ -75,14 +75,14 @@ $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.0-beta1/bin/pypy distribute_setup.py + $ ./pypy-2.0/bin/pypy distribute_setup.py - $ ./pypy-2.0-beta1/bin/pypy get-pip.py + $ ./pypy-2.0/bin/pypy get-pip.py - $ ./pypy-2.0-beta1/bin/pip install pygments # for example + $ ./pypy-2.0/bin/pip install pygments # for example -3rd party libraries will be installed in ``pypy-2.0-beta1/site-packages``, and -the scripts in ``pypy-2.0-beta1/bin``. +3rd party libraries will be installed in ``pypy-2.0/site-packages``, and +the scripts in ``pypy-2.0/bin``. Installing using virtualenv --------------------------- diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0 beta 2`_: the latest official release +* `Release 2.0`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0 beta 2`: http://pypy.org/download.html +.. _`Release 2.0`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -4,6 +4,8 @@ We're pleased to announce PyPy 2.0. This is a stable release that brings a swath of bugfixes, small performance improvements and compatibility fixes. +PyPy 2.0 is a big step for us and we hope in the future we'll be able to +provide stable releases more often. You can download the PyPy 2.0 release here: @@ -19,6 +21,10 @@ .. _`cffi`: http://cffi.readthedocs.org +If you're using PyPy for anything, it would help us immensely if you fill out +the following survey: http://bit.ly/pypysurvey This is for the developers +eyes and we will not make any information public without your agreement. + What is PyPy? ============= @@ -28,8 +34,8 @@ This release supports x86 machines running Linux 32/64, Mac OS X 64 or Windows 32. Windows 64 work is still stalling, we would welcome a volunteer -to handle that. ARM support is on the way and we're expecting to release -an alpha ARM version shortly. +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. .. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org @@ -54,6 +60,10 @@ * A lot of stability issues fixed. +* Refactoring much of the numpypy array classes, which resulted in removal of + lazy expression evaluation. On the other hand, we now have more complete + dtype support and support more array attributes. + .. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ .. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks 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 @@ -7,3 +7,6 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) + +.. branch: numpy-subarrays +It is now possible to create arrays and dtypes that use subarrays diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -8,7 +8,9 @@ arch = 'linux' cmd = 'wget "%s"' tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" -if sys.platform.startswith('darwin'): + if os.uname()[-1].startswith('arm'): + arch += '-armhf-raspbian' +elif sys.platform.startswith('darwin'): arch = 'osx' cmd = 'curl -O "%s"' tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -2,6 +2,7 @@ import os, sys +import pypy from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.tool.ann_override import PyPyAnnotatorPolicy @@ -22,20 +23,22 @@ # __________ Entry point __________ + def create_entry_point(space, w_dict): - w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) - w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) - w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) - w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) - withjit = space.config.objspace.usemodules.pypyjit + if w_dict is not None: # for tests + w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) + w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) + w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) + w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) + withjit = space.config.objspace.usemodules.pypyjit def entry_point(argv): if withjit: from rpython.jit.backend.hlinfo import highleveljitinfo highleveljitinfo.sys_executable = argv[0] - #debug("entry point starting") - #for arg in argv: + #debug("entry point starting") + #for arg in argv: # debug(" argv -> " + arg) if len(argv) > 2 and argv[1] == '--heapsize': # Undocumented option, handled at interp-level. @@ -71,7 +74,70 @@ debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 return exitcode - return entry_point + + # register the minimal equivalent of running a small piece of code. This + # should be used as sparsely as possible, just to register callbacks + + from rpython.rlib.entrypoint import entrypoint + from rpython.rtyper.lltypesystem import rffi, lltype + + w_pathsetter = space.appexec([], """(): + def f(path): + import sys + sys.path[:] = path + return f + """) + + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') + def pypy_setup_home(ll_home, verbose): + from pypy.module.sys.initpath import pypy_find_stdlib + if ll_home: + home = rffi.charp2str(ll_home) + else: + home = pypydir + w_path = pypy_find_stdlib(space, home) + if space.is_none(w_path): + if verbose: + debug("Failed to find library based on pypy_find_stdlib") + return 1 + space.startup() + space.call_function(w_pathsetter, w_path) + # import site + try: + import_ = space.getattr(space.getbuiltinmodule('__builtin__'), + space.wrap('__import__')) + space.call_function(import_, space.wrap('site')) + return 0 + except OperationError, e: + if verbose: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + + @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') + def pypy_execute_source(ll_source): + source = rffi.charp2str(ll_source) + return _pypy_execute_source(source) + + w_globals = space.newdict() + space.setitem(w_globals, space.wrap('__builtins__'), + space.builtin_modules['__builtin__']) + + def _pypy_execute_source(source): + try: + compiler = space.createcompiler() + stmt = compiler.compile(source, 'c callback', 'exec', 0) + stmt.exec_code(space, w_globals, w_globals) + except OperationError, e: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + return 0 + + return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_setup_home': pypy_setup_home} def call_finish(space): space.finish() @@ -219,7 +285,7 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy, pypy_hooks return PyPyJitPolicy(pypy_hooks) - + def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy rebuild = import_from_lib_pypy('ctypes_config_cache/rebuild') @@ -232,7 +298,7 @@ app = gateway.applevel(open(filename).read(), 'app_main.py', 'app_main') app.hidden_applevel = False w_dict = app.getwdict(space) - entry_point = create_entry_point(space, w_dict) + entry_point, _ = create_entry_point(space, w_dict) return entry_point, None, PyPyAnnotatorPolicy(single_space = space) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -666,7 +666,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -803,7 +803,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -812,11 +811,13 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = {} + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -27,7 +27,7 @@ new_inst = mod.get('generator_new') w = space.wrap if self.frame: - w_frame = w(self.frame) + w_frame = self.frame._reduce_state(space) else: w_frame = space.w_None @@ -36,7 +36,20 @@ w(self.running), ] - return space.newtuple([new_inst, space.newtuple(tup)]) + return space.newtuple([new_inst, space.newtuple([]), + space.newtuple(tup)]) + + def descr__setstate__(self, space, w_args): + from rpython.rlib.objectmodel import instantiate + args_w = space.unpackiterable(w_args) + w_framestate, w_running = args_w + if space.is_w(w_framestate, space.w_None): + self.frame = None + else: + frame = instantiate(space.FrameClass) # XXX fish + frame.descr__setstate__(space, w_framestate) + GeneratorIterator.__init__(self, frame) + self.running = self.space.is_true(w_running) def descr__iter__(self): """x.__iter__() <==> iter(x)""" diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -16,10 +16,9 @@ from rpython.tool.stdlib_opcode import host_bytecode_spec # Define some opcodes used -g = globals() for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY POP_BLOCK END_FINALLY'''.split(): - g[op] = stdlib_opcode.opmap[op] + globals()[op] = stdlib_opcode.opmap[op] HAVE_ARGUMENT = stdlib_opcode.HAVE_ARGUMENT class PyFrame(eval.Frame): @@ -304,11 +303,17 @@ @jit.dont_look_inside def descr__reduce__(self, space): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('frame_new') - w = space.wrap + w_tup_state = self._reduce_state(space) + nt = space.newtuple + return nt([new_inst, nt([]), w_tup_state]) + + @jit.dont_look_inside + def _reduce_state(self, space): + from pypy.module._pickle_support import maker # helper fns + w = space.wrap nt = space.newtuple cells = self._getcells() @@ -359,8 +364,7 @@ w(self.instr_prev_plus_one), w_cells, ] - - return nt([new_inst, nt([]), nt(tup_state)]) + return nt(tup_state) @jit.dont_look_inside def descr__setstate__(self, space, w_args): diff --git a/pypy/interpreter/test2/mymodule.py b/pypy/interpreter/test/mymodule.py rename from pypy/interpreter/test2/mymodule.py rename to pypy/interpreter/test/mymodule.py diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py new file mode 100644 --- /dev/null +++ b/pypy/interpreter/test/test_app_main.py @@ -0,0 +1,966 @@ +""" +Tests for the entry point of pypy-c, app_main.py. +""" +from __future__ import with_statement +import py +import sys, os, re, runpy, subprocess +from rpython.tool.udir import udir +from contextlib import contextmanager +from pypy.conftest import pypydir + +banner = sys.version.splitlines()[0] + +app_main = os.path.join(os.path.realpath(os.path.dirname(__file__)), os.pardir, 'app_main.py') +app_main = os.path.abspath(app_main) + +_counter = 0 +def _get_next_path(ext='.py'): + global _counter + p = udir.join('demo_test_app_main_%d%s' % (_counter, ext)) + _counter += 1 + return p + +def getscript(source): + p = _get_next_path() + p.write(str(py.code.Source(source))) + return str(p) + +def getscript_pyc(space, source): + p = _get_next_path() + p.write(str(py.code.Source(source))) + w_dir = space.wrap(str(p.dirpath())) + w_modname = space.wrap(p.purebasename) + space.appexec([w_dir, w_modname], """(dir, modname): + import sys + d = sys.modules.copy() + sys.path.insert(0, dir) + __import__(modname) + sys.path.pop(0) + for key in sys.modules.keys(): + if key not in d: + del sys.modules[key] + """) + p = str(p) + 'c' + assert os.path.isfile(p) # the .pyc file should have been created above + return p + +def getscript_in_dir(source): + pdir = _get_next_path(ext='') + p = pdir.ensure(dir=1).join('__main__.py') + p.write(str(py.code.Source(source))) + # return relative path for testing purposes + return py.path.local().bestrelpath(pdir) + +demo_script = getscript(""" + print 'hello' + print 'Name:', __name__ + print 'File:', __file__ + import sys + print 'Exec:', sys.executable + print 'Argv:', sys.argv + print 'goodbye' + myvalue = 6*7 + """) + +crashing_demo_script = getscript(""" + print 'Hello2' + myvalue2 = 11 + ooups + myvalue2 = 22 + print 'Goodbye2' # should not be reached + """) + + +class TestParseCommandLine: + def check_options(self, options, sys_argv, **expected): + assert sys.argv == sys_argv + for key, value in expected.items(): + assert options[key] == value + for key, value in options.items(): + if key not in expected: + assert not value, ( + "option %r has unexpectedly the value %r" % (key, value)) + + def check(self, argv, env, **expected): + import StringIO + from pypy.interpreter import app_main + saved_env = os.environ.copy() + saved_sys_argv = sys.argv[:] + saved_sys_stdout = sys.stdout + saved_sys_stderr = sys.stdout + app_main.os = os + try: + os.environ.update(env) + sys.stdout = sys.stderr = StringIO.StringIO() + try: + options = app_main.parse_command_line(argv) + except SystemExit: + output = expected['output_contains'] + assert output in sys.stdout.getvalue() + else: + self.check_options(options, **expected) + finally: + os.environ.clear() + os.environ.update(saved_env) + sys.argv[:] = saved_sys_argv + sys.stdout = saved_sys_stdout + sys.stderr = saved_sys_stderr + + def test_all_combinations_I_can_think_of(self): + self.check([], {}, sys_argv=[''], run_stdin=True) + self.check(['-'], {}, sys_argv=['-'], run_stdin=True) + self.check(['-S'], {}, sys_argv=[''], run_stdin=True, no_site=1) + self.check(['-OO'], {}, sys_argv=[''], run_stdin=True, optimize=2) + self.check(['-O', '-O'], {}, sys_argv=[''], run_stdin=True, optimize=2) + self.check(['-Qnew'], {}, sys_argv=[''], run_stdin=True, division_new=1) + self.check(['-Qold'], {}, sys_argv=[''], run_stdin=True, division_new=0) + self.check(['-Qwarn'], {}, sys_argv=[''], run_stdin=True, division_warning=1) + self.check(['-Qwarnall'], {}, sys_argv=[''], run_stdin=True, + division_warning=2) + self.check(['-Q', 'new'], {}, sys_argv=[''], run_stdin=True, division_new=1) + self.check(['-SOQnew'], {}, sys_argv=[''], run_stdin=True, + no_site=1, optimize=1, division_new=1) + self.check(['-SOQ', 'new'], {}, sys_argv=[''], run_stdin=True, + no_site=1, optimize=1, division_new=1) + self.check(['-i'], {}, sys_argv=[''], run_stdin=True, + interactive=1, inspect=1) + self.check(['-?'], {}, output_contains='usage:') + self.check(['-h'], {}, output_contains='usage:') + self.check(['-S', '-tO', '-h'], {}, output_contains='usage:') + self.check(['-S', '-thO'], {}, output_contains='usage:') + self.check(['-S', '-tO', '--help'], {}, output_contains='usage:') + self.check(['-S', '-tO', '--info'], {}, output_contains='translation') + self.check(['-S', '-tO', '--version'], {}, output_contains='Python') + self.check(['-S', '-tOV'], {}, output_contains='Python') + self.check(['--jit', 'foobar', '-S'], {}, sys_argv=[''], + run_stdin=True, no_site=1) + self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass') + self.check(['-cpass'], {}, sys_argv=['-c'], run_command='pass') + self.check(['-cpass','x'], {}, sys_argv=['-c','x'], run_command='pass') + self.check(['-Sc', 'pass'], {}, sys_argv=['-c'], run_command='pass', + no_site=1) + self.check(['-Scpass'], {}, sys_argv=['-c'], run_command='pass', no_site=1) + self.check(['-c', '', ''], {}, sys_argv=['-c', ''], run_command='') + self.check(['-mfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True) + self.check(['-m', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True) + self.check(['-Smfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True, no_site=1) + self.check(['-Sm', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], + run_module=True, no_site=1) + self.check(['-', 'foo', 'bar'], {}, sys_argv=['-', 'foo', 'bar'], + run_stdin=True) + self.check(['foo', 'bar'], {}, sys_argv=['foo', 'bar']) + self.check(['foo', '-i'], {}, sys_argv=['foo', '-i']) + self.check(['-i', 'foo'], {}, sys_argv=['foo'], interactive=1, inspect=1) + self.check(['--', 'foo'], {}, sys_argv=['foo']) + self.check(['--', '-i', 'foo'], {}, sys_argv=['-i', 'foo']) + self.check(['--', '-', 'foo'], {}, sys_argv=['-', 'foo'], run_stdin=True) + self.check(['-Wbog'], {}, sys_argv=[''], warnoptions=['bog'], run_stdin=True) + self.check(['-W', 'ab', '-SWc'], {}, sys_argv=[''], warnoptions=['ab', 'c'], + run_stdin=True, no_site=1) + + self.check([], {'PYTHONDEBUG': '1'}, sys_argv=[''], run_stdin=True, debug=1) + self.check([], {'PYTHONDONTWRITEBYTECODE': '1'}, sys_argv=[''], run_stdin=True, dont_write_bytecode=1) + self.check([], {'PYTHONNOUSERSITE': '1'}, sys_argv=[''], run_stdin=True, no_user_site=1) + self.check([], {'PYTHONUNBUFFERED': '1'}, sys_argv=[''], run_stdin=True, unbuffered=1) + self.check([], {'PYTHONVERBOSE': '1'}, sys_argv=[''], run_stdin=True, verbose=1) + + def test_sysflags(self): + flags = ( + ("debug", "-d", "1"), + ("py3k_warning", "-3", "1"), + ("division_warning", "-Qwarn", "1"), + ("division_warning", "-Qwarnall", "2"), + ("division_new", "-Qnew", "1"), + (["inspect", "interactive"], "-i", "1"), + ("optimize", "-O", "1"), + ("optimize", "-OO", "2"), + ("dont_write_bytecode", "-B", "1"), + ("no_user_site", "-s", "1"), + ("no_site", "-S", "1"), + ("ignore_environment", "-E", "1"), + ("tabcheck", "-t", "1"), + ("tabcheck", "-tt", "2"), + ("verbose", "-v", "1"), + ("unicode", "-U", "1"), + ("bytes_warning", "-b", "1"), + ) + for flag, opt, value in flags: + if isinstance(flag, list): # this is for inspect&interactive + expected = {} + for flag1 in flag: + expected[flag1] = int(value) + else: + expected = {flag: int(value)} + self.check([opt, '-c', 'pass'], {}, sys_argv=['-c'], + run_command='pass', **expected) + + def test_sysflags_envvar(self, monkeypatch): + monkeypatch.setenv('PYTHONNOUSERSITE', '1') + expected = {"no_user_site": True} + self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass', **expected) + + +class TestInteraction: + """ + These tests require pexpect (UNIX-only). + http://pexpect.sourceforge.net/ + """ + def _spawn(self, *args, **kwds): + try: + import pexpect + except ImportError, e: + py.test.skip(str(e)) + else: + # Version is of the style "0.999" or "2.1". Older versions of + # pexpect try to get the fileno of stdin, which generally won't + # work with py.test (due to sys.stdin being a DontReadFromInput + # instance). + version = map(int, pexpect.__version__.split('.')) + + # I only tested 0.999 and 2.1. The former does not work, the + # latter does. Feel free to refine this measurement. + # -exarkun, 17/12/2007 + if version < [2, 1]: + py.test.skip( + "pexpect version too old, requires 2.1 or newer: %r" % ( + pexpect.__version__,)) + + kwds.setdefault('timeout', 10) + print 'SPAWN:', ' '.join([args[0]] + args[1]), kwds + child = pexpect.spawn(*args, **kwds) + child.logfile = sys.stdout + return child + + def spawn(self, argv): + return self._spawn(sys.executable, [app_main] + argv) + + def test_interactive(self): + child = self.spawn([]) + child.expect('Python ') # banner + child.expect('>>> ') # prompt + child.sendline('[6*7]') + child.expect(re.escape('[42]')) + child.sendline('def f(x):') + child.expect(re.escape('... ')) + child.sendline(' return x + 100') + child.expect(re.escape('... ')) + child.sendline('') + child.expect('>>> ') + child.sendline('f(98)') + child.expect('198') + child.expect('>>> ') + child.sendline('__name__') + child.expect("'__main__'") + child.expect('>>> ') + child.sendline('import sys') + child.expect('>>> ') + child.sendline("'' in sys.path") + child.expect("True") + + def test_help(self): + # test that -h prints the usage, including the name of the executable + # which should be /full/path/to/app_main.py in this case + child = self.spawn(['-h']) + child.expect(r'usage: .*app_main.py \[option\]') + child.expect('PyPy options and arguments:') + + def test_run_script(self): + child = self.spawn([demo_script]) + idx = child.expect(['hello', 'Python ', '>>> ']) + assert idx == 0 # no banner or prompt + child.expect(re.escape("Name: __main__")) + child.expect(re.escape('File: ' + demo_script)) + child.expect(re.escape('Exec: ' + app_main)) + child.expect(re.escape('Argv: ' + repr([demo_script]))) + child.expect('goodbye') + + def test_run_script_with_args(self): + argv = [demo_script, 'hello', 'world'] + child = self.spawn(argv) + child.expect(re.escape('Argv: ' + repr(argv))) + child.expect('goodbye') + + def test_no_such_script(self): + import errno + msg = os.strerror(errno.ENOENT) # 'No such file or directory' + child = self.spawn(['xxx-no-such-file-xxx']) + child.expect(re.escape(msg)) + + def test_option_i(self): + argv = [demo_script, 'foo', 'bar'] + child = self.spawn(['-i'] + argv) + idx = child.expect(['hello', re.escape(banner)]) + assert idx == 0 # no banner + child.expect(re.escape('File: ' + demo_script)) + child.expect(re.escape('Argv: ' + repr(argv))) + child.expect('goodbye') + idx = child.expect(['>>> ', re.escape(banner)]) + assert idx == 0 # prompt, but still no banner + child.sendline('myvalue * 102') + child.expect('4284') + child.sendline('__name__') + child.expect('__main__') + + def test_option_i_crashing(self): + argv = [crashing_demo_script, 'foo', 'bar'] + child = self.spawn(['-i'] + argv) + idx = child.expect(['Hello2', re.escape(banner)]) + assert idx == 0 # no banner + child.expect('NameError') + child.sendline('myvalue2 * 1001') + child.expect('11011') + child.sendline('import sys; sys.argv') + child.expect(re.escape(repr(argv))) + child.sendline('sys.last_type.__name__') + child.expect(re.escape(repr('NameError'))) + + def test_options_i_c(self): + child = self.spawn(['-i', '-c', 'x=555']) + idx = child.expect(['>>> ', re.escape(banner)]) + assert idx == 0 # prompt, but no banner + child.sendline('x') + child.expect('555') + child.sendline('__name__') + child.expect('__main__') + child.sendline('import sys; sys.argv') + child.expect(re.escape("['-c']")) + + def test_options_i_c_crashing(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + child = self.spawn(['-i', '-c', 'x=666;foobar']) + child.expect('NameError') + idx = child.expect(['>>> ', re.escape(banner)]) + assert idx == 0 # prompt, but no banner + child.sendline('x') + child.expect('666') + child.sendline('__name__') + child.expect('__main__') + child.sendline('import sys; sys.argv') + child.expect(re.escape("['-c']")) + child.sendline('sys.last_type.__name__') + child.expect(re.escape(repr('NameError'))) + + def test_atexit(self): + child = self.spawn([]) + child.expect('>>> ') + child.sendline('def f(): print "foobye"') + child.sendline('') + child.sendline('import atexit; atexit.register(f)') + child.sendline('6*7') + child.expect('42') + # pexpect's sendeof() is confused by py.test capturing, though + # I think that it is a bug of sendeof() + old = sys.stdin + try: + sys.stdin = child + child.sendeof() + finally: + sys.stdin = old + child.expect('foobye') + + def test_pythonstartup(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) + child = self.spawn([]) + child.expect(re.escape(banner)) + child.expect('Traceback') + child.expect('NameError') + child.expect('>>> ') + child.sendline('[myvalue2]') + child.expect(re.escape('[11]')) + child.expect('>>> ') + + child = self.spawn(['-i', demo_script]) + for line in ['hello', 'goodbye', '>>> ']: + idx = child.expect([line, 'Hello2']) + assert idx == 0 # no PYTHONSTARTUP run here + child.sendline('myvalue2') + child.expect('Traceback') + child.expect('NameError') + + def test_pythonstartup_file1(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + monkeypatch.setenv('PYTHONSTARTUP', demo_script) + child = self.spawn([]) + child.expect('File: [^\n]+\.py') + child.expect('goodbye') + child.expect('>>> ') + child.sendline('[myvalue]') + child.expect(re.escape('[42]')) + child.expect('>>> ') + child.sendline('__file__') + child.expect('Traceback') + child.expect('NameError') + + def test_pythonstartup_file2(self, monkeypatch): + monkeypatch.setenv('PYTHONPATH', None) + monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) + child = self.spawn([]) + child.expect('Traceback') + child.expect('>>> ') + child.sendline('__file__') + child.expect('Traceback') + child.expect('NameError') + + def test_ignore_python_startup(self): + old = os.environ.get('PYTHONSTARTUP', '') + try: + os.environ['PYTHONSTARTUP'] = crashing_demo_script + child = self.spawn(['-E']) + child.expect(re.escape(banner)) + index = child.expect(['Traceback', '>>> ']) + assert index == 1 # no traceback + finally: + os.environ['PYTHONSTARTUP'] = old + + def test_ignore_python_inspect(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + child = self.spawn(['-E', '-c', 'pass']) + from pexpect import EOF + index = child.expect(['>>> ', EOF]) + assert index == 1 # no prompt + finally: + del os.environ['PYTHONINSPECT_'] + + def test_python_path_keeps_duplicates(self): + old = os.environ.get('PYTHONPATH', '') + try: + os.environ['PYTHONPATH'] = 'foobarbaz:foobarbaz' + child = self.spawn(['-c', 'import sys; print sys.path']) + child.expect(r"\['', 'foobarbaz', 'foobarbaz', ") + finally: + os.environ['PYTHONPATH'] = old + + def test_ignore_python_path(self): + old = os.environ.get('PYTHONPATH', '') + try: + os.environ['PYTHONPATH'] = 'foobarbaz' + child = self.spawn(['-E', '-c', 'import sys; print sys.path']) + from pexpect import EOF + index = child.expect(['foobarbaz', EOF]) + assert index == 1 # no foobarbaz + finally: + os.environ['PYTHONPATH'] = old + + def test_unbuffered(self): + line = 'import os,sys;sys.stdout.write(str(789));os.read(0,1)' + child = self.spawn(['-u', '-c', line]) + child.expect('789') # expect to see it before the timeout hits + child.sendline('X') + + def test_options_i_m(self, monkeypatch): + if sys.platform == "win32": + skip("close_fds is not supported on Windows platforms") + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') + p = os.path.abspath(p) + monkeypatch.chdir(os.path.dirname(app_main)) + child = self.spawn(['-i', + '-m', 'test.mymodule', + 'extra']) + child.expect('mymodule running') + child.expect('Name: __main__') + child.expect(re.escape('File: ' + p)) + child.expect(re.escape('Argv: ' + repr([p, 'extra']))) + child.expect('>>> ') + child.sendline('somevalue') + child.expect(re.escape(repr("foobar"))) + child.expect('>>> ') + child.sendline('import sys') + child.sendline('"test" in sys.modules') + child.expect('True') + child.sendline('"test.mymodule" in sys.modules') + child.expect('False') + child.sendline('sys.path[0]') + child.expect("''") + + def test_option_i_noexit(self): + child = self.spawn(['-i', '-c', 'import sys; sys.exit(1)']) + child.expect('Traceback') + child.expect('SystemExit: 1') + + def test_options_u_i(self): + if sys.platform == "win32": + skip("close_fds is not supported on Windows platforms") + import subprocess, select, os + python = sys.executable + pipe = subprocess.Popen([python, app_main, "-u", "-i"], + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0, close_fds=True) + iwtd, owtd, ewtd = select.select([pipe.stdout], [], [], 5) + assert iwtd # else we timed out + data = os.read(pipe.stdout.fileno(), 1024) + assert data.startswith('Python') + + def test_paste_several_lines_doesnt_mess_prompt(self): + py.test.skip("this can only work if readline is enabled") + child = self.spawn([]) + child.expect('>>> ') + child.sendline('if 1:\n print 42\n') + child.expect('... print 42') + child.expect('... ') + child.expect('42') + child.expect('>>> ') + + def test_pythoninspect(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + path = getscript(""" + print 6*7 + """) + child = self.spawn([path]) + child.expect('42') + child.expect('>>> ') + finally: + del os.environ['PYTHONINSPECT_'] + + def test_set_pythoninspect(self): + path = getscript(""" + import os + os.environ['PYTHONINSPECT'] = '1' + print 6*7 + """) + child = self.spawn([path]) + child.expect('42') + child.expect('>>> ') + + def test_clear_pythoninspect(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + path = getscript(""" + import os + del os.environ['PYTHONINSPECT'] + """) + child = self.spawn([path]) + child.expect('>>> ') + finally: + del os.environ['PYTHONINSPECT_'] + + def test_stdout_flushes_before_stdin_blocks(self): + # This doesn't really test app_main.py, but a behavior that + # can only be checked on top of py.py with pexpect. + path = getscript(""" + import sys + sys.stdout.write('Are you suggesting coconuts migrate? ') + line = sys.stdin.readline() + assert line.rstrip() == 'Not at all. They could be carried.' + print 'A five ounce bird could not carry a one pound coconut.' + """) + py_py = os.path.join(pypydir, 'bin', 'pyinteractive.py') + child = self._spawn(sys.executable, [py_py, '-S', path]) + child.expect('Are you suggesting coconuts migrate?', timeout=120) + child.sendline('Not at all. They could be carried.') + child.expect('A five ounce bird could not carry a one pound coconut.') + + def test_no_space_before_argument(self, monkeypatch): + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + child = self.spawn(['-cprint "hel" + "lo"']) + child.expect('hello') + + monkeypatch.chdir(os.path.dirname(app_main)) + child = self.spawn(['-mtest.mymodule']) + child.expect('mymodule running') + + def test_ps1_only_if_interactive(self): + argv = ['-c', 'import sys; print hasattr(sys, "ps1")'] + child = self.spawn(argv) + child.expect('False') + + +class TestNonInteractive: + def run_with_status_code(self, cmdline, senddata='', expect_prompt=False, + expect_banner=False, python_flags='', env=None): + cmdline = '%s %s "%s" %s' % (sys.executable, python_flags, + app_main, cmdline) + print 'POPEN:', cmdline + process = subprocess.Popen( + cmdline, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + shell=True, env=env, + universal_newlines=True + ) + child_in, child_out_err = process.stdin, process.stdout + child_in.write(senddata) + child_in.close() + data = child_out_err.read() + child_out_err.close() + process.wait() + assert (banner in data) == expect_banner # no banner unless expected + assert ('>>> ' in data) == expect_prompt # no prompt unless expected + return data, process.returncode + + def run(self, *args, **kwargs): + data, status = self.run_with_status_code(*args, **kwargs) + return data + + def test_script_on_stdin(self): + for extraargs, expected_argv in [ + ('', ['']), + ('-', ['-']), + ('- hello world', ['-', 'hello', 'world']), + ]: + data = self.run('%s < "%s"' % (extraargs, demo_script)) + assert "hello" in data + assert "Name: __main__" in data + assert "File: " in data + assert ("Exec: " + app_main) in data + assert ("Argv: " + repr(expected_argv)) in data + assert "goodbye" in data + + def test_run_crashing_script(self): + data = self.run('"%s"' % (crashing_demo_script,)) + assert 'Hello2' in data + assert 'NameError' in data + assert 'Goodbye2' not in data + + def test_crashing_script_on_stdin(self): + data = self.run(' < "%s"' % (crashing_demo_script,)) + assert 'Hello2' in data + assert 'NameError' in data + assert 'Goodbye2' not in data + + def test_option_W(self): + data = self.run('-W d -c "print 42"') + assert '42' in data + data = self.run('-Wd -c "print 42"') + assert '42' in data + + def test_option_W_crashing(self): + data = self.run('-W') + assert "Argument expected for the '-W' option" in data + + def test_option_W_arg_ignored(self): + data = self.run('-Wc') + assert "Invalid -W option ignored: invalid action: 'c'" in data + + def test_option_W_arg_ignored2(self): + data = self.run('-W-W') + assert "Invalid -W option ignored: invalid action:" in data + + def test_option_c(self): + data = self.run('-c "print 6**5"') + assert '7776' in data + + def test_no_pythonstartup(self, monkeypatch): + monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) + data = self.run('"%s"' % (demo_script,)) + assert 'Hello2' not in data + data = self.run('-c pass') + assert 'Hello2' not in data + + def test_pythonwarnings(self, monkeypatch): + # PYTHONWARNINGS_ is special cased by app_main: we cannot directly set + # PYTHONWARNINGS because else the warnings raised from within pypy are + # turned in errors. + monkeypatch.setenv('PYTHONWARNINGS_', "once,error") + data = self.run('-W ignore -W default ' + '-c "import sys; print sys.warnoptions"') + assert "['ignore', 'default', 'once', 'error']" in data + + def test_option_m(self, monkeypatch): + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + p = os.path.join(os.path.realpath(os.path.dirname(__file__)), 'mymodule.py') + p = os.path.abspath(p) + monkeypatch.chdir(os.path.dirname(app_main)) + data = self.run('-m test.mymodule extra') + assert 'mymodule running' in data + assert 'Name: __main__' in data + # ignoring case for windows. abspath behaves different from autopath + # concerning drive letters right now. + assert ('File: ' + p) in data + assert ('Argv: ' + repr([p, 'extra'])) in data + + def test_pythoninspect_doesnt_override_isatty(self): + os.environ['PYTHONINSPECT_'] = '1' + try: + data = self.run('', senddata='6*7\nprint 2+3\n') + assert data == '5\n' + finally: + del os.environ['PYTHONINSPECT_'] + + def test_i_flag_overrides_isatty(self): + data = self.run('-i', senddata='6*7\nraise SystemExit\n', + expect_prompt=True, expect_banner=True) + assert '42\n' in data + # if a file name is passed, the banner is never printed but + # we get a prompt anyway + cmdline = '-i %s' % getscript(""" + print 'hello world' + """) + data = self.run(cmdline, senddata='6*7\nraise SystemExit\n', + expect_prompt=True, expect_banner=False) + assert 'hello world\n' in data + assert '42\n' in data + + def test_option_S_copyright(self): + data = self.run('-S -i', expect_prompt=True, expect_banner=True) + assert 'copyright' not in data + + def test_non_interactive_stdout_fully_buffered(self): + path = getscript(r""" + import sys, time + sys.stdout.write('\x00(STDOUT)\n\x00') # stays in buffers + time.sleep(1) + sys.stderr.write('\x00[STDERR]\n\x00') + time.sleep(1) + # stdout flushed automatically here + """) + cmdline = '%s -u "%s" %s' % (sys.executable, app_main, path) + print 'POPEN:', cmdline + child_in, child_out_err = os.popen4(cmdline) + data = child_out_err.read(11) + assert data == '\x00[STDERR]\n\x00' # from stderr + child_in.close() + data = child_out_err.read(11) + assert data == '\x00(STDOUT)\n\x00' # from stdout + child_out_err.close() + + def test_non_interactive_stdout_unbuffered(self, monkeypatch): + monkeypatch.setenv('PYTHONUNBUFFERED', '1') + path = getscript(r""" + import sys, time + sys.stdout.write('\x00(STDOUT)\n\x00') + time.sleep(1) + sys.stderr.write('\x00[STDERR]\n\x00') + time.sleep(1) + # stdout flushed automatically here + """) + cmdline = '%s -E "%s" %s' % (sys.executable, app_main, path) + print 'POPEN:', cmdline + child_in, child_out_err = os.popen4(cmdline) + data = child_out_err.read(11) + assert data == '\x00(STDOUT)\n\x00' # from stderr + data = child_out_err.read(11) + assert data == '\x00[STDERR]\n\x00' # from stdout + child_out_err.close() + child_in.close() + + def test_proper_sys_path(self, tmpdir): + data = self.run('-c "import _ctypes"', python_flags='-S') + if data.startswith('Traceback'): + py.test.skip("'python -S' cannot import extension modules: " + "see probably http://bugs.python.org/issue586680") + + @contextmanager + def chdir_and_unset_pythonpath(new_cwd): + old_cwd = new_cwd.chdir() + old_pythonpath = os.getenv('PYTHONPATH') + os.unsetenv('PYTHONPATH') + try: + yield + finally: + old_cwd.chdir() + # Can't call putenv with a None argument. + if old_pythonpath is not None: + os.putenv('PYTHONPATH', old_pythonpath) + + tmpdir.join('site.py').write('print "SHOULD NOT RUN"') + runme_py = tmpdir.join('runme.py') + runme_py.write('print "some text"') + + cmdline = str(runme_py) + + with chdir_and_unset_pythonpath(tmpdir): + data = self.run(cmdline, python_flags='-S') + + assert data == "some text\n" + + runme2_py = tmpdir.mkdir('otherpath').join('runme2.py') + runme2_py.write('print "some new text"\n' + 'import sys\n' + 'print sys.path\n') + + cmdline2 = str(runme2_py) + + with chdir_and_unset_pythonpath(tmpdir): + data = self.run(cmdline2, python_flags='-S') + assert data.startswith("some new text\n") + assert repr(str(tmpdir.join('otherpath'))) in data + assert "''" not in data + + data = self.run('-c "import sys; print sys.path"') + assert data.startswith("[''") + + def test_pyc_commandline_argument(self): + p = getscript_pyc(self.space, "print 6*7\n") + assert os.path.isfile(p) and p.endswith('.pyc') + data = self.run(p) + assert data == 'in _run_compiled_module\n' + + def test_main_in_dir_commandline_argument(self): + if not hasattr(runpy, '_run_module_as_main'): + skip("requires CPython >= 2.6") + p = getscript_in_dir('import sys; print sys.argv[0]\n') + data = self.run(p) + assert data == p + '\n' + data = self.run(p + os.sep) + assert data == p + os.sep + '\n' + + def test_getfilesystemencoding(self): + py.test.skip("encoding is only set if stdout.isatty(), test is flawed") + if sys.version_info < (2, 7): + skip("test requires Python >= 2.7") + p = getscript_in_dir(""" + import sys + sys.stdout.write(u'15\u20ac') + sys.stdout.flush() + """) + env = os.environ.copy() + env["LC_CTYPE"] = 'en_US.UTF-8' + data = self.run(p, env=env) + assert data == '15\xe2\x82\xac' + + def test_pythonioencoding(self): + if sys.version_info < (2, 7): + skip("test requires Python >= 2.7") + for encoding, expected in [ + ("iso-8859-15", "15\xa4"), + ("utf-8", '15\xe2\x82\xac'), + ("utf-16-le", '1\x005\x00\xac\x20'), + ("iso-8859-1:ignore", "15"), + ("iso-8859-1:replace", "15?"), + ("iso-8859-1:backslashreplace", "15\\u20ac"), + ]: + p = getscript_in_dir(""" + import sys + sys.stdout.write(u'15\u20ac') + sys.stdout.flush() + """) + env = os.environ.copy() + env["PYTHONIOENCODING"] = encoding + data = self.run(p, env=env) + assert data == expected + + def test_sys_exit_pythonioencoding(self): + if sys.version_info < (2, 7): + skip("test required Python >= 2.7") + p = getscript_in_dir(""" + import sys + sys.exit(u'15\u20ac') + """) + env = os.environ.copy() + env["PYTHONIOENCODING"] = "utf-8" + data, status = self.run_with_status_code(p, env=env) + assert status == 1 + assert data.startswith("15\xe2\x82\xac") + + +class TestAppMain: + def test_print_info(self): + from pypy.interpreter import app_main + import sys, cStringIO + prev_so = sys.stdout + prev_ti = getattr(sys, 'pypy_translation_info', 'missing') + sys.pypy_translation_info = { + 'translation.foo': True, + 'translation.bar': 42, + 'translation.egg.something': None, + 'objspace.x': 'hello', + } + try: + sys.stdout = f = cStringIO.StringIO() + py.test.raises(SystemExit, app_main.print_info) + finally: + sys.stdout = prev_so + if prev_ti == 'missing': + del sys.pypy_translation_info + else: + sys.pypy_translation_info = prev_ti + assert f.getvalue() == ("[objspace]\n" + " x = 'hello'\n" + "[translation]\n" + " bar = 42\n" + " [egg]\n" + " something = None\n" + " foo = True\n") + + +class AppTestAppMain: + def setup_class(self): + # ---------------------------------------- + # setup code for test_setup_bootstrap_path + # ---------------------------------------- + from pypy.module.sys.version import CPYTHON_VERSION, PYPY_VERSION + cpy_ver = '%d.%d' % CPYTHON_VERSION[:2] + + goal_dir = os.path.dirname(app_main) + # build a directory hierarchy like which contains both bin/pypy-c and + # lib/pypy1.2/* + prefix = udir.join('pathtest').ensure(dir=1) + fake_exe = 'bin/pypy-c' + if sys.platform == 'win32': + fake_exe += '.exe' + fake_exe = prefix.join(fake_exe).ensure(file=1) + expected_path = [str(prefix.join(subdir).ensure(dir=1)) + for subdir in ('lib_pypy', + 'lib-python/%s' % cpy_ver)] + + self.w_goal_dir = self.space.wrap(goal_dir) + self.w_fake_exe = self.space.wrap(str(fake_exe)) + self.w_expected_path = self.space.wrap(expected_path) + self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir)) + + foo_py = prefix.join('foo.py').write("pass") + self.w_foo_py = self.space.wrap(str(foo_py)) + + def test_setup_bootstrap_path(self): + import sys + old_sys_path = sys.path[:] + sys.path.append(self.goal_dir) + try: + import app_main + app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found + assert sys.executable == '' + assert sys.path == old_sys_path + [self.goal_dir] + + app_main.setup_bootstrap_path(self.fake_exe) + assert sys.executable == self.fake_exe + assert self.goal_dir not in sys.path + + newpath = sys.path[:] + 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 + finally: + sys.path[:] = old_sys_path + + def test_trunk_can_be_prefix(self): + import sys + import os + old_sys_path = sys.path[:] + sys.path.append(self.goal_dir) + try: + import app_main + pypy_c = os.path.join(self.trunkdir, 'pypy', 'goal', 'pypy-c') + app_main.setup_bootstrap_path(pypy_c) + newpath = sys.path[:] + # we get at least lib_pypy + # lib-python/X.Y.Z, and maybe more (e.g. plat-linux2) + assert len(newpath) >= 2 + for p in newpath: + assert p.startswith(self.trunkdir) + finally: + sys.path[:] = old_sys_path + + def test_entry_point(self): + import sys + import os + old_sys_path = sys.path[:] + sys.path.append(self.goal_dir) + try: + import app_main + pypy_c = os.path.join(self.trunkdir, 'pypy', 'goal', 'pypy-c') + app_main.entry_point(pypy_c, [self.foo_py]) + # assert it did not crash + finally: + sys.path[:] = old_sys_path diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -135,18 +135,39 @@ def test_interpindirect2app(self): space = self.space + class BaseA(W_Root): def method(self, space, x): + "This is a method" + pass + + def method_with_default(self, space, x=5): + pass + + @gateway.unwrap_spec(x=int) + def method_with_unwrap_spec(self, space, x): pass class A(BaseA): def method(self, space, x): return space.wrap(x + 2) + def method_with_default(self, space, x): + return space.wrap(x + 2) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 2) + class B(BaseA): def method(self, space, x): return space.wrap(x + 1) + def method_with_default(self, space, x): + return space.wrap(x + 1) + + def method_with_unwrap_spec(self, space, x): + return space.wrap(x + 1) + class FakeTypeDef(object): rawdict = {} bases = {} @@ -163,6 +184,23 @@ assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2 assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1 + doc = space.str_w(space.getattr(w_c, space.wrap('__doc__'))) + assert doc == "This is a method" + + meth_with_default = gateway.interpindirect2app( + BaseA.method_with_default, {'x': int}) + w_d = space.wrap(meth_with_default) + + assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2 + assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1 + assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2 + assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1 + + meth_with_unwrap_spec = gateway.interpindirect2app( + BaseA.method_with_unwrap_spec) + w_e = space.wrap(meth_with_unwrap_spec) + assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2 + def test_interp2app_unwrap_spec(self): space = self.space w = space.wrap diff --git a/pypy/interpreter/test/test_targetpypy.py b/pypy/interpreter/test/test_targetpypy.py new file mode 100644 --- /dev/null +++ b/pypy/interpreter/test/test_targetpypy.py @@ -0,0 +1,28 @@ +from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point +from pypy.config.pypyoption import get_pypy_config +from rpython.rtyper.lltypesystem import rffi, lltype + +class TestTargetPyPy(object): + def test_run(self): + config = get_pypy_config(translating=False) + entry_point = get_entry_point(config)[0] + entry_point(['pypy-c' , '-S', '-c', 'print 3']) + +def test_exeucte_source(space): + _, d = create_entry_point(space, None) + execute_source = d['pypy_execute_source'] + lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3") + execute_source(lls) + lltype.free(lls, flavor='raw') + x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'], + space.wrap('modules')), + space.wrap('xyz'))) + assert x == 3 + lls = rffi.str2charp("sys") + execute_source(lls) + lltype.free(lls, flavor='raw') + # did not crash - the same globals + pypy_setup_home = d['pypy_setup_home'] + lls = rffi.str2charp(__file__) + pypy_setup_home(lls, 1) + lltype.free(lls, flavor='raw') diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py --- a/pypy/interpreter/test/test_zzpickle_and_slow.py +++ b/pypy/interpreter/test/test_zzpickle_and_slow.py @@ -485,3 +485,68 @@ pckl = pickle.dumps(pack.mod) result = pickle.loads(pckl) assert pack.mod is result + + +class AppTestGeneratorCloning: + + def setup_class(cls): + try: + cls.space.appexec([], """(): + def f(): yield 42 + f().__reduce__() + """) + except TypeError, e: + if 'pickle generator' not in str(e): + raise + py.test.skip("Frames can't be __reduce__()-ed") + + def test_deepcopy_generator(self): + import copy + + def f(n): + for i in range(n): + yield 42 + i + g = f(4) + g2 = copy.deepcopy(g) + res = g.next() + assert res == 42 + res = g2.next() + assert res == 42 + g3 = copy.deepcopy(g) + res = g.next() + assert res == 43 + res = g2.next() + assert res == 43 + res = g3.next() + assert res == 43 + + def test_shallowcopy_generator(self): + """Note: shallow copies of generators are often confusing. + To start with, 'for' loops have an iterator that will not + be copied, and so create tons of confusion. + """ + import copy + + def f(n): + while n > 0: + yield 42 + n + n -= 1 + g = f(2) + g2 = copy.copy(g) + res = g.next() + assert res == 44 + res = g2.next() + assert res == 44 + g3 = copy.copy(g) + res = g.next() + assert res == 43 + res = g2.next() + assert res == 43 + res = g3.next() + assert res == 43 + g4 = copy.copy(g2) + for i in range(2): + raises(StopIteration, g.next) + raises(StopIteration, g2.next) + raises(StopIteration, g3.next) + raises(StopIteration, g4.next) diff --git a/pypy/interpreter/test2/__init__.py b/pypy/interpreter/test2/__init__.py deleted file mode 100644 --- a/pypy/interpreter/test2/__init__.py +++ /dev/null @@ -1,1 +0,0 @@ -#empty diff --git a/pypy/interpreter/test2/test_app_main.py b/pypy/interpreter/test2/test_app_main.py deleted file mode 100644 --- a/pypy/interpreter/test2/test_app_main.py +++ /dev/null @@ -1,966 +0,0 @@ -""" -Tests for the entry point of pypy-c, app_main.py. -""" -from __future__ import with_statement -import py -import sys, os, re, runpy, subprocess -from rpython.tool.udir import udir -from contextlib import contextmanager -from pypy.conftest import pypydir - -banner = sys.version.splitlines()[0] - -app_main = os.path.join(os.path.realpath(os.path.dirname(__file__)), os.pardir, 'app_main.py') -app_main = os.path.abspath(app_main) - -_counter = 0 -def _get_next_path(ext='.py'): - global _counter - p = udir.join('demo_test_app_main_%d%s' % (_counter, ext)) - _counter += 1 - return p - -def getscript(source): - p = _get_next_path() - p.write(str(py.code.Source(source))) - return str(p) - -def getscript_pyc(space, source): - p = _get_next_path() - p.write(str(py.code.Source(source))) - w_dir = space.wrap(str(p.dirpath())) - w_modname = space.wrap(p.purebasename) - space.appexec([w_dir, w_modname], """(dir, modname): - import sys - d = sys.modules.copy() - sys.path.insert(0, dir) - __import__(modname) - sys.path.pop(0) - for key in sys.modules.keys(): - if key not in d: - del sys.modules[key] - """) - p = str(p) + 'c' - assert os.path.isfile(p) # the .pyc file should have been created above - return p - -def getscript_in_dir(source): - pdir = _get_next_path(ext='') - p = pdir.ensure(dir=1).join('__main__.py') - p.write(str(py.code.Source(source))) - # return relative path for testing purposes - return py.path.local().bestrelpath(pdir) - -demo_script = getscript(""" - print 'hello' - print 'Name:', __name__ - print 'File:', __file__ - import sys - print 'Exec:', sys.executable - print 'Argv:', sys.argv - print 'goodbye' - myvalue = 6*7 - """) - -crashing_demo_script = getscript(""" - print 'Hello2' - myvalue2 = 11 - ooups - myvalue2 = 22 - print 'Goodbye2' # should not be reached - """) - - -class TestParseCommandLine: - def check_options(self, options, sys_argv, **expected): - assert sys.argv == sys_argv - for key, value in expected.items(): - assert options[key] == value - for key, value in options.items(): - if key not in expected: - assert not value, ( - "option %r has unexpectedly the value %r" % (key, value)) - - def check(self, argv, env, **expected): - import StringIO - from pypy.interpreter import app_main - saved_env = os.environ.copy() - saved_sys_argv = sys.argv[:] - saved_sys_stdout = sys.stdout - saved_sys_stderr = sys.stdout - app_main.os = os - try: - os.environ.update(env) - sys.stdout = sys.stderr = StringIO.StringIO() - try: - options = app_main.parse_command_line(argv) - except SystemExit: - output = expected['output_contains'] - assert output in sys.stdout.getvalue() - else: - self.check_options(options, **expected) - finally: - os.environ.clear() - os.environ.update(saved_env) - sys.argv[:] = saved_sys_argv - sys.stdout = saved_sys_stdout - sys.stderr = saved_sys_stderr - - def test_all_combinations_I_can_think_of(self): - self.check([], {}, sys_argv=[''], run_stdin=True) - self.check(['-'], {}, sys_argv=['-'], run_stdin=True) - self.check(['-S'], {}, sys_argv=[''], run_stdin=True, no_site=1) - self.check(['-OO'], {}, sys_argv=[''], run_stdin=True, optimize=2) - self.check(['-O', '-O'], {}, sys_argv=[''], run_stdin=True, optimize=2) - self.check(['-Qnew'], {}, sys_argv=[''], run_stdin=True, division_new=1) - self.check(['-Qold'], {}, sys_argv=[''], run_stdin=True, division_new=0) - self.check(['-Qwarn'], {}, sys_argv=[''], run_stdin=True, division_warning=1) - self.check(['-Qwarnall'], {}, sys_argv=[''], run_stdin=True, - division_warning=2) - self.check(['-Q', 'new'], {}, sys_argv=[''], run_stdin=True, division_new=1) - self.check(['-SOQnew'], {}, sys_argv=[''], run_stdin=True, - no_site=1, optimize=1, division_new=1) - self.check(['-SOQ', 'new'], {}, sys_argv=[''], run_stdin=True, - no_site=1, optimize=1, division_new=1) - self.check(['-i'], {}, sys_argv=[''], run_stdin=True, - interactive=1, inspect=1) - self.check(['-?'], {}, output_contains='usage:') - self.check(['-h'], {}, output_contains='usage:') - self.check(['-S', '-tO', '-h'], {}, output_contains='usage:') - self.check(['-S', '-thO'], {}, output_contains='usage:') - self.check(['-S', '-tO', '--help'], {}, output_contains='usage:') - self.check(['-S', '-tO', '--info'], {}, output_contains='translation') - self.check(['-S', '-tO', '--version'], {}, output_contains='Python') - self.check(['-S', '-tOV'], {}, output_contains='Python') - self.check(['--jit', 'foobar', '-S'], {}, sys_argv=[''], - run_stdin=True, no_site=1) - self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass') - self.check(['-cpass'], {}, sys_argv=['-c'], run_command='pass') - self.check(['-cpass','x'], {}, sys_argv=['-c','x'], run_command='pass') - self.check(['-Sc', 'pass'], {}, sys_argv=['-c'], run_command='pass', - no_site=1) - self.check(['-Scpass'], {}, sys_argv=['-c'], run_command='pass', no_site=1) - self.check(['-c', '', ''], {}, sys_argv=['-c', ''], run_command='') - self.check(['-mfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True) - self.check(['-m', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True) - self.check(['-Smfoo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True, no_site=1) - self.check(['-Sm', 'foo', 'bar', 'baz'], {}, sys_argv=['foo', 'bar', 'baz'], - run_module=True, no_site=1) - self.check(['-', 'foo', 'bar'], {}, sys_argv=['-', 'foo', 'bar'], - run_stdin=True) - self.check(['foo', 'bar'], {}, sys_argv=['foo', 'bar']) - self.check(['foo', '-i'], {}, sys_argv=['foo', '-i']) - self.check(['-i', 'foo'], {}, sys_argv=['foo'], interactive=1, inspect=1) - self.check(['--', 'foo'], {}, sys_argv=['foo']) - self.check(['--', '-i', 'foo'], {}, sys_argv=['-i', 'foo']) - self.check(['--', '-', 'foo'], {}, sys_argv=['-', 'foo'], run_stdin=True) - self.check(['-Wbog'], {}, sys_argv=[''], warnoptions=['bog'], run_stdin=True) - self.check(['-W', 'ab', '-SWc'], {}, sys_argv=[''], warnoptions=['ab', 'c'], - run_stdin=True, no_site=1) - - self.check([], {'PYTHONDEBUG': '1'}, sys_argv=[''], run_stdin=True, debug=1) - self.check([], {'PYTHONDONTWRITEBYTECODE': '1'}, sys_argv=[''], run_stdin=True, dont_write_bytecode=1) - self.check([], {'PYTHONNOUSERSITE': '1'}, sys_argv=[''], run_stdin=True, no_user_site=1) - self.check([], {'PYTHONUNBUFFERED': '1'}, sys_argv=[''], run_stdin=True, unbuffered=1) - self.check([], {'PYTHONVERBOSE': '1'}, sys_argv=[''], run_stdin=True, verbose=1) - - def test_sysflags(self): - flags = ( - ("debug", "-d", "1"), - ("py3k_warning", "-3", "1"), - ("division_warning", "-Qwarn", "1"), - ("division_warning", "-Qwarnall", "2"), - ("division_new", "-Qnew", "1"), - (["inspect", "interactive"], "-i", "1"), - ("optimize", "-O", "1"), - ("optimize", "-OO", "2"), - ("dont_write_bytecode", "-B", "1"), - ("no_user_site", "-s", "1"), - ("no_site", "-S", "1"), - ("ignore_environment", "-E", "1"), - ("tabcheck", "-t", "1"), - ("tabcheck", "-tt", "2"), - ("verbose", "-v", "1"), - ("unicode", "-U", "1"), - ("bytes_warning", "-b", "1"), - ) - for flag, opt, value in flags: - if isinstance(flag, list): # this is for inspect&interactive - expected = {} - for flag1 in flag: - expected[flag1] = int(value) - else: - expected = {flag: int(value)} - self.check([opt, '-c', 'pass'], {}, sys_argv=['-c'], - run_command='pass', **expected) - - def test_sysflags_envvar(self, monkeypatch): - monkeypatch.setenv('PYTHONNOUSERSITE', '1') - expected = {"no_user_site": True} - self.check(['-c', 'pass'], {}, sys_argv=['-c'], run_command='pass', **expected) - - -class TestInteraction: - """ - These tests require pexpect (UNIX-only). - http://pexpect.sourceforge.net/ - """ - def _spawn(self, *args, **kwds): - try: - import pexpect - except ImportError, e: - py.test.skip(str(e)) - else: - # Version is of the style "0.999" or "2.1". Older versions of - # pexpect try to get the fileno of stdin, which generally won't - # work with py.test (due to sys.stdin being a DontReadFromInput - # instance). - version = map(int, pexpect.__version__.split('.')) - - # I only tested 0.999 and 2.1. The former does not work, the - # latter does. Feel free to refine this measurement. - # -exarkun, 17/12/2007 - if version < [2, 1]: - py.test.skip( - "pexpect version too old, requires 2.1 or newer: %r" % ( - pexpect.__version__,)) - - kwds.setdefault('timeout', 10) - print 'SPAWN:', ' '.join([args[0]] + args[1]), kwds - child = pexpect.spawn(*args, **kwds) - child.logfile = sys.stdout - return child - - def spawn(self, argv): - return self._spawn(sys.executable, [app_main] + argv) - - def test_interactive(self): - child = self.spawn([]) - child.expect('Python ') # banner - child.expect('>>> ') # prompt - child.sendline('[6*7]') - child.expect(re.escape('[42]')) - child.sendline('def f(x):') - child.expect(re.escape('... ')) - child.sendline(' return x + 100') - child.expect(re.escape('... ')) - child.sendline('') - child.expect('>>> ') - child.sendline('f(98)') - child.expect('198') - child.expect('>>> ') - child.sendline('__name__') - child.expect("'__main__'") - child.expect('>>> ') - child.sendline('import sys') - child.expect('>>> ') - child.sendline("'' in sys.path") - child.expect("True") - - def test_help(self): - # test that -h prints the usage, including the name of the executable - # which should be /full/path/to/app_main.py in this case - child = self.spawn(['-h']) - child.expect(r'usage: .*app_main.py \[option\]') - child.expect('PyPy options and arguments:') - - def test_run_script(self): - child = self.spawn([demo_script]) - idx = child.expect(['hello', 'Python ', '>>> ']) - assert idx == 0 # no banner or prompt - child.expect(re.escape("Name: __main__")) - child.expect(re.escape('File: ' + demo_script)) - child.expect(re.escape('Exec: ' + app_main)) - child.expect(re.escape('Argv: ' + repr([demo_script]))) - child.expect('goodbye') - - def test_run_script_with_args(self): - argv = [demo_script, 'hello', 'world'] - child = self.spawn(argv) - child.expect(re.escape('Argv: ' + repr(argv))) - child.expect('goodbye') - - def test_no_such_script(self): - import errno - msg = os.strerror(errno.ENOENT) # 'No such file or directory' - child = self.spawn(['xxx-no-such-file-xxx']) - child.expect(re.escape(msg)) - - def test_option_i(self): - argv = [demo_script, 'foo', 'bar'] - child = self.spawn(['-i'] + argv) - idx = child.expect(['hello', re.escape(banner)]) - assert idx == 0 # no banner - child.expect(re.escape('File: ' + demo_script)) - child.expect(re.escape('Argv: ' + repr(argv))) - child.expect('goodbye') - idx = child.expect(['>>> ', re.escape(banner)]) - assert idx == 0 # prompt, but still no banner - child.sendline('myvalue * 102') - child.expect('4284') - child.sendline('__name__') - child.expect('__main__') - - def test_option_i_crashing(self): - argv = [crashing_demo_script, 'foo', 'bar'] - child = self.spawn(['-i'] + argv) - idx = child.expect(['Hello2', re.escape(banner)]) - assert idx == 0 # no banner - child.expect('NameError') - child.sendline('myvalue2 * 1001') - child.expect('11011') - child.sendline('import sys; sys.argv') - child.expect(re.escape(repr(argv))) - child.sendline('sys.last_type.__name__') - child.expect(re.escape(repr('NameError'))) - - def test_options_i_c(self): - child = self.spawn(['-i', '-c', 'x=555']) - idx = child.expect(['>>> ', re.escape(banner)]) - assert idx == 0 # prompt, but no banner - child.sendline('x') - child.expect('555') - child.sendline('__name__') - child.expect('__main__') - child.sendline('import sys; sys.argv') - child.expect(re.escape("['-c']")) - - def test_options_i_c_crashing(self, monkeypatch): - monkeypatch.setenv('PYTHONPATH', None) - child = self.spawn(['-i', '-c', 'x=666;foobar']) - child.expect('NameError') - idx = child.expect(['>>> ', re.escape(banner)]) - assert idx == 0 # prompt, but no banner - child.sendline('x') - child.expect('666') - child.sendline('__name__') - child.expect('__main__') - child.sendline('import sys; sys.argv') - child.expect(re.escape("['-c']")) - child.sendline('sys.last_type.__name__') - child.expect(re.escape(repr('NameError'))) - - def test_atexit(self): - child = self.spawn([]) - child.expect('>>> ') - child.sendline('def f(): print "foobye"') - child.sendline('') - child.sendline('import atexit; atexit.register(f)') - child.sendline('6*7') - child.expect('42') - # pexpect's sendeof() is confused by py.test capturing, though - # I think that it is a bug of sendeof() - old = sys.stdin - try: - sys.stdin = child - child.sendeof() - finally: - sys.stdin = old - child.expect('foobye') - - def test_pythonstartup(self, monkeypatch): - monkeypatch.setenv('PYTHONPATH', None) - monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script) - child = self.spawn([]) - child.expect(re.escape(banner)) - child.expect('Traceback') - child.expect('NameError') - child.expect('>>> ') - child.sendline('[myvalue2]') - child.expect(re.escape('[11]')) - child.expect('>>> ') - - child = self.spawn(['-i', demo_script]) - for line in ['hello', 'goodbye', '>>> ']: - idx = child.expect([line, 'Hello2']) - assert idx == 0 # no PYTHONSTARTUP run here - child.sendline('myvalue2') - child.expect('Traceback') - child.expect('NameError') - - def test_pythonstartup_file1(self, monkeypatch): - monkeypatch.setenv('PYTHONPATH', None) - monkeypatch.setenv('PYTHONSTARTUP', demo_script) From noreply at buildbot.pypy.org Wed May 15 17:08:35 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 17:08:35 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Add some tests for subarrays, fix itemsize Message-ID: <20130515150835.EED851C3000@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64171:8b807472067a Date: 2013-05-15 16:56 +0200 http://bitbucket.org/pypy/pypy/changeset/8b807472067a/ Log: Add some tests for subarrays, fix itemsize diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -143,6 +143,7 @@ if w_fields == space.w_None: self.fields = None else: + self.fields = {} ofs_and_items = [] size = 0 for key in space.listview(w_fields): @@ -330,8 +331,9 @@ elif char == 'V': num = 20 basename = 'void' - w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - return dtype_from_list(space, space.newlist([])) + itemtype = types.VoidType(size) + return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(size), + "V", space.gettypefor(interp_boxes.W_VoidBox)) else: assert char == 'U' basename = 'unicode' diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -278,17 +278,6 @@ assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype - def test_pickle_record(self): - from numpypy import array, dtype - from cPickle import loads, dumps - - d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) - assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) - - new_d = loads(dumps(d)) - - assert new_d.__reduce__() == d.__reduce__() - class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): import numpypy as numpy @@ -766,6 +755,7 @@ assert isinstance(unicode_(3), unicode) class AppTestRecordDtypes(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): from numpypy import dtype, void @@ -810,6 +800,30 @@ assert dt.fields == None assert dt.subdtype == (dtype("float64"), (10,)) + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() + + def test_pickle_record_subarrays(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32", (3,)), ("y", "int32", (2,)), ("z", "int32", (4,)), ("value", float, (5,))]) + new_d = loads(dumps(d)) + + keys = d.fields.keys() + keys.sort() + assert keys == ["value", "x", "y", "z"] + + assert new_d.itemsize == d.itemsize == 76 + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) From noreply at buildbot.pypy.org Wed May 15 17:11:10 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 17:11:10 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Skip a bunch of tests if _testcapi is not there Message-ID: <20130515151110.932D11C02E4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-set-smm Changeset: r64172:4e1b2e04aa82 Date: 2013-05-15 17:01 +0200 http://bitbucket.org/pypy/pypy/changeset/4e1b2e04aa82/ Log: Skip a bunch of tests if _testcapi is not there diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -1387,7 +1387,8 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if (encoding not in broken_incremental_coders and + hasattr(_testcapi, 'codec_incrementalencoder')): # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_descr.py b/lib-python/2.7/test/test_descr.py --- a/lib-python/2.7/test/test_descr.py +++ b/lib-python/2.7/test/test_descr.py @@ -2080,8 +2080,9 @@ except ImportError: pass else: - class X(object): - p = property(_testcapi.test_with_docstring) + if hasattr(_testcapi, 'test_with_docstring'): + class X(object): + p = property(_testcapi.test_with_docstring) def test_properties_plus(self): class C(object): diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print +try: + from _testcapi import traceback_print +except ImportError: + traceback_print = None from StringIO import StringIO import sys import unittest @@ -176,6 +179,8 @@ class TracebackFormatTests(unittest.TestCase): def test_traceback_format(self): + if traceback_print is None: + return try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1609,7 +1609,10 @@ self.assertEqual("{}".format(u), '__unicode__ overridden') def test_encode_decimal(self): - from _testcapi import unicode_encodedecimal + try: + from _testcapi import unicode_encodedecimal + except ImportError: + return self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -54,4 +54,9 @@ fp, filename, description = imp.find_module('_testcapi', path=[output_dir]) imp.load_module('_testcapi', fp, filename, description) -compile_shared() +try: + import cpyext +except ImportError: + pass +else: + compile_shared() From noreply at buildbot.pypy.org Wed May 15 17:13:06 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 17:13:06 +0200 (CEST) Subject: [pypy-commit] pypy default: Skip a bunch of tests if _testcapi is not there Message-ID: <20130515151306.AA98B1C02E4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64173:ef7de7ebd5d7 Date: 2013-05-15 17:01 +0200 http://bitbucket.org/pypy/pypy/changeset/ef7de7ebd5d7/ Log: Skip a bunch of tests if _testcapi is not there diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -1387,7 +1387,8 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if (encoding not in broken_incremental_coders and + hasattr(_testcapi, 'codec_incrementalencoder')): # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_descr.py b/lib-python/2.7/test/test_descr.py --- a/lib-python/2.7/test/test_descr.py +++ b/lib-python/2.7/test/test_descr.py @@ -2080,8 +2080,9 @@ except ImportError: pass else: - class X(object): - p = property(_testcapi.test_with_docstring) + if hasattr(_testcapi, 'test_with_docstring'): + class X(object): + p = property(_testcapi.test_with_docstring) def test_properties_plus(self): class C(object): diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print +try: + from _testcapi import traceback_print +except ImportError: + traceback_print = None from StringIO import StringIO import sys import unittest @@ -176,6 +179,8 @@ class TracebackFormatTests(unittest.TestCase): def test_traceback_format(self): + if traceback_print is None: + return try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1609,7 +1609,10 @@ self.assertEqual("{}".format(u), '__unicode__ overridden') def test_encode_decimal(self): - from _testcapi import unicode_encodedecimal + try: + from _testcapi import unicode_encodedecimal + except ImportError: + return self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -54,4 +54,9 @@ fp, filename, description = imp.find_module('_testcapi', path=[output_dir]) imp.load_module('_testcapi', fp, filename, description) -compile_shared() +try: + import cpyext +except ImportError: + pass +else: + compile_shared() From noreply at buildbot.pypy.org Wed May 15 17:17:05 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 17:17:05 +0200 (CEST) Subject: [pypy-commit] pypy default: fix whatsnew Message-ID: <20130515151705.A67BD1C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64174:4e5b27e8c621 Date: 2013-05-15 17:06 +0200 http://bitbucket.org/pypy/pypy/changeset/4e5b27e8c621/ Log: fix whatsnew 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 @@ -10,3 +10,9 @@ .. branch: numpy-subarrays It is now possible to create arrays and dtypes that use subarrays + +.. branch: remove-array-smm +Remove multimethods in the arraymodule + +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback From noreply at buildbot.pypy.org Wed May 15 17:24:07 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 17:24:07 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix this test and remove some unused imports Message-ID: <20130515152407.715451C02E4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64175:e191271d612c Date: 2013-05-15 17:11 +0200 http://bitbucket.org/pypy/pypy/changeset/e191271d612c/ Log: Fix this test and remove some unused imports diff --git a/rpython/jit/metainterp/test/test_compile.py b/rpython/jit/metainterp/test/test_compile.py --- a/rpython/jit/metainterp/test/test_compile.py +++ b/rpython/jit/metainterp/test/test_compile.py @@ -1,10 +1,10 @@ from rpython.config.translationoption import get_combined_translation_config -from rpython.jit.metainterp.history import TargetToken, ConstInt, History, Stats -from rpython.jit.metainterp.history import BoxInt, INT +from rpython.jit.metainterp.history import ConstInt, History, Stats +from rpython.jit.metainterp.history import INT from rpython.jit.metainterp.compile import compile_loop -from rpython.jit.metainterp.compile import ResumeGuardDescr from rpython.jit.metainterp.compile import ResumeGuardCountersInt from rpython.jit.metainterp.compile import compile_tmp_callback +from rpython.jit.metainterp import jitexc from rpython.jit.metainterp import jitprof, typesystem, compile from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.tool.oparser import parse @@ -13,7 +13,7 @@ class FakeCPU(object): class tracker: pass - + ts = typesystem.llhelper def __init__(self): self.seen = [] @@ -41,7 +41,7 @@ loopnumbering = 0 class FakeMetaInterpStaticData(object): - + logger_noopt = FakeLogger() logger_ops = FakeLogger() config = get_combined_translation_config(translating=True) @@ -192,14 +192,13 @@ assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), got) == llexc # class FakeMetaInterpSD: - class ExitFrameWithExceptionRef(Exception): - pass + pass FakeMetaInterpSD.cpu = cpu deadframe = cpu.execute_token(loop_token, -156, -178) fail_descr = cpu.get_latest_descr(deadframe) try: fail_descr.handle_fail(deadframe, FakeMetaInterpSD(), None) - except FakeMetaInterpSD.ExitFrameWithExceptionRef, e: - assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.args[1]) == llexc + except jitexc.ExitFrameWithExceptionRef, e: + assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.value) == llexc else: assert 0, "should have raised" From noreply at buildbot.pypy.org Wed May 15 17:38:12 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 17:38:12 +0200 (CEST) Subject: [pypy-commit] pypy default: fix one problem with test_ztranslation Message-ID: <20130515153812.A38E71C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64176:c562ea31ca4b Date: 2013-05-15 17:19 +0200 http://bitbucket.org/pypy/pypy/changeset/c562ea31ca4b/ Log: fix one problem with test_ztranslation diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -55,6 +55,10 @@ from rpython.rlib.rbigint import rbigint return rbigint.fromint(NonConstant(42)) +class W_MyListObj(W_MyObject): + def append(self, w_other): + pass + class W_MyType(W_MyObject): def __init__(self): self.mro_w = [w_some_obj(), w_some_obj()] @@ -107,6 +111,9 @@ self._seen_extras = [] ObjSpace.__init__(self, config=config) + def _freeze_(self): + return True + def float_w(self, w_obj): is_root(w_obj) return NonConstant(42.5) @@ -131,7 +138,7 @@ def newlist(self, list_w): for w_x in list_w: is_root(w_x) - return w_some_obj() + return W_MyListObj() def newslice(self, w_start, w_end, w_step): is_root(w_start) From noreply at buildbot.pypy.org Wed May 15 17:49:05 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 15 May 2013 17:49:05 +0200 (CEST) Subject: [pypy-commit] pypy default: backout the merge of the numpy-subarrays branch Message-ID: <20130515154905.E60E61C009D@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: Changeset: r64177:af55d16f641d Date: 2013-05-15 17:24 +0200 http://bitbucket.org/pypy/pypy/changeset/af55d16f641d/ Log: backout the merge of the numpy-subarrays branch 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 @@ -8,9 +8,6 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) -.. branch: numpy-subarrays -It is now possible to create arrays and dtypes that use subarrays - .. branch: remove-array-smm Remove multimethods in the arraymodule diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,6 +11,7 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE +from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -323,7 +324,6 @@ orig_array) def argsort(self, space, w_axis): - from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py --- a/pypy/module/micronumpy/arrayimpl/sort.py +++ b/pypy/module/micronumpy/arrayimpl/sort.py @@ -12,7 +12,7 @@ from rpython.rlib.objectmodel import specialize from pypy.interpreter.error import OperationError from pypy.module.micronumpy.base import W_NDimArray -from pypy.module.micronumpy import types +from pypy.module.micronumpy import interp_dtype, types from pypy.module.micronumpy.iter import AxisIterator INT_SIZE = rffi.sizeof(lltype.Signed) @@ -20,7 +20,7 @@ def make_sort_function(space, itemtype, comp_type, count=1): TP = itemtype.T step = rffi.sizeof(TP) - + class Repr(object): def __init__(self, index_stride_size, stride_size, size, values, indexes, index_start, start): @@ -69,13 +69,12 @@ class ArgArrayRepWithStorage(Repr): def __init__(self, index_stride_size, stride_size, size): - from pypy.module.micronumpy import interp_dtype start = 0 dtype = interp_dtype.get_dtype_cache(space).w_longdtype self.indexes = dtype.itemtype.malloc(size*dtype.get_size()) - self.values = alloc_raw_storage(size * stride_size, + self.values = alloc_raw_storage(size * stride_size, track_allocation=False) - Repr.__init__(self, index_stride_size, stride_size, + Repr.__init__(self, index_stride_size, stride_size, size, self.values, self.indexes, start, start) def __del__(self): @@ -97,7 +96,7 @@ for i in range(stop-start): retval.setitem(i, lst.getitem(i+start)) return retval - + if count < 2: def arg_lt(a, b): # Does numpy do <= ? @@ -109,14 +108,13 @@ return True elif a[0][i] > b[0][i]: return False - # Does numpy do True? + # Does numpy do True? return False ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length, arg_getitem_slice, arg_lt) def argsort(arr, space, w_axis, itemsize): - from pypy.module.micronumpy import interp_dtype if w_axis is space.w_None: # note that it's fine ot pass None here as we're not going # to pass the result around (None is the link to base in slices) @@ -182,7 +180,7 @@ class SortCache(object): built = False - + def __init__(self, space): if self.built: return diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind", "shape"] + _immutable_fields_ = ["itemtype", "num", "kind"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True, shape=[], subdtype=None): + fields=None, fieldnames=None, native=True): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,8 +63,6 @@ self.fieldnames = fieldnames self.native = native self.float_type = None - self.shape = list(shape) - self.subdtype = subdtype @specialize.argtype(1) def box(self, value): @@ -113,12 +111,8 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) - def descr_get_subdtype(self, space): - return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) - def descr_get_shape(self, space): - w_shape = [space.wrap(dim) for dim in self.shape] - return space.newtuple(w_shape) + return space.newtuple([]) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -285,22 +279,15 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - size = 1 - w_shape = space.newtuple([]) - if space.len_w(w_elem) == 3: - w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) - if not base.issequence_w(space, w_shape): - w_shape = space.newtuple([w_shape,]) - else: - w_fldname, w_flddesc = space.fixedview(w_elem) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) + w_fldname, w_flddesc = space.fixedview(w_elem, 2) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() * size + offset += subdtype.itemtype.get_element_size() fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -346,24 +333,10 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) - if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): - subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) - assert isinstance(subdtype, W_Dtype) - size = 1 - if space.isinstance_w(w_shape, space.w_int): - w_shape = space.newtuple([w_shape]) - shape = [] - for w_dim in space.fixedview(w_shape): - dim = space.int_w(w_dim) - shape.append(dim) - size *= dim - return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), - "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) - if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -382,8 +355,6 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) - elif space.isinstance_w(w_dtype, space.w_tuple): - return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -420,7 +391,6 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), - subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -723,7 +723,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -790,26 +790,6 @@ d = dtype({'names': ['a', 'b', 'c'], }) - def test_create_subarrays(self): - from numpypy import dtype - d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) - assert d.itemsize == 32 - assert d.name == "void256" - keys = d.fields.keys() - assert "x" in keys - assert "y" in keys - assert d["x"].shape == (2,) - assert d["x"].itemsize == 16 - e = dtype([("x", "float", 2), ("y", "int", 2)]) - assert e.fields.keys() == keys - assert e['x'].shape == (2,) - - dt = dtype((float, 10)) - assert dt.shape == (10,) - assert dt.kind == 'V' - assert dt.fields == None - assert dt.subdtype == (dtype("float64"), (10,)) - class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2699,20 +2699,6 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 - def test_subarrays(self): - from numpypy import dtype, array - - d = dtype([("x", "int", 3), ("y", "float", 5)]) - a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) - - assert (a[0]["x"] == [1, 2, 3]).all() - assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() - assert (a[1]["x"] == [4, 5, 6]).all() - assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() - - a[0]["x"][0] = 200 - assert a[0]["x"][0] == 200 - class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,9 +3,7 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes -from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage -from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1078,7 +1076,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1219,7 +1217,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1227,7 +1225,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1343,7 +1341,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1698,36 +1696,10 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char - def coerce(self, space, dtype, w_items): - items_w = space.fixedview(w_items) - arr = VoidBoxStorage(self.size, dtype) - ofs = 0 - for i in range(len(items_w)): - subdtype = dtype.subdtype - itemtype = subdtype.itemtype - w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) - itemtype.store(arr, 0, ofs, w_box) - ofs += itemtype.get_element_size() - return interp_boxes.W_VoidBox(arr, 0, dtype) - - @jit.unroll_safe - def store(self, arr, i, ofs, box): - assert isinstance(box, interp_boxes.W_VoidBox) - for k in range(self.get_element_size()): - arr.storage[k + ofs] = box.arr.storage[k + box.ofs] - - def read(self, arr, i, offset, dtype=None): - from pypy.module.micronumpy.base import W_NDimArray - if dtype is None: - dtype = arr.dtype - strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) - implementation = SliceArray(i + offset, strides, backstrides, dtype.shape, arr, arr, dtype.subdtype) - return W_NDimArray(implementation) - NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1761,7 +1733,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.len_w(w_item): + if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) From noreply at buildbot.pypy.org Wed May 15 19:12:36 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 19:12:36 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: fix tests Message-ID: <20130515171236.56A911C02E4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-set-smm Changeset: r64178:afc67eb165b6 Date: 2013-05-15 18:48 +0200 http://bitbucket.org/pypy/pypy/changeset/afc67eb165b6/ Log: fix tests diff --git a/pypy/objspace/std/test/test_setstrategies.py b/pypy/objspace/std/test/test_setstrategies.py --- a/pypy/objspace/std/test/test_setstrategies.py +++ b/pypy/objspace/std/test/test_setstrategies.py @@ -65,18 +65,16 @@ assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_remove(self): - from pypy.objspace.std.setobject import set_remove__Set_ANY s1 = W_SetObject(self.space, self.wrapped([1])) - set_remove__Set_ANY(self.space, s1, self.space.wrap(1)) + self.space.call_method(s1, 'remove', self.space.wrap(1)) assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_union(self): - from pypy.objspace.std.setobject import set_union__Set s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) s2 = W_SetObject(self.space, self.wrapped([4,5,6,7])) s3 = W_SetObject(self.space, self.wrapped([4,'5','6',7])) - s4 = set_union__Set(self.space, s1, [s2]) - s5 = set_union__Set(self.space, s1, [s3]) + s4 = s1.descr_union(self.space, [s2]) + s5 = s1.descr_union(self.space, [s3]) assert s4.strategy is self.space.fromcache(IntegerSetStrategy) assert s5.strategy is self.space.fromcache(ObjectSetStrategy) @@ -91,10 +89,8 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) - set_discard__Set_ANY(self.space, s1, self.space.wrap("five")) + s1.descr_discard(self.space, self.space.wrap("five")) skip("currently not supported") assert s1.strategy is self.space.fromcache(IntegerSetStrategy) @@ -112,8 +108,6 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) assert not s1.has_key(self.space.wrap("five")) skip("currently not supported") From noreply at buildbot.pypy.org Wed May 15 19:16:20 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 19:16:20 +0200 (CEST) Subject: [pypy-commit] pypy default: An attempt to fix test_zjit Message-ID: <20130515171620.DB59B1C009D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64179:ee0e0b487513 Date: 2013-05-15 18:55 +0200 http://bitbucket.org/pypy/pypy/changeset/ee0e0b487513/ Log: An attempt to fix test_zjit diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -14,6 +14,7 @@ from pypy.module.micronumpy.interp_arrayops import where from pypy.module.micronumpy import interp_ufuncs from rpython.rlib.objectmodel import specialize, instantiate +from rpython.rlib.nonconst import NonConstant class BogusBytecode(Exception): @@ -40,6 +41,10 @@ TWO_ARG_FUNCTIONS = ["dot", 'take'] THREE_ARG_FUNCTIONS = ['where'] +class W_TypeObject(W_Root): + def __init__(self, name): + self.name = name + class FakeSpace(object): w_ValueError = "ValueError" w_TypeError = "TypeError" @@ -48,17 +53,17 @@ w_NotImplementedError = "NotImplementedError" w_None = None - w_bool = "bool" - w_int = "int" - w_float = "float" - w_list = "list" - w_long = "long" - w_tuple = 'tuple' - w_slice = "slice" - w_str = "str" - w_unicode = "unicode" - w_complex = "complex" - w_dict = "dict" + w_bool = W_TypeObject("bool") + w_int = W_TypeObject("int") + w_float = W_TypeObject("float") + w_list = W_TypeObject("list") + w_long = W_TypeObject("long") + w_tuple = W_TypeObject('tuple') + w_slice = W_TypeObject("slice") + w_str = W_TypeObject("str") + w_unicode = W_TypeObject("unicode") + w_complex = W_TypeObject("complex") + w_dict = W_TypeObject("dict") def __init__(self): """NOT_RPYTHON""" @@ -73,6 +78,13 @@ def issequence_w(self, w_obj): return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray) + def len(self, w_obj): + assert isinstance(w_obj, ListObject) + return self.wrap(len(w_obj.items)) + + def getattr(self, w_obj, w_attr): + return StringObject(NonConstant('foo')) + def isinstance_w(self, w_obj, w_tp): return w_obj.tp == w_tp From noreply at buildbot.pypy.org Wed May 15 19:19:48 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 19:19:48 +0200 (CEST) Subject: [pypy-commit] pypy default: RPython is odd, just give up. You can't mix methods in one call site Message-ID: <20130515171948.CA2431C02E4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64180:e981356d611c Date: 2013-05-15 19:01 +0200 http://bitbucket.org/pypy/pypy/changeset/e981356d611c/ Log: RPython is odd, just give up. You can't mix methods in one call site that are different functions from the same class, but you can mix functions. Work around this problem. diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py --- a/pypy/objspace/fake/checkmodule.py +++ b/pypy/objspace/fake/checkmodule.py @@ -5,6 +5,7 @@ def checkmodule(*modnames): config = get_pypy_config(translating=True) space = FakeObjSpace(config) + space.setup() seeobj_w = [] for modname in modnames: mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__']) diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -323,38 +323,36 @@ t.buildrtyper().specialize() t.checkgraphs() + def setup(space): + for name in (ObjSpace.ConstantTable + + ObjSpace.ExceptionTable + + ['int', 'str', 'float', 'long', 'tuple', 'list', + 'dict', 'unicode', 'complex', 'slice', 'bool', + 'basestring', 'object', 'bytearray']): + setattr(space, 'w_' + name, w_some_obj()) + space.w_type = w_some_type() + # + for (name, _, arity, _) in ObjSpace.MethodTable: + if name == 'type': + continue + args = ['w_%d' % i for i in range(arity)] + params = args[:] + d = {'is_root': is_root, + 'w_some_obj': w_some_obj} + if name in ('get',): + params[-1] += '=None' + exec compile2("""\ + def meth(%s): + %s + return w_some_obj() + """ % (', '.join(params), + '; '.join(['is_root(%s)' % arg for arg in args]))) in d + meth = func_with_new_name(d['meth'], name) + setattr(space, name, meth) + # + for name in ObjSpace.IrregularOpTable: + assert hasattr(space, name) # missing? -def setup(): - for name in (ObjSpace.ConstantTable + - ObjSpace.ExceptionTable + - ['int', 'str', 'float', 'long', 'tuple', 'list', - 'dict', 'unicode', 'complex', 'slice', 'bool', - 'basestring', 'object', 'bytearray']): - setattr(FakeObjSpace, 'w_' + name, w_some_obj()) - FakeObjSpace.w_type = w_some_type() - # - for (name, _, arity, _) in ObjSpace.MethodTable: - if name == 'type': - continue - args = ['w_%d' % i for i in range(arity)] - params = args[:] - d = {'is_root': is_root, - 'w_some_obj': w_some_obj} - if name in ('get',): - params[-1] += '=None' - exec compile2("""\ - def meth(self, %s): - %s - return w_some_obj() - """ % (', '.join(params), - '; '.join(['is_root(%s)' % arg for arg in args]))) in d - meth = func_with_new_name(d['meth'], name) - setattr(FakeObjSpace, name, meth) - # - for name in ObjSpace.IrregularOpTable: - assert hasattr(FakeObjSpace, name) # missing? - -setup() # ____________________________________________________________ diff --git a/rpython/tool/sourcetools.py b/rpython/tool/sourcetools.py --- a/rpython/tool/sourcetools.py +++ b/rpython/tool/sourcetools.py @@ -169,14 +169,14 @@ try: co = compile2_cache[key] #print "***** duplicate code ******* " - #print source - except KeyError: - #if DEBUG: - co = py.code.compile(source, filename, mode, flags) - #else: - # co = compile(source, filename, mode, flags) - compile2_cache[key] = co - return co + #print source + except KeyError: + #if DEBUG: + co = py.code.compile(source, filename, mode, flags) + #else: + # co = compile(source, filename, mode, flags) + compile2_cache[key] = co + return co compile2_cache = {} @@ -203,7 +203,7 @@ localnames = locals.keys() localnames.sort() values = [locals[key] for key in localnames] - + source = source.putaround( before = "def container(%s):" % (', '.join(localnames),), after = "# no unindent\n return %s" % resultname) @@ -305,7 +305,7 @@ items = [_convert_const_maybe(item, encoding) for item in x] return tuple(items) return x - + def with_unicode_literals(fn=None, **kwds): """Decorator that replace all string literals with unicode literals. Similar to 'from __future__ import string literals' at function level. From noreply at buildbot.pypy.org Wed May 15 19:30:15 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 15 May 2013 19:30:15 +0200 (CEST) Subject: [pypy-commit] pypy default: fix this test Message-ID: <20130515173015.705D71C146E@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64181:f87522e1a950 Date: 2013-05-15 19:17 +0200 http://bitbucket.org/pypy/pypy/changeset/f87522e1a950/ Log: fix this test 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 @@ -1186,7 +1186,7 @@ config = get_combined_translation_config(translating=True) self.config = config - @entrypoint('test', [lltype.Signed], relax=True, c_name='foo') + @entrypoint('test', [lltype.Signed], c_name='foo') def f(a): return a + 3 From noreply at buildbot.pypy.org Wed May 15 19:44:39 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:39 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__init__/__len__ multi-methods. Message-ID: <20130515174439.1A1DA1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64182:d6955fb2f4f0 Date: 2013-05-15 15:45 +0200 http://bitbucket.org/pypy/pypy/changeset/d6955fb2f4f0/ Log: Remove list.__init__/__len__ multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -15,11 +15,13 @@ from rpython.rlib.listsort import make_timsort_class from rpython.rlib import rerased, jit, debug from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM +from pypy.objspace.std.stdtypedef import StdTypeDef from sys import maxint + UNROLL_CUTOFF = 5 + class W_AbstractListObject(W_Object): __slots__ = () @@ -326,6 +328,20 @@ argument reverse. Argument must be unwrapped.""" self.strategy.sort(self, reverse) + # exposed to app-level + + def descr_init(self, space, __args__): + # this is on the silly side + w_iterable, = __args__.parse_obj( + None, 'list', init_signature, init_defaults) + self.clear(space) + if w_iterable is not None: + self.extend(w_iterable) + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' from pypy.objspace.std.iterobject import W_ReverseSeqIterObject @@ -1368,18 +1384,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def init__List(space, w_list, __args__): - # this is on the silly side - w_iterable, = __args__.parse_obj( - None, 'list', init_signature, init_defaults) - w_list.clear(space) - if w_iterable is not None: - w_list.extend(w_iterable) - -def len__List(space, w_list): - result = w_list.length() - return wrapint(space, result) - def getitem__List_ANY(space, w_list, w_index): try: return w_list.getitem(get_list_index(space, w_index)) @@ -1684,7 +1688,11 @@ __doc__ = """list() -> new list list(sequence) -> new list initialized from sequence's items""", __new__ = interp2app(descr_new), + __init__ = interp2app(W_ListObject.descr_init), __hash__ = None, + + __len__ = interp2app(W_ListObject.descr_len), + sort = interp2app(W_ListObject.descr_sort), index = interp2app(W_ListObject.descr_index), append = interp2app(W_ListObject.append), From noreply at buildbot.pypy.org Wed May 15 19:44:40 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:40 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__getitem__/__getslice__ multi-methods. Message-ID: <20130515174440.3B6DE1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64183:c391c5a8e7f6 Date: 2013-05-15 15:54 +0200 http://bitbucket.org/pypy/pypy/changeset/c391c5a8e7f6/ Log: Remove list.__getitem__/__getslice__ multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -342,6 +342,31 @@ result = self.length() return wrapint(space, result) + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + # XXX consider to extend rlist's functionality? + length = self.length() + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, step, slicelength) + + try: + return self.getitem(get_list_index(space, w_index)) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + + slicelength = stop - start + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, 1, stop - start) + def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' from pypy.objspace.std.iterobject import W_ReverseSeqIterObject @@ -1384,31 +1409,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def getitem__List_ANY(space, w_list, w_index): - try: - return w_list.getitem(get_list_index(space, w_index)) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - -def getitem__List_Slice(space, w_list, w_slice): - # XXX consider to extend rlist's functionality? - length = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - if slicelength == 0: - return make_empty_list(space) - return w_list.getslice(start, stop, step, slicelength) - -def getslice__List_ANY_ANY(space, w_list, w_start, w_stop): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - - slicelength = stop - start - if slicelength == 0: - return make_empty_list(space) - return w_list.getslice(start, stop, 1, stop - start) - def setslice__List_ANY_ANY_List(space, w_list, w_start, w_stop, w_other): length = w_list.length() start, stop = normalize_simple_slice(space, length, w_start, w_stop) @@ -1693,6 +1693,9 @@ __len__ = interp2app(W_ListObject.descr_len), + __getitem__ = interp2app(W_ListObject.descr_getitem), + __getslice__ = interp2app(W_ListObject.descr_getslice), + sort = interp2app(W_ListObject.descr_sort), index = interp2app(W_ListObject.descr_index), append = interp2app(W_ListObject.append), From noreply at buildbot.pypy.org Wed May 15 19:44:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:41 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__setitem__/__setslice__ multi-methods. Message-ID: <20130515174441.6EDF21C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64184:d0f14d2a8109 Date: 2013-05-15 16:44 +0200 http://bitbucket.org/pypy/pypy/changeset/d0f14d2a8109/ Log: Remove list.__setitem__/__setslice__ multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -367,6 +367,36 @@ return make_empty_list(space) return self.getslice(start, stop, 1, stop - start) + def descr_setitem(self, space, w_index, w_any): + if isinstance(w_index, W_SliceObject): + oldsize = self.length() + start, stop, step, slicelength = w_index.indices4(space, oldsize) + if isinstance(w_any, W_ListObject): + self.setslice(start, step, slicelength, w_any) + else: + sequence_w = space.listview(w_any) + w_other = W_ListObject(space, sequence_w) + self.setslice(start, step, slicelength, w_other) + return + + idx = get_list_index(space, w_index) + try: + self.setitem(idx, w_any) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_setslice(self, space, w_start, w_stop, w_iterable): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + + if isinstance(w_iterable, W_ListObject): + self.setslice(start, 1, stop-start, w_iterable) + else: + sequence_w = space.listview(w_iterable) + w_other = W_ListObject(space, sequence_w) + self.setslice(start, 1, stop-start, w_other) + def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' from pypy.objspace.std.iterobject import W_ReverseSeqIterObject @@ -1409,18 +1439,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def setslice__List_ANY_ANY_List(space, w_list, w_start, w_stop, w_other): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - w_list.setslice(start, 1, stop-start, w_other) - -def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - sequence_w = space.listview(w_iterable) - w_other = W_ListObject(space, sequence_w) - w_list.setslice(start, 1, stop-start, w_other) - def delslice__List_ANY_ANY(space, w_list, w_start, w_stop): length = w_list.length() start, stop = normalize_simple_slice(space, length, w_start, w_stop) @@ -1541,27 +1559,6 @@ start, stop, step, slicelength = w_slice.indices4(space, w_list.length()) w_list.deleteslice(start, step, slicelength) -def setitem__List_ANY_ANY(space, w_list, w_index, w_any): - idx = get_list_index(space, w_index) - try: - w_list.setitem(idx, w_any) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - return space.w_None - -def setitem__List_Slice_List(space, w_list, w_slice, w_other): - oldsize = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, oldsize) - w_list.setslice(start, step, slicelength, w_other) - -def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable): - oldsize = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, oldsize) - sequence_w = space.listview(w_iterable) - w_other = W_ListObject(space, sequence_w) - w_list.setslice(start, step, slicelength, w_other) - app = applevel(""" def listrepr(currently_in_repr, l): 'The app-level part of repr().' @@ -1695,6 +1692,8 @@ __getitem__ = interp2app(W_ListObject.descr_getitem), __getslice__ = interp2app(W_ListObject.descr_getslice), + __setitem__ = interp2app(W_ListObject.descr_setitem), + __setslice__ = interp2app(W_ListObject.descr_setslice), sort = interp2app(W_ListObject.descr_sort), index = interp2app(W_ListObject.descr_index), From noreply at buildbot.pypy.org Wed May 15 19:44:42 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:42 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__delitem__/__delslice__ multi-methods. Message-ID: <20130515174442.A7C2A1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64185:b42d871e5519 Date: 2013-05-15 16:56 +0200 http://bitbucket.org/pypy/pypy/changeset/b42d871e5519/ Log: Remove list.__delitem__/__delslice__ multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -397,6 +397,27 @@ w_other = W_ListObject(space, sequence_w) self.setslice(start, 1, stop-start, w_other) + def descr_delitem(self, space, w_idx): + if isinstance(w_idx, W_SliceObject): + start, stop, step, slicelength = w_idx.indices4(space, self.length()) + self.deleteslice(start, step, slicelength) + return + + idx = get_list_index(space, w_idx) + if idx < 0: + idx += self.length() + try: + self.pop(idx) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + + def descr_delslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + self.deleteslice(start, 1, stop-start) + def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' from pypy.objspace.std.iterobject import W_ReverseSeqIterObject @@ -1439,11 +1460,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def delslice__List_ANY_ANY(space, w_list, w_start, w_stop): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - w_list.deleteslice(start, 1, stop-start) - def contains__List_ANY(space, w_list, w_obj): try: w_list.find(w_obj) @@ -1543,22 +1559,6 @@ gt__List_List = _make_list_comparison('gt') ge__List_List = _make_list_comparison('ge') -def delitem__List_ANY(space, w_list, w_idx): - idx = get_list_index(space, w_idx) - if idx < 0: - idx += w_list.length() - try: - w_list.pop(idx) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list deletion index out of range")) - return space.w_None - - -def delitem__List_Slice(space, w_list, w_slice): - start, stop, step, slicelength = w_slice.indices4(space, w_list.length()) - w_list.deleteslice(start, step, slicelength) - app = applevel(""" def listrepr(currently_in_repr, l): 'The app-level part of repr().' @@ -1694,6 +1694,8 @@ __getslice__ = interp2app(W_ListObject.descr_getslice), __setitem__ = interp2app(W_ListObject.descr_setitem), __setslice__ = interp2app(W_ListObject.descr_setslice), + __delitem__ = interp2app(W_ListObject.descr_delitem), + __delslice__ = interp2app(W_ListObject.descr_delslice), sort = interp2app(W_ListObject.descr_sort), index = interp2app(W_ListObject.descr_index), From noreply at buildbot.pypy.org Wed May 15 19:44:43 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:43 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__iter__/__contains__ multi-methods. Message-ID: <20130515174443.C4A641C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64186:01cb1c6441ed Date: 2013-05-15 17:01 +0200 http://bitbucket.org/pypy/pypy/changeset/01cb1c6441ed/ Log: Remove list.__iter__/__contains__ multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -342,6 +342,17 @@ result = self.length() return wrapint(space, result) + def descr_iter(self, space): + from pypy.objspace.std import iterobject + return iterobject.W_FastListIterObject(self) + + def descr_contains(self, space, w_obj): + try: + self.find(w_obj) + return space.w_True + except ValueError: + return space.w_False + def descr_getitem(self, space, w_index): if isinstance(w_index, W_SliceObject): # XXX consider to extend rlist's functionality? @@ -1460,17 +1471,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def contains__List_ANY(space, w_list, w_obj): - try: - w_list.find(w_obj) - return space.w_True - except ValueError: - return space.w_False - -def iter__List(space, w_list): - from pypy.objspace.std import iterobject - return iterobject.W_FastListIterObject(w_list) - def add__List_List(space, w_list1, w_list2): w_clone = w_list1.clone() w_clone.extend(w_list2) @@ -1689,6 +1689,8 @@ __hash__ = None, __len__ = interp2app(W_ListObject.descr_len), + __iter__ = interp2app(W_ListObject.descr_iter), + __contains__ = interp2app(W_ListObject.descr_contains), __getitem__ = interp2app(W_ListObject.descr_getitem), __getslice__ = interp2app(W_ListObject.descr_getslice), From noreply at buildbot.pypy.org Wed May 15 19:44:45 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:45 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__add__/__iadd__ multi-methods. Message-ID: <20130515174445.53E241C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64187:3765c6e20d7b Date: 2013-05-15 17:27 +0200 http://bitbucket.org/pypy/pypy/changeset/3765c6e20d7b/ Log: Remove list.__add__/__iadd__ multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -353,6 +353,24 @@ except ValueError: return space.w_False + def descr_add(self, space, w_list2): + w_clone = self.clone() + w_clone.extend(w_list2) + return w_clone + + def descr_inplace_add(self, space, w_iterable): + if isinstance(w_iterable, W_ListObject): + self.extend(w_iterable) + return self + + try: + self.extend(w_iterable) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self + def descr_getitem(self, space, w_index): if isinstance(w_index, W_SliceObject): # XXX consider to extend rlist's functionality? @@ -1471,24 +1489,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def add__List_List(space, w_list1, w_list2): - w_clone = w_list1.clone() - w_clone.extend(w_list2) - return w_clone - -def inplace_add__List_ANY(space, w_list1, w_iterable2): - try: - w_list1.extend(w_iterable2) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - return w_list1 - -def inplace_add__List_List(space, w_list1, w_list2): - w_list1.extend(w_list2) - return w_list1 - def mul_list_times(space, w_list, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) @@ -1692,6 +1692,9 @@ __iter__ = interp2app(W_ListObject.descr_iter), __contains__ = interp2app(W_ListObject.descr_contains), + __add__ = interp2app(W_ListObject.descr_add), + __iadd__ = interp2app(W_ListObject.descr_inplace_add), + __getitem__ = interp2app(W_ListObject.descr_getitem), __getslice__ = interp2app(W_ListObject.descr_getslice), __setitem__ = interp2app(W_ListObject.descr_setitem), diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -783,6 +783,8 @@ assert l == [1,2,3,4,5] def test_iadd_subclass(self): + #XXX + skip("Maybe there is something wrong in descroperation?") class Bar(object): def __radd__(self, other): return ('radd', self, other) From noreply at buildbot.pypy.org Wed May 15 19:44:46 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:46 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__add__/__radd__/__iadd__ multi-methods. Message-ID: <20130515174446.862751C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64188:65beb21312e7 Date: 2013-05-15 17:51 +0200 http://bitbucket.org/pypy/pypy/changeset/65beb21312e7/ Log: Remove list.__add__/__radd__/__iadd__ multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -371,6 +371,31 @@ raise return self + def mul_list_times(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self.mul(times) + + def descr_mul(self, space, w_times): + return self.mul_list_times(space, w_times) + + def descr_rmul(self, space, w_times): + return self.mul_list_times(self.space, w_times) + + def descr_inplace_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + raise FailedToImplement + raise + self.inplace_mul(times) + return self + def descr_getitem(self, space, w_index): if isinstance(w_index, W_SliceObject): # XXX consider to extend rlist's functionality? @@ -1489,31 +1514,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def mul_list_times(space, w_list, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - return w_list.mul(times) - -def mul__List_ANY(space, w_list, w_times): - return mul_list_times(space, w_list, w_times) - -def mul__ANY_List(space, w_times, w_list): - return mul_list_times(space, w_list, w_times) - -def inplace_mul__List_ANY(space, w_list, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - w_list.inplace_mul(times) - return w_list - def list_unroll_condition(space, w_list1, w_list2): return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) @@ -1694,6 +1694,9 @@ __add__ = interp2app(W_ListObject.descr_add), __iadd__ = interp2app(W_ListObject.descr_inplace_add), + __mul__ = interp2app(W_ListObject.descr_mul), + __rmul__ = interp2app(W_ListObject.descr_rmul), + __imul__ = interp2app(W_ListObject.descr_inplace_mul), __getitem__ = interp2app(W_ListObject.descr_getitem), __getslice__ = interp2app(W_ListObject.descr_getslice), From noreply at buildbot.pypy.org Wed May 15 19:44:47 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:47 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list comparison multi-methods. Message-ID: <20130515174447.B51CA1C146E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64189:10e0cdd4ff06 Date: 2013-05-15 18:20 +0200 http://bitbucket.org/pypy/pypy/changeset/10e0cdd4ff06/ Log: Remove list comparison multi-methods. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -126,6 +126,10 @@ from pypy.objspace.std.floatobject import W_FloatObject return type(w_object) is W_FloatObject +def list_unroll_condition(space, w_list1, w_list2): + return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ + jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) + class W_ListObject(W_AbstractListObject): def __init__(w_self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) @@ -338,6 +342,49 @@ if w_iterable is not None: self.extend(w_iterable) + @jit.look_inside_iff(list_unroll_condition) + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_ListObject): + return space.w_NotImplemented + + # needs to be safe against eq_w() mutating the w_lists behind our back + if self.length() != w_other.length(): + return space.w_False + + # XXX in theory, this can be implemented more efficiently as well. let's + # not care for now + i = 0 + while i < self.length() and i < w_other.length(): + if not space.eq_w(self.getitem(i), w_other.getitem(i)): + return space.w_False + i += 1 + return space.w_True + + def descr_ne(self, space, w_other): + return space.not_(self.descr_eq(space, w_other)) + + @staticmethod + def _make_list_comparison(name): + import operator + op = getattr(operator, name) + + @jit.look_inside_iff(list_unroll_condition) + def compare_unwrappeditems(space, w_list1, w_list2): + # needs to be safe against eq_w() mutating the w_lists behind our back + # Search for the first index where items are different + i = 0 + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now + while i < w_list1.length() and i < w_list2.length(): + w_item1 = w_list1.getitem(i) + w_item2 = w_list2.getitem(i) + if not space.eq_w(w_item1, w_item2): + return getattr(space, name)(w_item1, w_item2) + i += 1 + # No more items to compare -- compare sizes + return space.newbool(op(w_list1.length(), w_list2.length())) + return func_with_new_name(compare_unwrappeditems, name + '__List_List') + def descr_len(self, space): result = self.length() return wrapint(space, result) @@ -1514,51 +1561,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def list_unroll_condition(space, w_list1, w_list2): - return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) - - at jit.look_inside_iff(list_unroll_condition) -def eq__List_List(space, w_list1, w_list2): - # needs to be safe against eq_w() mutating the w_lists behind our back - if w_list1.length() != w_list2.length(): - return space.w_False - - # XXX in theory, this can be implemented more efficiently as well. let's - # not care for now - i = 0 - while i < w_list1.length() and i < w_list2.length(): - if not space.eq_w(w_list1.getitem(i), w_list2.getitem(i)): - return space.w_False - i += 1 - return space.w_True - -def _make_list_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(list_unroll_condition) - def compare_unwrappeditems(space, w_list1, w_list2): - # needs to be safe against eq_w() mutating the w_lists behind our back - # Search for the first index where items are different - i = 0 - # XXX in theory, this can be implemented more efficiently as well. - # let's not care for now - while i < w_list1.length() and i < w_list2.length(): - w_item1 = w_list1.getitem(i) - w_item2 = w_list2.getitem(i) - if not space.eq_w(w_item1, w_item2): - return getattr(space, name)(w_item1, w_item2) - i += 1 - # No more items to compare -- compare sizes - return space.newbool(op(w_list1.length(), w_list2.length())) - return func_with_new_name(compare_unwrappeditems, name + '__List_List') - -lt__List_List = _make_list_comparison('lt') -le__List_List = _make_list_comparison('le') -gt__List_List = _make_list_comparison('gt') -ge__List_List = _make_list_comparison('ge') - app = applevel(""" def listrepr(currently_in_repr, l): 'The app-level part of repr().' @@ -1688,6 +1690,13 @@ __init__ = interp2app(W_ListObject.descr_init), __hash__ = None, + __eq__ = interp2app(W_ListObject.descr_eq), + __ne__ = interp2app(W_ListObject.descr_ne), + __lt__ = interp2app(W_ListObject._make_list_comparison('lt')), + __le__ = interp2app(W_ListObject._make_list_comparison('le')), + __gt__ = interp2app(W_ListObject._make_list_comparison('gt')), + __ge__ = interp2app(W_ListObject._make_list_comparison('ge')), + __len__ = interp2app(W_ListObject.descr_len), __iter__ = interp2app(W_ListObject.descr_iter), __contains__ = interp2app(W_ListObject.descr_contains), From noreply at buildbot.pypy.org Wed May 15 19:44:48 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:48 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list.__repr__ multi-method. Message-ID: <20130515174448.E71FF1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64190:023fdccdedde Date: 2013-05-15 18:22 +0200 http://bitbucket.org/pypy/pypy/changeset/023fdccdedde/ Log: Remove list.__repr__ multi-method. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -342,6 +342,15 @@ if w_iterable is not None: self.extend(w_iterable) + def descr_repr(self, space): + if self.length() == 0: + return space.wrap('[]') + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return listrepr(space, w_currently_in_repr, self) + @jit.look_inside_iff(list_unroll_condition) def descr_eq(self, space, w_other): if not isinstance(w_other, W_ListObject): @@ -1579,15 +1588,6 @@ listrepr = app.interphook("listrepr") -def repr__List(space, w_list): - if w_list.length() == 0: - return space.wrap('[]') - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return listrepr(space, w_currently_in_repr, w_list) - def get_positive_index(where, length): if where < 0: where += length @@ -1688,6 +1688,7 @@ list(sequence) -> new list initialized from sequence's items""", __new__ = interp2app(descr_new), __init__ = interp2app(W_ListObject.descr_init), + __repr__ = interp2app(W_ListObject.descr_repr), __hash__ = None, __eq__ = interp2app(W_ListObject.descr_eq), From noreply at buildbot.pypy.org Wed May 15 19:44:50 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:50 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: hg merge default Message-ID: <20130515174450.93D1D1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64191:ec226759d640 Date: 2013-05-15 19:31 +0200 http://bitbucket.org/pypy/pypy/changeset/ec226759d640/ Log: hg merge default 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 @@ -8,5 +8,11 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) +.. branch: remove-array-smm +Remove multimethods in the arraymodule + +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback .. branch: remove-set-smm +Remove multi-methods on sets 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 @@ -100,11 +100,11 @@ return space.w_True if comp_op == LT or comp_op == LE: if arr1.len < arr2.len: - return space.w_False + return space.w_True + return space.w_False + if arr1.len > arr2.len: return space.w_True - if arr1.len > arr2.len: - return space.w_False - return space.w_True + return space.w_False UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True})) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -552,6 +552,15 @@ assert (a >= c) is False assert (c >= a) is True + a = self.array('i', [-1, 0, 1, 42, 0x7f]) + assert not a == 2*a + assert a != 2*a + assert a < 2*a + assert a <= 2*a + assert not a > 2*a + assert not a >= 2*a + + def test_reduce(self): import pickle a = self.array('i', [1, 2, 3]) diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -14,6 +14,7 @@ from pypy.module.micronumpy.interp_arrayops import where from pypy.module.micronumpy import interp_ufuncs from rpython.rlib.objectmodel import specialize, instantiate +from rpython.rlib.nonconst import NonConstant class BogusBytecode(Exception): @@ -40,6 +41,10 @@ TWO_ARG_FUNCTIONS = ["dot", 'take'] THREE_ARG_FUNCTIONS = ['where'] +class W_TypeObject(W_Root): + def __init__(self, name): + self.name = name + class FakeSpace(object): w_ValueError = "ValueError" w_TypeError = "TypeError" @@ -48,17 +53,17 @@ w_NotImplementedError = "NotImplementedError" w_None = None - w_bool = "bool" - w_int = "int" - w_float = "float" - w_list = "list" - w_long = "long" - w_tuple = 'tuple' - w_slice = "slice" - w_str = "str" - w_unicode = "unicode" - w_complex = "complex" - w_dict = "dict" + w_bool = W_TypeObject("bool") + w_int = W_TypeObject("int") + w_float = W_TypeObject("float") + w_list = W_TypeObject("list") + w_long = W_TypeObject("long") + w_tuple = W_TypeObject('tuple') + w_slice = W_TypeObject("slice") + w_str = W_TypeObject("str") + w_unicode = W_TypeObject("unicode") + w_complex = W_TypeObject("complex") + w_dict = W_TypeObject("dict") def __init__(self): """NOT_RPYTHON""" @@ -73,6 +78,13 @@ def issequence_w(self, w_obj): return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray) + def len(self, w_obj): + assert isinstance(w_obj, ListObject) + return self.wrap(len(w_obj.items)) + + def getattr(self, w_obj, w_attr): + return StringObject(NonConstant('foo')) + def isinstance_w(self, w_obj, w_tp): return w_obj.tp == w_tp diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py --- a/pypy/objspace/fake/checkmodule.py +++ b/pypy/objspace/fake/checkmodule.py @@ -5,6 +5,7 @@ def checkmodule(*modnames): config = get_pypy_config(translating=True) space = FakeObjSpace(config) + space.setup() seeobj_w = [] for modname in modnames: mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__']) diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -55,6 +55,10 @@ from rpython.rlib.rbigint import rbigint return rbigint.fromint(NonConstant(42)) +class W_MyListObj(W_MyObject): + def append(self, w_other): + pass + class W_MyType(W_MyObject): def __init__(self): self.mro_w = [w_some_obj(), w_some_obj()] @@ -107,6 +111,9 @@ self._seen_extras = [] ObjSpace.__init__(self, config=config) + def _freeze_(self): + return True + def float_w(self, w_obj): is_root(w_obj) return NonConstant(42.5) @@ -131,7 +138,7 @@ def newlist(self, list_w): for w_x in list_w: is_root(w_x) - return w_some_obj() + return W_MyListObj() def newslice(self, w_start, w_end, w_step): is_root(w_start) @@ -316,38 +323,36 @@ t.buildrtyper().specialize() t.checkgraphs() + def setup(space): + for name in (ObjSpace.ConstantTable + + ObjSpace.ExceptionTable + + ['int', 'str', 'float', 'long', 'tuple', 'list', + 'dict', 'unicode', 'complex', 'slice', 'bool', + 'basestring', 'object', 'bytearray']): + setattr(space, 'w_' + name, w_some_obj()) + space.w_type = w_some_type() + # + for (name, _, arity, _) in ObjSpace.MethodTable: + if name == 'type': + continue + args = ['w_%d' % i for i in range(arity)] + params = args[:] + d = {'is_root': is_root, + 'w_some_obj': w_some_obj} + if name in ('get',): + params[-1] += '=None' + exec compile2("""\ + def meth(%s): + %s + return w_some_obj() + """ % (', '.join(params), + '; '.join(['is_root(%s)' % arg for arg in args]))) in d + meth = func_with_new_name(d['meth'], name) + setattr(space, name, meth) + # + for name in ObjSpace.IrregularOpTable: + assert hasattr(space, name) # missing? -def setup(): - for name in (ObjSpace.ConstantTable + - ObjSpace.ExceptionTable + - ['int', 'str', 'float', 'long', 'tuple', 'list', - 'dict', 'unicode', 'complex', 'slice', 'bool', - 'basestring', 'object', 'bytearray']): - setattr(FakeObjSpace, 'w_' + name, w_some_obj()) - FakeObjSpace.w_type = w_some_type() - # - for (name, _, arity, _) in ObjSpace.MethodTable: - if name == 'type': - continue - args = ['w_%d' % i for i in range(arity)] - params = args[:] - d = {'is_root': is_root, - 'w_some_obj': w_some_obj} - if name in ('get',): - params[-1] += '=None' - exec compile2("""\ - def meth(self, %s): - %s - return w_some_obj() - """ % (', '.join(params), - '; '.join(['is_root(%s)' % arg for arg in args]))) in d - meth = func_with_new_name(d['meth'], name) - setattr(FakeObjSpace, name, meth) - # - for name in ObjSpace.IrregularOpTable: - assert hasattr(FakeObjSpace, name) # missing? - -setup() # ____________________________________________________________ diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -333,8 +333,9 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(w_self, space): - raise UnwrapError, 'cannot unwrap %r' % (w_self,) + def unwrap(self, space): + raise UnwrapError('cannot unwrap %r' % self) + class UnwrapError(Exception): pass @@ -399,7 +400,7 @@ mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree) return mm -NOT_MULTIMETHODS = dict.fromkeys( +NOT_MULTIMETHODS = set( ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv', 'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift', 'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel', diff --git a/rpython/jit/metainterp/test/test_compile.py b/rpython/jit/metainterp/test/test_compile.py --- a/rpython/jit/metainterp/test/test_compile.py +++ b/rpython/jit/metainterp/test/test_compile.py @@ -1,10 +1,10 @@ from rpython.config.translationoption import get_combined_translation_config -from rpython.jit.metainterp.history import TargetToken, ConstInt, History, Stats -from rpython.jit.metainterp.history import BoxInt, INT +from rpython.jit.metainterp.history import ConstInt, History, Stats +from rpython.jit.metainterp.history import INT from rpython.jit.metainterp.compile import compile_loop -from rpython.jit.metainterp.compile import ResumeGuardDescr from rpython.jit.metainterp.compile import ResumeGuardCountersInt from rpython.jit.metainterp.compile import compile_tmp_callback +from rpython.jit.metainterp import jitexc from rpython.jit.metainterp import jitprof, typesystem, compile from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.tool.oparser import parse @@ -13,7 +13,7 @@ class FakeCPU(object): class tracker: pass - + ts = typesystem.llhelper def __init__(self): self.seen = [] @@ -41,7 +41,7 @@ loopnumbering = 0 class FakeMetaInterpStaticData(object): - + logger_noopt = FakeLogger() logger_ops = FakeLogger() config = get_combined_translation_config(translating=True) @@ -192,14 +192,13 @@ assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), got) == llexc # class FakeMetaInterpSD: - class ExitFrameWithExceptionRef(Exception): - pass + pass FakeMetaInterpSD.cpu = cpu deadframe = cpu.execute_token(loop_token, -156, -178) fail_descr = cpu.get_latest_descr(deadframe) try: fail_descr.handle_fail(deadframe, FakeMetaInterpSD(), None) - except FakeMetaInterpSD.ExitFrameWithExceptionRef, e: - assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.args[1]) == llexc + except jitexc.ExitFrameWithExceptionRef, e: + assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.value) == llexc else: assert 0, "should have raised" diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -170,12 +170,57 @@ jit2gc = gctransformer.translator._jit2gc self.frame_tid = jit2gc['frame_tid'] self.gctransformer = gctransformer + # + # unless overridden in need_thread_support(): + self.belongs_to_current_thread = lambda framedata: True def need_stacklet_support(self, gctransformer, getfn): + from rpython.annotator import model as annmodel + from rpython.rlib import _stacklet_asmgcc # stacklet support: BIG HACK for rlib.rstacklet - from rpython.rlib import _stacklet_asmgcc _stacklet_asmgcc._asmstackrootwalker = self # as a global! argh _stacklet_asmgcc.complete_destrptr(gctransformer) + # + def gc_detach_callback_pieces(): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + result = llmemory.NULL + framedata = anchor.address[1] + while framedata != anchor: + next = framedata.address[1] + if self.belongs_to_current_thread(framedata): + # detach it + prev = framedata.address[0] + prev.address[1] = next + next.address[0] = prev + # update the global stack counter + rffi.stackcounter.stacks_counter -= 1 + # reattach framedata into the singly-linked list 'result' + framedata.address[0] = rffi.cast(llmemory.Address, -1) + framedata.address[1] = result + result = framedata + framedata = next + return result + # + def gc_reattach_callback_pieces(pieces): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + while pieces != llmemory.NULL: + framedata = pieces + pieces = pieces.address[1] + # attach 'framedata' into the normal doubly-linked list + following = anchor.address[1] + following.address[0] = framedata + framedata.address[1] = following + anchor.address[1] = framedata + framedata.address[0] = anchor + # update the global stack counter + rffi.stackcounter.stacks_counter += 1 + # + s_addr = annmodel.SomeAddress() + s_None = annmodel.s_None + self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces, + [], s_addr) + self.gc_reattach_callback_pieces_ptr=getfn(gc_reattach_callback_pieces, + [s_addr], s_None) def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. @@ -227,6 +272,7 @@ stack_stop = llop.stack_current(llmemory.Address) return (stack_start <= framedata <= stack_stop or stack_start >= framedata >= stack_stop) + self.belongs_to_current_thread = belongs_to_current_thread def thread_before_fork(): # before fork(): collect all ASM_FRAMEDATA structures that do diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -800,6 +800,21 @@ def gct_gc_adr_of_root_stack_top(self, hop): self._gc_adr_of_gcdata_attr(hop, 'root_stack_top') + def gct_gc_detach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 0 + hop.genop("direct_call", + [self.root_walker.gc_detach_callback_pieces_ptr], + resultvar=op.result) + + def gct_gc_reattach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 1 + hop.genop("direct_call", + [self.root_walker.gc_reattach_callback_pieces_ptr, + op.args[0]], + resultvar=op.result) + def gct_gc_shadowstackref_new(self, hop): op = hop.spaceop livevars = self.push_roots(hop) diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -32,6 +32,7 @@ if not p.handle: return False self.context = llmemory.cast_ptr_to_adr(p.handle) + self.next_callback_piece = p.callback_pieces anchor = p.anchor del p self.curframe = lltype.malloc(WALKFRAME, flavor='raw') @@ -50,11 +51,19 @@ retaddraddr = self.translateptr(retaddraddr) curframe.frame_address = retaddraddr.address[0] - def teardown(self): - lltype.free(self.curframe, flavor='raw') - lltype.free(self.otherframe, flavor='raw') - self.context = llmemory.NULL - return llmemory.NULL + def fetch_next_stack_piece(self): + if self.next_callback_piece == llmemory.NULL: + lltype.free(self.curframe, flavor='raw') + lltype.free(self.otherframe, flavor='raw') + self.context = llmemory.NULL + return False + else: + anchor = self.next_callback_piece + nextaddr = anchor + sizeofaddr + nextaddr = self.translateptr(nextaddr) + self.next_callback_piece = nextaddr.address[0] + self.fill_initial_frame(self.curframe, anchor) + return True def next(self, obj, prev): # @@ -117,7 +126,10 @@ location) # ^^^ non-translated if caller.frame_address == llmemory.NULL: - return self.teardown() # completely done with this stack + # completely done with this piece of stack + if not self.fetch_next_stack_piece(): + return llmemory.NULL + continue # self.otherframe = callee self.curframe = caller @@ -154,6 +166,7 @@ SUSPSTACK = lltype.GcStruct('SuspStack', ('handle', _c.handle), ('anchor', llmemory.Address), + ('callback_pieces', llmemory.Address), rtti=True) NULL_SUSPSTACK = lltype.nullptr(SUSPSTACK) CUSTOMTRACEFUNC = lltype.FuncType([llmemory.Address, llmemory.Address], @@ -185,6 +198,7 @@ # stacklet with stacklet_new(). If this call fails, then we # are just returning NULL. _stack_just_closed() + # return _c.new(gcrootfinder.newthrd, llhelper(_c.run_fn, _new_runfn), llmemory.NULL) @@ -252,14 +266,36 @@ newsuspstack.handle = _c.null_handle self.suspstack = newsuspstack # Invoke '_new_callback' by closing the stack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + newsuspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _new_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) return self.get_result_suspstack(h) def switch(self, suspstack): + # Immediately before the switch, 'suspstack' describes the suspended + # state of the *target* of the switch. Then it is theoretically + # freed. In fact what occurs is that we reuse the same 'suspstack' + # object in the target, just after the switch, to store the + # description of where we came from. Then that "other" 'suspstack' + # object is returned. self.suspstack = suspstack + # + callback_pieces = llop.gc_detach_callback_pieces(llmemory.Address) + old_callback_pieces = suspstack.callback_pieces + suspstack.callback_pieces = callback_pieces + # h = pypy_asm_stackwalk2(llhelper(FUNCNOARG_P, _switch_callback), alternateanchor) + # + llop.gc_reattach_callback_pieces(lltype.Void, callback_pieces) + if not h: + self.suspstack.callback_pieces = old_callback_pieces + # return self.get_result_suspstack(h) def attach_handle_on_suspstack(self, handle): diff --git a/rpython/rlib/rsre/rpy.py b/rpython/rlib/rsre/rpy.py --- a/rpython/rlib/rsre/rpy.py +++ b/rpython/rlib/rsre/rpy.py @@ -8,11 +8,12 @@ module is a custom module that has _sre.compile == my_compile and CODESIZE == rsre_char.CODESIZE. """ - import sre_compile, __builtin__, new + import sre_compile, sre_constants, __builtin__, new sre_hacked = new.module("_sre_hacked") sre_hacked.compile = my_compile sre_hacked.MAGIC = sre_compile.MAGIC sre_hacked.CODESIZE = rsre_char.CODESIZE + sre_hacked.MAXREPEAT = sre_constants.MAX_REPEAT sre_hacked.getlower = rsre_char.getlower def my_import(name, *args): if name == '_sre': diff --git a/rpython/rlib/rsre/rsre_re.py b/rpython/rlib/rsre/rsre_re.py --- a/rpython/rlib/rsre/rsre_re.py +++ b/rpython/rlib/rsre/rsre_re.py @@ -4,7 +4,7 @@ """ import re, sys from rpython.rlib.rsre import rsre_core, rsre_char -from rpython.rlib.rsre.test.test_match import get_code as _get_code +from rpython.rlib.rsre.rpy import get_code as _get_code from rpython.rlib.unicodedata import unicodedb from rpython.rlib.objectmodel import specialize rsre_char.set_unicode_db(unicodedb) @@ -176,7 +176,7 @@ def span(self, groupnum=0): # if not isinstance(groupnum, (int, long)): # groupnum = self.re.groupindex[groupnum] - + return self._ctx.span(groupnum) def start(self, groupnum=0): diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -82,6 +82,29 @@ return True return False + @here_is_a_test + def test_c_callback(self): + # + self.steps = [0] + self.main_h = self.sthread.new(cb_stacklet_callback, llmemory.NULL) + self.steps.append(2) + call_qsort_rec(10) + self.steps.append(9) + assert not self.sthread.is_empty_handle(self.main_h) + self.main_h = self.sthread.switch(self.main_h) + assert self.sthread.is_empty_handle(self.main_h) + # + # check that self.steps == [0,1,2, 3,4,5,6, 3,4,5,6, 3,4,5,6,..., 9] + print self.steps + expected = 0 + assert self.steps[-1] == 9 + for i in range(len(self.steps)-1): + if expected == 7: + expected = 3 + assert self.steps[i] == expected + expected += 1 + assert expected == 7 + class FooObj: def __init__(self, n, d, next=None): @@ -211,6 +234,43 @@ print "LEAVING %d to go to %d" % (self.n, n) return h +QSORT_CALLBACK_PTR = lltype.Ptr(lltype.FuncType( + [llmemory.Address, llmemory.Address], rffi.INT)) +qsort = rffi.llexternal('qsort', + [llmemory.Address, rffi.SIZE_T, rffi.SIZE_T, + QSORT_CALLBACK_PTR], + lltype.Void) +def cb_compare_callback(a, b): + runner.steps.append(3) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.main_h = runner.sthread.switch(runner.main_h) + assert not runner.sthread.is_empty_handle(runner.main_h) + runner.steps.append(6) + return rffi.cast(rffi.INT, 1) +def cb_stacklet_callback(h, arg): + runner.steps.append(1) + while True: + assert not runner.sthread.is_empty_handle(h) + h = runner.sthread.switch(h) + assert not runner.sthread.is_empty_handle(h) + if runner.steps[-1] == 9: + return h + runner.steps.append(4) + rgc.collect() + runner.steps.append(5) +class GcObject(object): + num = 1234 +def call_qsort_rec(r): + if r > 0: + g = GcObject() + g.num += r + call_qsort_rec(r - 1) + assert g.num == 1234 + r + else: + raw = llmemory.raw_malloc(5) + qsort(raw, 5, 1, cb_compare_callback) + llmemory.raw_free(raw) + def entry_point(argv): seed = 0 diff --git a/rpython/rtyper/llinterp.py b/rpython/rtyper/llinterp.py --- a/rpython/rtyper/llinterp.py +++ b/rpython/rtyper/llinterp.py @@ -886,6 +886,11 @@ def op_gc_stack_bottom(self): pass # marker for trackgcroot.py + def op_gc_detach_callback_pieces(self): + raise NotImplementedError("gc_detach_callback_pieces") + def op_gc_reattach_callback_pieces(self): + raise NotImplementedError("gc_reattach_callback_pieces") + def op_gc_shadowstackref_new(self): # stacklet+shadowstack raise NotImplementedError("gc_shadowstackref_new") def op_gc_shadowstackref_context(self): diff --git a/rpython/rtyper/lltypesystem/lloperation.py b/rpython/rtyper/lltypesystem/lloperation.py --- a/rpython/rtyper/lltypesystem/lloperation.py +++ b/rpython/rtyper/lltypesystem/lloperation.py @@ -516,6 +516,10 @@ 'gc_asmgcroot_static': LLOp(sideeffects=False), 'gc_stack_bottom': LLOp(canrun=True), + # for stacklet+asmgcroot support + 'gc_detach_callback_pieces': LLOp(), + 'gc_reattach_callback_pieces': LLOp(), + # for stacklet+shadowstack support 'gc_shadowstackref_new': LLOp(canmallocgc=True), 'gc_shadowstackref_context': LLOp(), diff --git a/rpython/tool/sourcetools.py b/rpython/tool/sourcetools.py --- a/rpython/tool/sourcetools.py +++ b/rpython/tool/sourcetools.py @@ -169,14 +169,14 @@ try: co = compile2_cache[key] #print "***** duplicate code ******* " - #print source - except KeyError: - #if DEBUG: - co = py.code.compile(source, filename, mode, flags) - #else: - # co = compile(source, filename, mode, flags) - compile2_cache[key] = co - return co + #print source + except KeyError: + #if DEBUG: + co = py.code.compile(source, filename, mode, flags) + #else: + # co = compile(source, filename, mode, flags) + compile2_cache[key] = co + return co compile2_cache = {} @@ -203,7 +203,7 @@ localnames = locals.keys() localnames.sort() values = [locals[key] for key in localnames] - + source = source.putaround( before = "def container(%s):" % (', '.join(localnames),), after = "# no unindent\n return %s" % resultname) @@ -305,7 +305,7 @@ items = [_convert_const_maybe(item, encoding) for item in x] return tuple(items) return x - + def with_unicode_literals(fn=None, **kwds): """Decorator that replace all string literals with unicode literals. Similar to 'from __future__ import string literals' at function level. 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 @@ -1186,7 +1186,7 @@ config = get_combined_translation_config(translating=True) self.config = config - @entrypoint('test', [lltype.Signed], relax=True, c_name='foo') + @entrypoint('test', [lltype.Signed], c_name='foo') def f(a): return a + 3 From noreply at buildbot.pypy.org Wed May 15 19:44:51 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:51 +0200 (CEST) Subject: [pypy-commit] pypy remove-set-smm: Close to-be-merged branch. Message-ID: <20130515174451.B463E1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-set-smm Changeset: r64192:547e1eb226e4 Date: 2013-05-15 19:31 +0200 http://bitbucket.org/pypy/pypy/changeset/547e1eb226e4/ Log: Close to-be-merged branch. From noreply at buildbot.pypy.org Wed May 15 19:44:53 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 19:44:53 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge remove-set-smm, it removes multi-methods on sets. Message-ID: <20130515174453.099BD1C009D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64193:337350a2c8dd Date: 2013-05-15 19:32 +0200 http://bitbucket.org/pypy/pypy/changeset/337350a2c8dd/ Log: Merge remove-set-smm, it removes multi-methods on sets. 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 @@ -13,3 +13,6 @@ .. branch: callback-stacklet Fixed bug when switching stacklets from a C callback + +.. branch: remove-set-smm +Remove multi-methods on sets diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,8 +1,8 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef +from pypy.objspace.std.setobject import set_typedef as settypedef +from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.signature import Signature diff --git a/pypy/objspace/std/frozensettype.py b/pypy/objspace/std/frozensettype.py deleted file mode 100644 --- a/pypy/objspace/std/frozensettype.py +++ /dev/null @@ -1,55 +0,0 @@ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - - -frozenset_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -frozenset_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -frozenset_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -frozenset_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -frozenset_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -frozenset_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -frozenset_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -frozenset_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -frozenset_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__frozenset__new__(space, w_frozensettype, w_iterable=None): - from pypy.objspace.std.setobject import W_FrozensetObject - if (space.is_w(w_frozensettype, space.w_frozenset) and - w_iterable is not None and type(w_iterable) is W_FrozensetObject): - return w_iterable - w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) - W_FrozensetObject.__init__(w_obj, space, w_iterable) - return w_obj - -frozenset_typedef = StdTypeDef("frozenset", - __doc__ = """frozenset(iterable) --> frozenset object - -Build an immutable unordered collection.""", - __new__ = gateway.interp2app(descr__frozenset__new__), - ) - -frozenset_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -38,8 +38,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.settype import set_typedef - from pypy.objspace.std.frozensettype import frozenset_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.dicttype import dict_typedef @@ -63,10 +61,10 @@ from pypy.objspace.std import intobject from pypy.objspace.std import floatobject from pypy.objspace.std import complexobject - from pypy.objspace.std import setobject from pypy.objspace.std import tupleobject from pypy.objspace.std import listobject from pypy.objspace.std import dictmultiobject + from pypy.objspace.std import setobject from pypy.objspace.std import stringobject from pypy.objspace.std import bytearrayobject from pypy.objspace.std import typeobject @@ -81,6 +79,11 @@ import pypy.objspace.std.marshal_impl # install marshal multimethods + # not-multimethod based types + + self.pythontypes.append(setobject.W_SetObject.typedef) + self.pythontypes.append(setobject.W_FrozensetObject.typedef) + # the set of implementation types self.typeorder = { objectobject.W_ObjectObject: [], @@ -100,10 +103,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - setobject.W_BaseSetObject: [], - setobject.W_SetObject: [], - setobject.W_FrozensetObject: [], - setobject.W_SetIterObject: [], iterobject.W_SeqIterObject: [], iterobject.W_FastListIterObject: [], iterobject.W_FastTupleIterObject: [], @@ -192,12 +191,7 @@ (complexobject.W_ComplexObject, complexobject.delegate_Float2Complex), ] - self.typeorder[setobject.W_SetObject] += [ - (setobject.W_BaseSetObject, None) - ] - self.typeorder[setobject.W_FrozensetObject] += [ - (setobject.W_BaseSetObject, None) - ] + self.typeorder[stringobject.W_StringObject] += [ (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode), ] diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -1,13 +1,9 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway -from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef from pypy.interpreter.signature import Signature -from pypy.interpreter.generator import GeneratorIterator -from pypy.objspace.std.listobject import W_ListObject +from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.unicodeobject import W_UnicodeObject @@ -15,20 +11,13 @@ from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit + UNROLL_CUTOFF = 5 -class W_BaseSetObject(W_Object): + +class W_BaseSetObject(W_Root): typedef = None - # make sure that Base is used for Set and Frozenset in multimethod - # declarations - @classmethod - def is_implementation_for(cls, typedef): - if typedef is frozensettypedef or typedef is settypedef: - assert cls is W_BaseSetObject - return True - return False - def __init__(w_self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" w_self.space = space @@ -66,7 +55,6 @@ # _____________ strategy methods ________________ - def clear(self): """ Removes all elements from the set. """ self.strategy.clear(self) @@ -164,9 +152,355 @@ """ Removes an arbitrary element from the set. May raise KeyError if set is empty.""" return self.strategy.popitem(self) + # app-level operations + + def descr_init(self, space, __args__): + w_iterable, = __args__.parse_obj( + None, 'set', + init_signature, + init_defaults) + _initialize_set(space, self, w_iterable) + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return setrepr(space, w_currently_in_repr, self) + + def descr_cmp(self, space, w_other): + # hack hack until we get the expected result + raise OperationError(space.w_TypeError, + space.wrap('cannot compare sets using cmp()')) + + def descr_eq(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_False + + # XXX there is no test_buildinshortcut.py + # tested in test_buildinshortcut.py + # XXX do not make new setobject here + w_other_as_set = self._newobj(space, w_other) + return space.wrap(self.equals(w_other_as_set)) + + def descr_ne(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(not self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_True + + # XXX this is not tested + w_other_as_set = self._newobj(space, w_other) + return space.wrap(not self.equals(w_other_as_set)) + + # automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the + # correct answer here! + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() >= w_other.length(): + return space.w_False + else: + return self.descr_issubset(space, w_other) + + def descr_le(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() <= w_other.length(): + return space.w_False + else: + return self.descr_issuperset(space, w_other) + + def descr_ge(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + def descr_len(self, space): + return space.newint(self.length()) + + def descr_iter(self, space): + return W_SetIterObject(space, self.iter()) + + def descr_contains(self, space, w_other): + try: + return space.newbool(self.has_key(w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + w_f = _convert_set_to_frozenset(space, w_other) + if w_f is not None: + return space.newbool(self.has_key(w_f)) + raise + + def descr_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.difference(w_other) + + def descr_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.intersect(w_other) + + def descr_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + w_copy = self.copy_real() + w_copy.update(w_other) + return w_copy + + def descr_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.symmetric_difference(w_other) + + def descr_inplace_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.difference_update(w_other) + return self + + def descr_inplace_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.intersect_update(w_other) + return self + + def descr_inplace_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.update(w_other) + return self + + def descr_inplace_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.descr_symmetric_difference_update(space, w_other) + return self + + def descr_copy(self, space): + """Return a shallow copy of a set.""" + if type(self) is W_FrozensetObject: + return self + return self.copy_real() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference(self, space, others_w): + """Return a new set with elements in the set that are not in the + others.""" + result = self.copy_real() + result.descr_difference_update(space, others_w) + return result + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection(self, space, others_w): + """Return a new set with elements common to the set and all others.""" + #XXX find smarter implementations + others_w = [self] + others_w + + # find smallest set in others_w to reduce comparisons + startindex, startlength = 0, -1 + for i in range(len(others_w)): + w_other = others_w[i] + try: + length = space.int_w(space.len(w_other)) + except OperationError, e: + if (e.match(space, space.w_TypeError) or + e.match(space, space.w_AttributeError)): + continue + raise + + if startlength == -1 or length < startlength: + startindex = i + startlength = length + + others_w[startindex], others_w[0] = others_w[0], others_w[startindex] + + result = self._newobj(space, others_w[0]) + for i in range(1,len(others_w)): + w_other = others_w[i] + if isinstance(w_other, W_BaseSetObject): + result.intersect_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + result.intersect_update(w_other_as_set) + return result + + def descr_issubset(self, space, w_other): + """Report whether another set contains this set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() > w_other_as_set.length(): + return space.w_False + return space.wrap(self.issubset(w_other_as_set)) + + def descr_issuperset(self, space, w_other): + """Report whether this set contains another set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() < w_other_as_set.length(): + return space.w_False + return space.wrap(w_other_as_set.issubset(self)) + + def descr_symmetric_difference(self, space, w_other): + """Return the symmetric difference of two sets as a new set. + + (i.e. all elements that are in exactly one of the sets.)""" + + if isinstance(w_other, W_BaseSetObject): + return self.symmetric_difference(w_other) + + w_other_as_set = self._newobj(space, w_other) + return self.symmetric_difference(w_other_as_set) + + @gateway.unwrap_spec(others_w='args_w') + def descr_union(self, space, others_w): + """Return a new set with elements from the set and all others.""" + result = self.copy_real() + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + result.update(w_other) + else: + for w_key in space.listview(w_other): + result.add(w_key) + return result + + def descr_reduce(self, space): + """Return state information for pickling.""" + return setreduce(space, self) + + def descr_isdisjoint(self, space, w_other): + """Return True if two sets have a null intersection.""" + + if isinstance(w_other, W_BaseSetObject): + return space.newbool(self.isdisjoint(w_other)) + + #XXX may be optimized when other strategies are added + for w_key in space.listview(w_other): + if self.has_key(w_key): + return space.w_False + return space.w_True + + def descr_add(self, space, w_other): + """Add an element to a set. + + This has no effect if the element is already present.""" + self.add(w_other) + + def descr_clear(self, space): + """Remove all elements from this set.""" + self.clear() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference_update(self, space, others_w): + """Update the set, removing elements found in others.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.difference_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + self.difference_update(w_other_as_set) + + def _discard_from_set(self, space, w_item): + """ + Discard an element from a set, with automatic conversion to + frozenset if the argument is a set. + Returns True if successfully removed. + """ + try: + deleted = self.remove(w_item) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + else: + w_f = _convert_set_to_frozenset(space, w_item) + if w_f is None: + raise + deleted = self.remove(w_f) + + if self.length() == 0: + self.switch_to_empty_strategy() + return deleted + + def descr_discard(self, space, w_item): + """Remove an element from a set if it is a member. + + If the element is not a member, do nothing.""" + self._discard_from_set(space, w_item) + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection_update(self, space, others_w): + """Update the set, keeping only elements found in it and all others.""" + result = self.descr_intersection(space, others_w) + self.strategy = result.strategy + self.sstorage = result.sstorage + + def descr_pop(self, space): + """Remove and return an arbitrary set element.""" + return self.popitem() + + def descr_remove(self, space, w_item): + """Remove an element from a set; it must be a member. + + If the element is not a member, raise a KeyError.""" + if not self._discard_from_set(space, w_item): + space.raise_key_error(w_item) + + def descr_symmetric_difference_update(self, space, w_other): + """Update a set with the symmetric difference of itself and another.""" + if isinstance(w_other, W_BaseSetObject): + self.symmetric_difference_update(w_other) + return + w_other_as_set = self._newobj(space, w_other) + self.symmetric_difference_update(w_other_as_set) + + @gateway.unwrap_spec(others_w='args_w') + def descr_update(self, space, others_w): + """Update a set with the union of itself and another.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.update(w_other) + else: + for w_key in space.listview(w_other): + self.add(w_key) + + class W_SetObject(W_BaseSetObject): - from pypy.objspace.std.settype import set_typedef as typedef - def _newobj(w_self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" if type(w_self) is W_SetObject: @@ -176,8 +510,71 @@ W_SetObject.__init__(w_obj, space, w_iterable) return w_obj + @staticmethod + def descr_new(space, w_settype, __args__): + w_obj = space.allocate_instance(W_SetObject, w_settype) + W_SetObject.__init__(w_obj, space) + return w_obj + +W_SetObject.typedef = StdTypeDef("set", + __doc__ = """set(iterable) --> set object + +Build an unordered collection.""", + __new__ = gateway.interp2app(W_SetObject.descr_new), + __init__ = gateway.interp2app(W_BaseSetObject.descr_init), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), + __hash__ = None, + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), + + # mutating operators + __isub__ = gateway.interp2app(W_BaseSetObject.descr_inplace_sub), + __iand__ = gateway.interp2app(W_BaseSetObject.descr_inplace_and), + __ior__ = gateway.interp2app(W_BaseSetObject.descr_inplace_or), + __ixor__ = gateway.interp2app(W_BaseSetObject.descr_inplace_xor), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint), + + # mutating methods + add = gateway.interp2app(W_BaseSetObject.descr_add), + clear = gateway.interp2app(W_BaseSetObject.descr_clear), + difference_update = gateway.interp2app(W_BaseSetObject.descr_difference_update), + discard = gateway.interp2app(W_BaseSetObject.descr_discard), + intersection_update = gateway.interp2app(W_BaseSetObject.descr_intersection_update), + pop = gateway.interp2app(W_BaseSetObject.descr_pop), + remove = gateway.interp2app(W_BaseSetObject.descr_remove), + symmetric_difference_update = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference_update), + update = gateway.interp2app(W_BaseSetObject.descr_update) + ) +set_typedef = W_SetObject.typedef + + class W_FrozensetObject(W_BaseSetObject): - from pypy.objspace.std.frozensettype import frozenset_typedef as typedef hash = 0 def _newobj(w_self, space, w_iterable): @@ -189,9 +586,77 @@ W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj -registerimplementation(W_BaseSetObject) -registerimplementation(W_SetObject) -registerimplementation(W_FrozensetObject) + @staticmethod + def descr_new2(space, w_frozensettype, w_iterable=None): + if (space.is_w(w_frozensettype, space.w_frozenset) and + w_iterable is not None and type(w_iterable) is W_FrozensetObject): + return w_iterable + w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) + W_FrozensetObject.__init__(w_obj, space, w_iterable) + return w_obj + + def descr_hash(self, space): + multi = r_uint(1822399083) + r_uint(1822399083) + 1 + if self.hash != 0: + return space.wrap(self.hash) + hash = r_uint(1927868237) + hash *= r_uint(self.length() + 1) + w_iterator = self.iter() + while True: + w_item = w_iterator.next_entry() + if w_item is None: + break + h = space.hash_w(w_item) + value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) + hash = hash ^ value + hash = hash * 69069 + 907133923 + if hash == 0: + hash = 590923713 + hash = intmask(hash) + self.hash = hash + + return space.wrap(hash) + +W_FrozensetObject.typedef = StdTypeDef("frozenset", + __doc__ = """frozenset(iterable) --> frozenset object + +Build an immutable unordered collection.""", + __new__ = gateway.interp2app(W_FrozensetObject.descr_new2), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), + __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint) + ) +frozenset_typedef = W_FrozensetObject.typedef + + class SetStrategy(object): def __init__(self, space): @@ -285,8 +750,8 @@ def popitem(self, w_set): raise NotImplementedError + class EmptySetStrategy(SetStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -377,6 +842,7 @@ raise OperationError(self.space.w_KeyError, self.space.wrap('pop from an empty set')) + class AbstractUnwrappedSetStrategy(object): _mixin_ = True @@ -432,7 +898,6 @@ w_set.add(w_key) def remove(self, w_set, w_item): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string d = self.unerase(w_set.sstorage) if not self.is_correct_type(w_item): #XXX check type of w_item and immediately return False in some cases @@ -464,7 +929,6 @@ return keys_w def has_key(self, w_set, w_key): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string if not self.is_correct_type(w_key): #XXX check type of w_item and immediately return False in some cases w_set.switch_to_object_strategy(self.space) @@ -718,6 +1182,7 @@ self.space.wrap('pop from an empty set')) return self.wrap(result[0]) + class StringSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) @@ -801,7 +1266,6 @@ return self.unerase(w_set.sstorage).keys() def is_correct_type(self, w_key): - from pypy.objspace.std.intobject import W_IntObject return type(w_key) is W_IntObject def may_contain_equal_elements(self, strategy): @@ -822,6 +1286,7 @@ def iter(self, w_set): return IntegerIteratorImplementation(self.space, self, w_set) + class ObjectSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) @@ -866,6 +1331,7 @@ break d_obj[w_item] = None + class IteratorImplementation(object): def __init__(self, space, strategy, implementation): self.space = space @@ -910,6 +1376,7 @@ return self.len - self.pos return 0 + class EmptyIteratorImplementation(IteratorImplementation): def next_entry(self): return None @@ -927,6 +1394,7 @@ else: return None + class UnicodeIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -939,6 +1407,7 @@ else: return None + class IntegerIteratorImplementation(IteratorImplementation): #XXX same implementation in dictmultiobject on dictstrategy-branch def __init__(self, space, strategy, w_set): @@ -953,6 +1422,7 @@ else: return None + class RDictIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -966,26 +1436,34 @@ else: return None -class W_SetIterObject(W_Object): - from pypy.objspace.std.settype import setiter_typedef as typedef - # XXX this class should be killed, and the various - # iterimplementations should be W_Objects directly. + +class W_SetIterObject(W_Root): def __init__(w_self, space, iterimplementation): w_self.space = space w_self.iterimplementation = iterimplementation -registerimplementation(W_SetIterObject) + def descr_length_hint(self, space): + return space.wrap(self.iterimplementation.length()) -def iter__SetIterObject(space, w_setiter): - return w_setiter + def descr_iter(self, space): + return self -def next__SetIterObject(space, w_setiter): - iterimplementation = w_setiter.iterimplementation - w_key = iterimplementation.next() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) + def descr_next(self, space): + iterimplementation = self.iterimplementation + w_key = iterimplementation.next() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) + +W_SetIterObject.typedef = StdTypeDef("setiterator", + __length_hint__ = gateway.interp2app(W_SetIterObject.descr_length_hint), + __iter__ = gateway.interp2app(W_SetIterObject.descr_iter), + next = gateway.interp2app(W_SetIterObject.descr_next) + ) +setiter_typedef = W_SetIterObject.typedef + + # some helper functions @@ -993,7 +1471,6 @@ return r_dict(space.eq_w, space.hash_w, force_non_null=True) def set_strategy_and_setdata(space, w_set, w_iterable): - from pypy.objspace.std.intobject import W_IntObject if w_iterable is None : w_set.strategy = strategy = space.fromcache(EmptySetStrategy) w_set.sstorage = strategy.get_empty_storage() @@ -1067,6 +1544,8 @@ w_set.strategy = space.fromcache(ObjectSetStrategy) w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w) +init_signature = Signature(['some_iterable'], None, None) +init_defaults = [None] def _initialize_set(space, w_obj, w_iterable=None): w_obj.clear() set_strategy_and_setdata(space, w_obj, w_iterable) @@ -1084,424 +1563,6 @@ else: return None -def set_update__Set(space, w_left, others_w): - """Update a set with the union of itself and another.""" - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - w_left.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - w_left.add(w_key) - -def inplace_or__Set_Set(space, w_left, w_other): - w_left.update(w_other) - return w_left - -inplace_or__Set_Frozenset = inplace_or__Set_Set - -def set_add__Set_ANY(space, w_left, w_other): - """Add an element to a set. - - This has no effect if the element is already present. - """ - w_left.add(w_other) - -def set_copy__Set(space, w_set): - return w_set.copy_real() - -def frozenset_copy__Frozenset(space, w_left): - if type(w_left) is W_FrozensetObject: - return w_left - else: - return set_copy__Set(space, w_left) - -def set_clear__Set(space, w_left): - w_left.clear() - -def sub__Set_Set(space, w_left, w_other): - return w_left.difference(w_other) - -sub__Set_Frozenset = sub__Set_Set -sub__Frozenset_Set = sub__Set_Set -sub__Frozenset_Frozenset = sub__Set_Set - -def set_difference__Set(space, w_left, others_w): - result = w_left.copy_real() - set_difference_update__Set(space, result, others_w) - return result - -frozenset_difference__Frozenset = set_difference__Set - - -def set_difference_update__Set(space, w_left, others_w): - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - # optimization only - w_left.difference_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - w_left.difference_update(w_other_as_set) - -def inplace_sub__Set_Set(space, w_left, w_other): - w_left.difference_update(w_other) - return w_left - -inplace_sub__Set_Frozenset = inplace_sub__Set_Set - -def eq__Set_Set(space, w_left, w_other): - # optimization only (the general case is eq__Set_settypedef) - return space.wrap(w_left.equals(w_other)) - -eq__Set_Frozenset = eq__Set_Set -eq__Frozenset_Frozenset = eq__Set_Set -eq__Frozenset_Set = eq__Set_Set - -def eq__Set_settypedef(space, w_left, w_other): - # tested in test_buildinshortcut.py - #XXX do not make new setobject here - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(w_left.equals(w_other_as_set)) - -eq__Set_frozensettypedef = eq__Set_settypedef -eq__Frozenset_settypedef = eq__Set_settypedef -eq__Frozenset_frozensettypedef = eq__Set_settypedef - -def eq__Set_ANY(space, w_left, w_other): - # workaround to have "set() == 42" return False instead of falling - # back to cmp(set(), 42) because the latter raises a TypeError - return space.w_False - -eq__Frozenset_ANY = eq__Set_ANY - -def ne__Set_Set(space, w_left, w_other): - return space.wrap(not w_left.equals(w_other)) - -ne__Set_Frozenset = ne__Set_Set -ne__Frozenset_Frozenset = ne__Set_Set -ne__Frozenset_Set = ne__Set_Set - -def ne__Set_settypedef(space, w_left, w_other): - #XXX this is not tested - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(not w_left.equals(w_other_as_set)) - -ne__Set_frozensettypedef = ne__Set_settypedef -ne__Frozenset_settypedef = ne__Set_settypedef -ne__Frozenset_frozensettypedef = ne__Set_settypedef - - -def ne__Set_ANY(space, w_left, w_other): - # more workarounds - return space.w_True - -ne__Frozenset_ANY = ne__Set_ANY - -def contains__Set_ANY(space, w_left, w_other): - try: - return space.newbool(w_left.has_key(w_other)) - except OperationError, e: - if e.match(space, space.w_TypeError): - w_f = _convert_set_to_frozenset(space, w_other) - if w_f is not None: - return space.newbool(w_left.has_key(w_f)) - raise - -contains__Frozenset_ANY = contains__Set_ANY - -def set_issubset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() > w_other.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other)) - -set_issubset__Set_Frozenset = set_issubset__Set_Set -frozenset_issubset__Frozenset_Set = set_issubset__Set_Set -frozenset_issubset__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issubset__Set_ANY(space, w_left, w_other): - # not checking whether w_left is w_other here, because if that were the - # case the more precise multimethod would have applied. - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() > w_other_as_set.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other_as_set)) - -frozenset_issubset__Frozenset_ANY = set_issubset__Set_ANY - -le__Set_Set = set_issubset__Set_Set -le__Set_Frozenset = set_issubset__Set_Set -le__Frozenset_Set = set_issubset__Set_Set -le__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issuperset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() < w_other.length(): - return space.w_False - return space.wrap(w_other.issubset(w_left)) - -set_issuperset__Set_Frozenset = set_issuperset__Set_Set -set_issuperset__Frozenset_Set = set_issuperset__Set_Set -set_issuperset__Frozenset_Frozenset = set_issuperset__Set_Set - -def set_issuperset__Set_ANY(space, w_left, w_other): - if space.is_w(w_left, w_other): - return space.w_True - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() < w_other_as_set.length(): - return space.w_False - return space.wrap(w_other_as_set.issubset(w_left)) - -frozenset_issuperset__Frozenset_ANY = set_issuperset__Set_ANY - -ge__Set_Set = set_issuperset__Set_Set -ge__Set_Frozenset = set_issuperset__Set_Set -ge__Frozenset_Set = set_issuperset__Set_Set -ge__Frozenset_Frozenset = set_issuperset__Set_Set - -# automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the -# correct answer here! -def lt__Set_Set(space, w_left, w_other): - if w_left.length() >= w_other.length(): - return space.w_False - else: - return le__Set_Set(space, w_left, w_other) - -lt__Set_Frozenset = lt__Set_Set -lt__Frozenset_Set = lt__Set_Set -lt__Frozenset_Frozenset = lt__Set_Set - -def gt__Set_Set(space, w_left, w_other): - if w_left.length() <= w_other.length(): - return space.w_False - else: - return ge__Set_Set(space, w_left, w_other) - -gt__Set_Frozenset = gt__Set_Set -gt__Frozenset_Set = gt__Set_Set -gt__Frozenset_Frozenset = gt__Set_Set - -def _discard_from_set(space, w_left, w_item): - """ - Discard an element from a set, with automatic conversion to - frozenset if the argument is a set. - Returns True if successfully removed. - """ - try: - deleted = w_left.remove(w_item) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - else: - w_f = _convert_set_to_frozenset(space, w_item) - if w_f is None: - raise - deleted = w_left.remove(w_f) - - if w_left.length() == 0: - w_left.switch_to_empty_strategy() - return deleted - -def set_discard__Set_ANY(space, w_left, w_item): - _discard_from_set(space, w_left, w_item) - -def set_remove__Set_ANY(space, w_left, w_item): - if not _discard_from_set(space, w_left, w_item): - space.raise_key_error(w_item) - -def hash__Frozenset(space, w_set): - multi = r_uint(1822399083) + r_uint(1822399083) + 1 - if w_set.hash != 0: - return space.wrap(w_set.hash) - hash = r_uint(1927868237) - hash *= r_uint(w_set.length() + 1) - w_iterator = w_set.iter() - while True: - w_item = w_iterator.next_entry() - if w_item is None: - break - h = space.hash_w(w_item) - value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) - hash = hash ^ value - hash = hash * 69069 + 907133923 - if hash == 0: - hash = 590923713 - hash = intmask(hash) - w_set.hash = hash - - return space.wrap(hash) - -def set_pop__Set(space, w_left): - return w_left.popitem() - -def and__Set_Set(space, w_left, w_other): - new_set = w_left.intersect(w_other) - return new_set - -and__Set_Frozenset = and__Set_Set -and__Frozenset_Set = and__Set_Set -and__Frozenset_Frozenset = and__Set_Set - -def set_intersection__Set(space, w_left, others_w): - #XXX find smarter implementations - others_w = [w_left] + others_w - - # find smallest set in others_w to reduce comparisons - startindex, startlength = 0, -1 - for i in range(len(others_w)): - w_other = others_w[i] - try: - length = space.int_w(space.len(w_other)) - except OperationError, e: - if (e.match(space, space.w_TypeError) or - e.match(space, space.w_AttributeError)): - continue - raise - - if startlength == -1 or length < startlength: - startindex = i - startlength = length - - others_w[startindex], others_w[0] = others_w[0], others_w[startindex] - - result = w_left._newobj(space, others_w[0]) - for i in range(1,len(others_w)): - w_other = others_w[i] - if isinstance(w_other, W_BaseSetObject): - # optimization only - result.intersect_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - result.intersect_update(w_other_as_set) - return result - -frozenset_intersection__Frozenset = set_intersection__Set - -def set_intersection_update__Set(space, w_left, others_w): - result = set_intersection__Set(space, w_left, others_w) - w_left.strategy = result.strategy - w_left.sstorage = result.sstorage - return - -def inplace_and__Set_Set(space, w_left, w_other): - w_left.intersect_update(w_other) - return w_left - -inplace_and__Set_Frozenset = inplace_and__Set_Set - -def set_isdisjoint__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - return space.newbool(w_left.isdisjoint(w_other)) - -set_isdisjoint__Set_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Set = set_isdisjoint__Set_Set - -def set_isdisjoint__Set_ANY(space, w_left, w_other): - #XXX may be optimized when other strategies are added - for w_key in space.listview(w_other): - if w_left.has_key(w_key): - return space.w_False - return space.w_True - -frozenset_isdisjoint__Frozenset_ANY = set_isdisjoint__Set_ANY - -def set_symmetric_difference__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_result = w_left.symmetric_difference(w_other) - return w_result - -set_symmetric_difference__Set_Frozenset = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Set = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Frozenset = \ - set_symmetric_difference__Set_Set - -xor__Set_Set = set_symmetric_difference__Set_Set -xor__Set_Frozenset = set_symmetric_difference__Set_Set -xor__Frozenset_Set = set_symmetric_difference__Set_Set -xor__Frozenset_Frozenset = set_symmetric_difference__Set_Set - - -def set_symmetric_difference__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_result = w_left.symmetric_difference(w_other_as_set) - return w_result - -frozenset_symmetric_difference__Frozenset_ANY = \ - set_symmetric_difference__Set_ANY - -def set_symmetric_difference_update__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_left.symmetric_difference_update(w_other) - -set_symmetric_difference_update__Set_Frozenset = \ - set_symmetric_difference_update__Set_Set - -def set_symmetric_difference_update__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_left.symmetric_difference_update(w_other_as_set) - -def inplace_xor__Set_Set(space, w_left, w_other): - set_symmetric_difference_update__Set_Set(space, w_left, w_other) - return w_left - -inplace_xor__Set_Frozenset = inplace_xor__Set_Set - -def or__Set_Set(space, w_left, w_other): - w_copy = w_left.copy_real() - w_copy.update(w_other) - return w_copy - -or__Set_Frozenset = or__Set_Set -or__Frozenset_Set = or__Set_Set -or__Frozenset_Frozenset = or__Set_Set - -def set_union__Set(space, w_left, others_w): - result = w_left.copy_real() - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - result.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - result.add(w_key) - return result - -frozenset_union__Frozenset = set_union__Set - -def len__Set(space, w_left): - return space.newint(w_left.length()) - -len__Frozenset = len__Set - -def iter__Set(space, w_left): - return W_SetIterObject(space, w_left.iter()) - -iter__Frozenset = iter__Set - -def cmp__Set_settypedef(space, w_left, w_other): - # hack hack until we get the expected result - raise OperationError(space.w_TypeError, - space.wrap('cannot compare sets using cmp()')) - -cmp__Set_frozensettypedef = cmp__Set_settypedef -cmp__Frozenset_settypedef = cmp__Set_settypedef -cmp__Frozenset_frozensettypedef = cmp__Set_settypedef - -init_signature = Signature(['some_iterable'], None, None) -init_defaults = [None] -def init__Set(space, w_set, __args__): - w_iterable, = __args__.parse_obj( - None, 'set', - init_signature, - init_defaults) - _initialize_set(space, w_set, w_iterable) app = gateway.applevel(""" def setrepr(currently_in_repr, s): @@ -1521,26 +1582,11 @@ setrepr = app.interphook("setrepr") -def repr__Set(space, w_set): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return setrepr(space, w_currently_in_repr, w_set) - -repr__Frozenset = repr__Set - app = gateway.applevel(""" - def reduce__Set(s): + def setreduce(s): dict = getattr(s,'__dict__', None) return (s.__class__, (tuple(s),), dict) """, filename=__file__) -set_reduce__Set = app.interphook('reduce__Set') -frozenset_reduce__Frozenset = app.interphook('reduce__Set') - -from pypy.objspace.std import frozensettype -from pypy.objspace.std import settype - -register_all(vars(), settype, frozensettype) +setreduce = app.interphook('setreduce') diff --git a/pypy/objspace/std/settype.py b/pypy/objspace/std/settype.py deleted file mode 100644 --- a/pypy/objspace/std/settype.py +++ /dev/null @@ -1,91 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -set_add = SMM('add', 2, - doc='Add an element to a set.\n\nThis' - ' has no effect if the element is' - ' already present.') -set_clear = SMM('clear', 1, - doc='Remove all elements from this set.') -set_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -set_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -set_difference_update = SMM('difference_update', 1, varargs_w=True, - doc='Update the set, removing elements' - ' found in others.') -set_discard = SMM('discard', 2, - doc='Remove an element from a set if it' - ' is a member.\n\nIf the element is' - ' not a member, do nothing.') -set_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -set_intersection_update = SMM('intersection_update', 1, varargs_w=True, - doc='Update the set, keeping only elements' - ' found in it and all others.') -set_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -set_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -set_pop = SMM('pop', 1, - doc='Remove and return an arbitrary set' - ' element.') -set_remove = SMM('remove', 2, - doc='Remove an element from a set; it' - ' must be a member.\n\nIf the' - ' element is not a member, raise a' - ' KeyError.') -set_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -set_symmetric_difference_update = SMM('symmetric_difference_update', 2, - doc='Update a set with the symmetric' - ' difference of itself and another.') -set_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -set_update = SMM('update', 1, varargs_w=True, - doc='Update the set, adding elements' - ' from all others.') -set_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -set_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__new__(space, w_settype, __args__): - from pypy.objspace.std.setobject import W_SetObject, newset - w_obj = space.allocate_instance(W_SetObject, w_settype) - W_SetObject.__init__(w_obj, space) - return w_obj - -set_typedef = StdTypeDef("set", - __doc__ = """set(iterable) --> set object - -Build an unordered collection.""", - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - ) - -set_typedef.registermethods(globals()) - -def descr_setiterator__length_hint__(space, w_self): - from pypy.objspace.std.setobject import W_SetIterObject - assert isinstance(w_self, W_SetIterObject) - return space.wrap(w_self.iterimplementation.length()) - -setiter_typedef = StdTypeDef("setiterator", - __length_hint__ = gateway.interp2app(descr_setiterator__length_hint__), - ) diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -12,9 +12,6 @@ from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject, IntegerSetStrategy from pypy.objspace.std.setobject import _initialize_set from pypy.objspace.std.setobject import newset -from pypy.objspace.std.setobject import and__Set_Set -from pypy.objspace.std.setobject import set_intersection__Set -from pypy.objspace.std.setobject import eq__Set_Set from pypy.objspace.std.listobject import W_ListObject letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -36,11 +33,11 @@ t0 = W_SetObject(self.space) _initialize_set(self.space, t0, self.otherword) t1 = W_FrozensetObject(self.space, self.otherword) - r0 = and__Set_Set(self.space, s, t0) - r1 = and__Set_Set(self.space, s, t1) - assert eq__Set_Set(self.space, r0, r1) == self.true - sr = set_intersection__Set(self.space, s, [self.otherword]) - assert eq__Set_Set(self.space, r0, sr) == self.true + r0 = s.descr_and(self.space, t0) + r1 = s.descr_and(self.space, t1) + assert r0.descr_eq(self.space, r1) == self.true + sr = s.descr_intersection(self.space, [self.otherword]) + assert r0.descr_eq(self.space, sr) == self.true def test_compare(self): s = W_SetObject(self.space) @@ -66,7 +63,7 @@ b = W_SetObject(self.space) _initialize_set(self.space, b, self.space.wrap("abc")) - result = set_intersection__Set(space, a, [b]) + result = a.descr_intersection(space, [b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("abc")))) c = W_SetObject(self.space) @@ -80,7 +77,7 @@ b.get_storage_copy = None d.get_storage_copy = None - result = set_intersection__Set(space, a, [d,c,b]) + result = a.descr_intersection(space, [d,c,b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("")))) def test_create_set_from_list(self): diff --git a/pypy/objspace/std/test/test_setstrategies.py b/pypy/objspace/std/test/test_setstrategies.py --- a/pypy/objspace/std/test/test_setstrategies.py +++ b/pypy/objspace/std/test/test_setstrategies.py @@ -65,18 +65,16 @@ assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_remove(self): - from pypy.objspace.std.setobject import set_remove__Set_ANY s1 = W_SetObject(self.space, self.wrapped([1])) - set_remove__Set_ANY(self.space, s1, self.space.wrap(1)) + self.space.call_method(s1, 'remove', self.space.wrap(1)) assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_union(self): - from pypy.objspace.std.setobject import set_union__Set s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) s2 = W_SetObject(self.space, self.wrapped([4,5,6,7])) s3 = W_SetObject(self.space, self.wrapped([4,'5','6',7])) - s4 = set_union__Set(self.space, s1, [s2]) - s5 = set_union__Set(self.space, s1, [s3]) + s4 = s1.descr_union(self.space, [s2]) + s5 = s1.descr_union(self.space, [s3]) assert s4.strategy is self.space.fromcache(IntegerSetStrategy) assert s5.strategy is self.space.fromcache(ObjectSetStrategy) @@ -91,10 +89,8 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) - set_discard__Set_ANY(self.space, s1, self.space.wrap("five")) + s1.descr_discard(self.space, self.space.wrap("five")) skip("currently not supported") assert s1.strategy is self.space.fromcache(IntegerSetStrategy) @@ -112,8 +108,6 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) assert not s1.has_key(self.space.wrap("five")) skip("currently not supported") From noreply at buildbot.pypy.org Wed May 15 20:26:16 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 15 May 2013 20:26:16 +0200 (CEST) Subject: [pypy-commit] pypy default: minor cleanup Message-ID: <20130515182616.502AC1C02E4@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64194:59479d0d1685 Date: 2013-05-15 11:16 -0700 http://bitbucket.org/pypy/pypy/changeset/59479d0d1685/ Log: minor cleanup diff --git a/pypy/module/sys/system.py b/pypy/module/sys/system.py --- a/pypy/module/sys/system.py +++ b/pypy/module/sys/system.py @@ -1,6 +1,6 @@ """Information about the current system.""" from pypy.interpreter import gateway -from rpython.rlib import rfloat, rbigint +from rpython.rlib import rbigint, rfloat from rpython.rtyper.lltypesystem import rffi @@ -47,7 +47,6 @@ return space.call_function(w_float_info, space.newtuple(info_w)) def get_long_info(space): - #assert rbigint.SHIFT == 31 bits_per_digit = rbigint.SHIFT sizeof_digit = rffi.sizeof(rbigint.STORE_TYPE) info_w = [ @@ -58,7 +57,4 @@ return space.call_function(w_long_info, space.newtuple(info_w)) def get_float_repr_style(space): - if rfloat.USE_SHORT_FLOAT_REPR: - return space.wrap("short") - else: - return space.wrap("legacy") + return space.wrap("short" if rfloat.USE_SHORT_FLOAT_REPR else "legacy") From noreply at buildbot.pypy.org Wed May 15 20:27:20 2013 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 15 May 2013 20:27:20 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: fix ztranslation - one fix and lots of asserts Message-ID: <20130515182720.C11B71C02E4@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r64195:d48e9c0866a0 Date: 2013-05-15 21:19 +0300 http://bitbucket.org/pypy/pypy/changeset/d48e9c0866a0/ Log: fix ztranslation - one fix and lots of asserts diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -69,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -12,6 +12,7 @@ from pypy.module.micronumpy.iter import PureShapeIterator from pypy.module.micronumpy import constants from pypy.module.micronumpy.support import int_w +from pypy.module.micronumpy.interp_boxes import W_GenericBox call2_driver = jit.JitDriver(name='numpy_call2', greens = ['shapelen', 'func', 'calc_dtype', @@ -33,8 +34,12 @@ out=out, left_iter=left_iter, right_iter=right_iter, out_iter=out_iter) - w_left = left_iter.getitem().convert_to(calc_dtype) - w_right = right_iter.getitem().convert_to(calc_dtype) + item_l = left_iter.getitem() + item_r = right_iter.getitem() + assert isinstance(item_l, W_GenericBox) + assert isinstance(item_r, W_GenericBox) + w_left = item_l.convert_to(calc_dtype) + w_right = item_r.convert_to(calc_dtype) out_iter.setitem(func(calc_dtype, w_left, w_right).convert_to( res_dtype)) left_iter.next() @@ -59,7 +64,9 @@ calc_dtype=calc_dtype, res_dtype=res_dtype, shape=shape, w_obj=w_obj, out=out, obj_iter=obj_iter, out_iter=out_iter) - elem = obj_iter.getitem().convert_to(calc_dtype) + item = obj_iter.getitem() + assert isinstance(item, W_GenericBox) + elem = item.convert_to(calc_dtype) out_iter.setitem(func(calc_dtype, elem).convert_to(res_dtype)) out_iter.next() obj_iter.next() @@ -86,7 +93,9 @@ shapelen = len(shape) while not target_iter.done(): setslice_driver1.jit_merge_point(shapelen=shapelen, dtype=dtype) - target_iter.setitem(source_iter.getitem().convert_to(dtype)) + item = source_iter.getitem() + assert isinstance(item, W_GenericBox) + target_iter.setitem(item.convert_to(dtype)) target_iter.next() source_iter.next() return target @@ -100,7 +109,9 @@ shapelen = len(shape) while not target_iter.done(): setslice_driver2.jit_merge_point(shapelen=shapelen, dtype=dtype) - target_iter.setitem(dtype.build_and_convert(space, source_iter.getitem())) + item = source_iter.getitem() + assert isinstance(item, W_GenericBox) + target_iter.setitem(dtype.build_and_convert(space, item)) target_iter.next() source_iter.next() return target @@ -113,7 +124,9 @@ def compute_reduce(obj, calc_dtype, func, done_func, identity): obj_iter = obj.create_iter() if identity is None: - cur_value = obj_iter.getitem().convert_to(calc_dtype) + item = obj_iter.getitem() + assert isinstance(item, W_GenericBox) + cur_value = item.convert_to(calc_dtype) obj_iter.next() else: cur_value = identity.convert_to(calc_dtype) @@ -123,7 +136,9 @@ done_func=done_func, calc_dtype=calc_dtype, identity=identity, ) - rval = obj_iter.getitem().convert_to(calc_dtype) + item = obj_iter.getitem() + assert isinstance(item, W_GenericBox) + rval = item.convert_to(calc_dtype) if done_func is not None and done_func(calc_dtype, rval): return rval cur_value = func(calc_dtype, cur_value, rval) @@ -142,7 +157,9 @@ reduce_cum_driver.jit_merge_point(shapelen=shapelen, func=func, dtype=calc_dtype, ) - rval = obj_iter.getitem().convert_to(calc_dtype) + item = obj_iter.getitem() + assert isinstance(item, W_GenericBox) + rval = item.convert_to(calc_dtype) cur_value = func(calc_dtype, cur_value, rval) out_iter.setitem(cur_value) out_iter.next() @@ -173,13 +190,16 @@ iter = x_iter shapelen = len(shape) while not iter.done(): - where_driver.jit_merge_point(shapelen=shapelen, dtype=dtype, + where_driver.jit_merge_point(shapelen=shapelen, dtype=dtype, arr_dtype=arr_dtype) w_cond = arr_iter.getitem() + assert isinstance(w_cond, W_GenericBox) if arr_dtype.itemtype.bool(w_cond): - w_val = x_iter.getitem().convert_to(dtype) + item = x_iter.getitem() else: - w_val = y_iter.getitem().convert_to(dtype) + item = y_iter.getitem() + assert isinstance(item, W_GenericBox) + w_val = item.convert_to(dtype) out_iter.setitem(w_val) out_iter.next() arr_iter.next() @@ -188,7 +208,7 @@ return out axis_reduce__driver = jit.JitDriver(name='numpy_axis_reduce', - greens=['shapelen', + greens=['shapelen', 'func', 'dtype', 'identity'], reds='auto') @@ -208,12 +228,15 @@ axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func, dtype=dtype, identity=identity, ) - w_val = arr_iter.getitem().convert_to(dtype) + item = arr_iter.getitem() + assert isinstance(item, W_GenericBox) + w_val = item.convert_to(dtype) if out_iter.first_line: if identity is not None: w_val = func(dtype, identity, w_val) else: cur = temp_iter.getitem() + assert isinstance(cur, W_GenericBox) w_val = func(dtype, cur, w_val) out_iter.setitem(w_val) if cumultative: @@ -228,19 +251,21 @@ arg_driver = jit.JitDriver(name='numpy_' + op_name, greens = ['shapelen', 'dtype'], reds = 'auto') - + def argmin_argmax(arr): result = 0 idx = 1 dtype = arr.get_dtype() iter = arr.create_iter() cur_best = iter.getitem() + assert isinstance(cur_best, W_GenericBox) iter.next() shapelen = len(arr.get_shape()) while not iter.done(): arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype, ) w_val = iter.getitem() + assert isinstance(w_val, W_GenericBox) new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) if dtype.itemtype.ne(new_best, cur_best): result = idx @@ -265,7 +290,7 @@ result.shape == [3, 5, 2, 4] broadcast shape should be [3, 5, 2, 7, 4] result should skip dims 3 which is len(result_shape) - 1 - (note that if right is 1d, result should + (note that if right is 1d, result should skip len(result_shape)) left should skip 2, 4 which is a.ndims-1 + range(right.ndims) except where it==(right.ndims-2) @@ -283,9 +308,13 @@ righti = right.create_dot_iter(broadcast_shape, right_skip) while not outi.done(): dot_driver.jit_merge_point(dtype=dtype) - lval = lefti.getitem().convert_to(dtype) - rval = righti.getitem().convert_to(dtype) - outval = outi.getitem().convert_to(dtype) + litem = lefti.getitem() + ritem = righti.getitem() + oitem = outi.getitem() + assert isinstance(litem, W_GenericBox) and isinstance(ritem, W_GenericBox) and isinstance(oitem, W_GenericBox) + lval = litem.convert_to(dtype) + rval = ritem.convert_to(dtype) + outval = oitem.convert_to(dtype) v = dtype.itemtype.mul(lval, rval) value = dtype.itemtype.add(v, outval).convert_to(dtype) outi.setitem(value) @@ -355,7 +384,7 @@ setitem_filter_driver.jit_merge_point(shapelen=shapelen, index_dtype=index_dtype, arr_dtype=arr_dtype, - ) + ) if index_iter.getitem_bool(): arr_iter.setitem(value_iter.getitem()) value_iter.next() @@ -397,7 +426,9 @@ arr_iter.next_skip_x(start) while length > 0: flatiter_setitem_driver1.jit_merge_point(dtype=dtype) - arr_iter.setitem(val_iter.getitem().convert_to(dtype)) + item = val_iter.getitem() + assert isinstance(item, W_GenericBox) + arr_iter.setitem(item.convert_to(dtype)) # need to repeat i_nput values until all assignments are done arr_iter.next_skip_x(step) length -= 1 @@ -541,7 +572,9 @@ index = 0 else: index = len(iterators) - 1 - out_iter.setitem(iterators[index].getitem().convert_to(dtype)) + item = iterators[index].getitem() + assert isinstance(item, W_GenericBox) + out_iter.setitem(item.convert_to(dtype)) for iter in iterators: iter.next() out_iter.next() @@ -559,9 +592,13 @@ out_iter = out.create_iter(shape) while not arr_iter.done(): clip_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) - w_v = arr_iter.getitem().convert_to(dtype) - w_min = min_iter.getitem().convert_to(dtype) - w_max = max_iter.getitem().convert_to(dtype) + i_arr = arr_iter.getitem() + i_min = min_iter.getitem() + i_max = max_iter.getitem() + assert isinstance(i_arr, W_GenericBox) and isinstance(i_min, W_GenericBox) and isinstance(i_max, W_GenericBox) + w_v = i_arr.convert_to(dtype) + w_min = i_min.convert_to(dtype) + w_max = i_max.convert_to(dtype) if dtype.itemtype.lt(w_v, w_min): w_v = w_min elif dtype.itemtype.gt(w_v, w_max): @@ -613,4 +650,4 @@ out_iter.setitem(arr.getitem_index(space, indexes)) iter.next() out_iter.next() - + diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1686,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1725,7 +1726,8 @@ if dtype is None: dtype = arr.dtype strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) - implementation = SliceArray(i + offset, strides, backstrides, dtype.shape, arr, arr, dtype.subdtype) + implementation = SliceArray(i + offset, strides, backstrides, + dtype.shape, arr, W_NDimArray(arr), dtype.subdtype) return W_NDimArray(implementation) NonNativeVoidType = VoidType From noreply at buildbot.pypy.org Wed May 15 20:27:22 2013 From: noreply at buildbot.pypy.org (mattip) Date: Wed, 15 May 2013 20:27:22 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: merge heads Message-ID: <20130515182722.054231C02E4@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r64196:588ab90bac6c Date: 2013-05-15 21:20 +0300 http://bitbucket.org/pypy/pypy/changeset/588ab90bac6c/ Log: merge heads From noreply at buildbot.pypy.org Wed May 15 20:28:14 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 15 May 2013 20:28:14 +0200 (CEST) Subject: [pypy-commit] pypy py3k: avoid the deprecated method Message-ID: <20130515182814.5B3D91C02E4@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64197:8550ff66dd79 Date: 2013-05-15 11:17 -0700 http://bitbucket.org/pypy/pypy/changeset/8550ff66dd79/ Log: avoid the deprecated method 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 @@ -38,8 +38,8 @@ if isinstance(w_initializer, W_ArrayBase): a.extend(w_initializer, True) else: - a.descr_fromstring(space, - space.bufferstr_w(w_initializer)) + a.descr_frombytes(space, + space.bufferstr_w(w_initializer)) elif space.type(w_initializer) is space.w_list: a.descr_fromlist(space, w_initializer) else: From noreply at buildbot.pypy.org Wed May 15 20:31:21 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 20:31:21 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changed the stack-pointer from beeing tempsize-based to being 0 based (relative to _temps_and_stack-array) to the world Message-ID: <20130515183122.00EC81C1306@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r392:b1bce04a7d50 Date: 2013-05-15 18:28 +0000 http://bitbucket.org/pypy/lang-smalltalk/changeset/b1bce04a7d50/ Log: changed the stack-pointer from beeing tempsize-based to being 0 based (relative to _temps_and_stack-array) to the world diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -493,8 +493,7 @@ # the stackpointer in the W_PointersObject starts counting at the # tempframe start # Stackpointer from smalltalk world == stacksize in python world - self.store_stackpointer(self.space.unwrap_int(w_sp1) - - self.tempsize()) + self.store_stackpointer(self.space.unwrap_int(w_sp1)) def store_stackpointer(self, size): depth = self.stackdepth() @@ -507,8 +506,7 @@ self.push(self.space.w_nil) def wrap_stackpointer(self): - return self.space.wrap_int(self.stackdepth() + - self.tempsize()) + return self.space.wrap_int(self.stackdepth()) def external_stackpointer(self): return self.stackdepth() + self.stackstart() @@ -669,7 +667,7 @@ self._temps_and_stack[self._stack_ptr] = None def stackdepth(self): - return rarithmetic.intmask(self._stack_ptr - self.tempsize()) + return rarithmetic.intmask(self._stack_ptr) @jit.unroll_safe def pop_and_return_n(self, n): @@ -941,8 +939,7 @@ return constants.MTHDCTX_TEMP_FRAME_START def stackstart(self): - return (constants.MTHDCTX_TEMP_FRAME_START + - self.tempsize()) + return (constants.MTHDCTX_TEMP_FRAME_START) def myblocksize(self): return self.size() - self.tempsize() From noreply at buildbot.pypy.org Wed May 15 20:31:23 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 15 May 2013 20:31:23 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: moved the s_method retrival in c_loop outside of the loop Message-ID: <20130515183123.1CB641C1306@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r393:293ebf9ed46a Date: 2013-05-15 18:28 +0000 http://bitbucket.org/pypy/lang-smalltalk/changeset/293ebf9ed46a/ Log: moved the s_method retrival in c_loop outside of the loop diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -89,9 +89,9 @@ old_pc = 0 if not jit.we_are_jitted() and may_context_switch: self.quick_check_for_interrupt(s_context) + method = s_context.s_method() while True: pc = s_context.pc() - method = s_context.s_method() if pc < old_pc: if jit.we_are_jitted(): self.quick_check_for_interrupt(s_context, From noreply at buildbot.pypy.org Wed May 15 21:14:45 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 21:14:45 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: hg merge default Message-ID: <20130515191445.BD9691C1106@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64198:ffb0292d1328 Date: 2013-05-15 19:40 +0200 http://bitbucket.org/pypy/pypy/changeset/ffb0292d1328/ Log: hg merge default diff too long, truncating to 2000 out of 2249 lines diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -1387,7 +1387,8 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if (encoding not in broken_incremental_coders and + hasattr(_testcapi, 'codec_incrementalencoder')): # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_descr.py b/lib-python/2.7/test/test_descr.py --- a/lib-python/2.7/test/test_descr.py +++ b/lib-python/2.7/test/test_descr.py @@ -2080,8 +2080,9 @@ except ImportError: pass else: - class X(object): - p = property(_testcapi.test_with_docstring) + if hasattr(_testcapi, 'test_with_docstring'): + class X(object): + p = property(_testcapi.test_with_docstring) def test_properties_plus(self): class C(object): diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print +try: + from _testcapi import traceback_print +except ImportError: + traceback_print = None from StringIO import StringIO import sys import unittest @@ -176,6 +179,8 @@ class TracebackFormatTests(unittest.TestCase): def test_traceback_format(self): + if traceback_print is None: + return try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1609,7 +1609,10 @@ self.assertEqual("{}".format(u), '__unicode__ overridden') def test_encode_decimal(self): - from _testcapi import unicode_encodedecimal + try: + from _testcapi import unicode_encodedecimal + except ImportError: + return self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -54,4 +54,9 @@ fp, filename, description = imp.find_module('_testcapi', path=[output_dir]) imp.load_module('_testcapi', fp, filename, description) -compile_shared() +try: + import cpyext +except ImportError: + pass +else: + compile_shared() 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 @@ -7,3 +7,12 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) + +.. branch: remove-array-smm +Remove multimethods in the arraymodule + +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback + +.. branch: remove-set-smm +Remove multi-methods on sets 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 @@ -100,11 +100,11 @@ return space.w_True if comp_op == LT or comp_op == LE: if arr1.len < arr2.len: - return space.w_False + return space.w_True + return space.w_False + if arr1.len > arr2.len: return space.w_True - if arr1.len > arr2.len: - return space.w_False - return space.w_True + return space.w_False UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True})) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -552,6 +552,15 @@ assert (a >= c) is False assert (c >= a) is True + a = self.array('i', [-1, 0, 1, 42, 0x7f]) + assert not a == 2*a + assert a != 2*a + assert a < 2*a + assert a <= 2*a + assert not a > 2*a + assert not a >= 2*a + + def test_reduce(self): import pickle a = self.array('i', [1, 2, 3]) diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -14,6 +14,7 @@ from pypy.module.micronumpy.interp_arrayops import where from pypy.module.micronumpy import interp_ufuncs from rpython.rlib.objectmodel import specialize, instantiate +from rpython.rlib.nonconst import NonConstant class BogusBytecode(Exception): @@ -40,6 +41,10 @@ TWO_ARG_FUNCTIONS = ["dot", 'take'] THREE_ARG_FUNCTIONS = ['where'] +class W_TypeObject(W_Root): + def __init__(self, name): + self.name = name + class FakeSpace(object): w_ValueError = "ValueError" w_TypeError = "TypeError" @@ -48,17 +53,17 @@ w_NotImplementedError = "NotImplementedError" w_None = None - w_bool = "bool" - w_int = "int" - w_float = "float" - w_list = "list" - w_long = "long" - w_tuple = 'tuple' - w_slice = "slice" - w_str = "str" - w_unicode = "unicode" - w_complex = "complex" - w_dict = "dict" + w_bool = W_TypeObject("bool") + w_int = W_TypeObject("int") + w_float = W_TypeObject("float") + w_list = W_TypeObject("list") + w_long = W_TypeObject("long") + w_tuple = W_TypeObject('tuple') + w_slice = W_TypeObject("slice") + w_str = W_TypeObject("str") + w_unicode = W_TypeObject("unicode") + w_complex = W_TypeObject("complex") + w_dict = W_TypeObject("dict") def __init__(self): """NOT_RPYTHON""" @@ -73,6 +78,13 @@ def issequence_w(self, w_obj): return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray) + def len(self, w_obj): + assert isinstance(w_obj, ListObject) + return self.wrap(len(w_obj.items)) + + def getattr(self, w_obj, w_attr): + return StringObject(NonConstant('foo')) + def isinstance_w(self, w_obj, w_tp): return w_obj.tp == w_tp diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py --- a/pypy/objspace/fake/checkmodule.py +++ b/pypy/objspace/fake/checkmodule.py @@ -5,6 +5,7 @@ def checkmodule(*modnames): config = get_pypy_config(translating=True) space = FakeObjSpace(config) + space.setup() seeobj_w = [] for modname in modnames: mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__']) diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -55,6 +55,10 @@ from rpython.rlib.rbigint import rbigint return rbigint.fromint(NonConstant(42)) +class W_MyListObj(W_MyObject): + def append(self, w_other): + pass + class W_MyType(W_MyObject): def __init__(self): self.mro_w = [w_some_obj(), w_some_obj()] @@ -107,6 +111,9 @@ self._seen_extras = [] ObjSpace.__init__(self, config=config) + def _freeze_(self): + return True + def float_w(self, w_obj): is_root(w_obj) return NonConstant(42.5) @@ -131,7 +138,7 @@ def newlist(self, list_w): for w_x in list_w: is_root(w_x) - return w_some_obj() + return W_MyListObj() def newslice(self, w_start, w_end, w_step): is_root(w_start) @@ -316,38 +323,36 @@ t.buildrtyper().specialize() t.checkgraphs() + def setup(space): + for name in (ObjSpace.ConstantTable + + ObjSpace.ExceptionTable + + ['int', 'str', 'float', 'long', 'tuple', 'list', + 'dict', 'unicode', 'complex', 'slice', 'bool', + 'basestring', 'object', 'bytearray']): + setattr(space, 'w_' + name, w_some_obj()) + space.w_type = w_some_type() + # + for (name, _, arity, _) in ObjSpace.MethodTable: + if name == 'type': + continue + args = ['w_%d' % i for i in range(arity)] + params = args[:] + d = {'is_root': is_root, + 'w_some_obj': w_some_obj} + if name in ('get',): + params[-1] += '=None' + exec compile2("""\ + def meth(%s): + %s + return w_some_obj() + """ % (', '.join(params), + '; '.join(['is_root(%s)' % arg for arg in args]))) in d + meth = func_with_new_name(d['meth'], name) + setattr(space, name, meth) + # + for name in ObjSpace.IrregularOpTable: + assert hasattr(space, name) # missing? -def setup(): - for name in (ObjSpace.ConstantTable + - ObjSpace.ExceptionTable + - ['int', 'str', 'float', 'long', 'tuple', 'list', - 'dict', 'unicode', 'complex', 'slice', 'bool', - 'basestring', 'object', 'bytearray']): - setattr(FakeObjSpace, 'w_' + name, w_some_obj()) - FakeObjSpace.w_type = w_some_type() - # - for (name, _, arity, _) in ObjSpace.MethodTable: - if name == 'type': - continue - args = ['w_%d' % i for i in range(arity)] - params = args[:] - d = {'is_root': is_root, - 'w_some_obj': w_some_obj} - if name in ('get',): - params[-1] += '=None' - exec compile2("""\ - def meth(self, %s): - %s - return w_some_obj() - """ % (', '.join(params), - '; '.join(['is_root(%s)' % arg for arg in args]))) in d - meth = func_with_new_name(d['meth'], name) - setattr(FakeObjSpace, name, meth) - # - for name in ObjSpace.IrregularOpTable: - assert hasattr(FakeObjSpace, name) # missing? - -setup() # ____________________________________________________________ diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,8 +1,8 @@ import py, sys from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef +from pypy.objspace.std.setobject import set_typedef as settypedef +from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.signature import Signature diff --git a/pypy/objspace/std/frozensettype.py b/pypy/objspace/std/frozensettype.py deleted file mode 100644 --- a/pypy/objspace/std/frozensettype.py +++ /dev/null @@ -1,55 +0,0 @@ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - - -frozenset_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -frozenset_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -frozenset_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -frozenset_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -frozenset_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -frozenset_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -frozenset_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -frozenset_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -frozenset_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__frozenset__new__(space, w_frozensettype, w_iterable=None): - from pypy.objspace.std.setobject import W_FrozensetObject - if (space.is_w(w_frozensettype, space.w_frozenset) and - w_iterable is not None and type(w_iterable) is W_FrozensetObject): - return w_iterable - w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) - W_FrozensetObject.__init__(w_obj, space, w_iterable) - return w_obj - -frozenset_typedef = StdTypeDef("frozenset", - __doc__ = """frozenset(iterable) --> frozenset object - -Build an immutable unordered collection.""", - __new__ = gateway.interp2app(descr__frozenset__new__), - ) - -frozenset_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -38,8 +38,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.settype import set_typedef - from pypy.objspace.std.frozensettype import frozenset_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.dicttype import dict_typedef @@ -63,10 +61,10 @@ from pypy.objspace.std import intobject from pypy.objspace.std import floatobject from pypy.objspace.std import complexobject - from pypy.objspace.std import setobject from pypy.objspace.std import tupleobject from pypy.objspace.std import listobject from pypy.objspace.std import dictmultiobject + from pypy.objspace.std import setobject from pypy.objspace.std import stringobject from pypy.objspace.std import bytearrayobject from pypy.objspace.std import typeobject @@ -81,6 +79,11 @@ import pypy.objspace.std.marshal_impl # install marshal multimethods + # not-multimethod based types + + self.pythontypes.append(setobject.W_SetObject.typedef) + self.pythontypes.append(setobject.W_FrozensetObject.typedef) + # the set of implementation types self.typeorder = { objectobject.W_ObjectObject: [], @@ -100,10 +103,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - setobject.W_BaseSetObject: [], - setobject.W_SetObject: [], - setobject.W_FrozensetObject: [], - setobject.W_SetIterObject: [], iterobject.W_SeqIterObject: [], iterobject.W_FastListIterObject: [], iterobject.W_FastTupleIterObject: [], @@ -192,12 +191,7 @@ (complexobject.W_ComplexObject, complexobject.delegate_Float2Complex), ] - self.typeorder[setobject.W_SetObject] += [ - (setobject.W_BaseSetObject, None) - ] - self.typeorder[setobject.W_FrozensetObject] += [ - (setobject.W_BaseSetObject, None) - ] + self.typeorder[stringobject.W_StringObject] += [ (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode), ] @@ -339,8 +333,9 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(w_self, space): - raise UnwrapError, 'cannot unwrap %r' % (w_self,) + def unwrap(self, space): + raise UnwrapError('cannot unwrap %r' % self) + class UnwrapError(Exception): pass @@ -405,7 +400,7 @@ mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree) return mm -NOT_MULTIMETHODS = dict.fromkeys( +NOT_MULTIMETHODS = set( ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv', 'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift', 'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel', diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -1,13 +1,9 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway -from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef from pypy.interpreter.signature import Signature -from pypy.interpreter.generator import GeneratorIterator -from pypy.objspace.std.listobject import W_ListObject +from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.unicodeobject import W_UnicodeObject @@ -15,20 +11,13 @@ from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit + UNROLL_CUTOFF = 5 -class W_BaseSetObject(W_Object): + +class W_BaseSetObject(W_Root): typedef = None - # make sure that Base is used for Set and Frozenset in multimethod - # declarations - @classmethod - def is_implementation_for(cls, typedef): - if typedef is frozensettypedef or typedef is settypedef: - assert cls is W_BaseSetObject - return True - return False - def __init__(w_self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" w_self.space = space @@ -66,7 +55,6 @@ # _____________ strategy methods ________________ - def clear(self): """ Removes all elements from the set. """ self.strategy.clear(self) @@ -164,9 +152,355 @@ """ Removes an arbitrary element from the set. May raise KeyError if set is empty.""" return self.strategy.popitem(self) + # app-level operations + + def descr_init(self, space, __args__): + w_iterable, = __args__.parse_obj( + None, 'set', + init_signature, + init_defaults) + _initialize_set(space, self, w_iterable) + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return setrepr(space, w_currently_in_repr, self) + + def descr_cmp(self, space, w_other): + # hack hack until we get the expected result + raise OperationError(space.w_TypeError, + space.wrap('cannot compare sets using cmp()')) + + def descr_eq(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_False + + # XXX there is no test_buildinshortcut.py + # tested in test_buildinshortcut.py + # XXX do not make new setobject here + w_other_as_set = self._newobj(space, w_other) + return space.wrap(self.equals(w_other_as_set)) + + def descr_ne(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(not self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_True + + # XXX this is not tested + w_other_as_set = self._newobj(space, w_other) + return space.wrap(not self.equals(w_other_as_set)) + + # automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the + # correct answer here! + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() >= w_other.length(): + return space.w_False + else: + return self.descr_issubset(space, w_other) + + def descr_le(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() <= w_other.length(): + return space.w_False + else: + return self.descr_issuperset(space, w_other) + + def descr_ge(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + def descr_len(self, space): + return space.newint(self.length()) + + def descr_iter(self, space): + return W_SetIterObject(space, self.iter()) + + def descr_contains(self, space, w_other): + try: + return space.newbool(self.has_key(w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + w_f = _convert_set_to_frozenset(space, w_other) + if w_f is not None: + return space.newbool(self.has_key(w_f)) + raise + + def descr_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.difference(w_other) + + def descr_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.intersect(w_other) + + def descr_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + w_copy = self.copy_real() + w_copy.update(w_other) + return w_copy + + def descr_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.symmetric_difference(w_other) + + def descr_inplace_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.difference_update(w_other) + return self + + def descr_inplace_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.intersect_update(w_other) + return self + + def descr_inplace_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.update(w_other) + return self + + def descr_inplace_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.descr_symmetric_difference_update(space, w_other) + return self + + def descr_copy(self, space): + """Return a shallow copy of a set.""" + if type(self) is W_FrozensetObject: + return self + return self.copy_real() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference(self, space, others_w): + """Return a new set with elements in the set that are not in the + others.""" + result = self.copy_real() + result.descr_difference_update(space, others_w) + return result + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection(self, space, others_w): + """Return a new set with elements common to the set and all others.""" + #XXX find smarter implementations + others_w = [self] + others_w + + # find smallest set in others_w to reduce comparisons + startindex, startlength = 0, -1 + for i in range(len(others_w)): + w_other = others_w[i] + try: + length = space.int_w(space.len(w_other)) + except OperationError, e: + if (e.match(space, space.w_TypeError) or + e.match(space, space.w_AttributeError)): + continue + raise + + if startlength == -1 or length < startlength: + startindex = i + startlength = length + + others_w[startindex], others_w[0] = others_w[0], others_w[startindex] + + result = self._newobj(space, others_w[0]) + for i in range(1,len(others_w)): + w_other = others_w[i] + if isinstance(w_other, W_BaseSetObject): + result.intersect_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + result.intersect_update(w_other_as_set) + return result + + def descr_issubset(self, space, w_other): + """Report whether another set contains this set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() > w_other_as_set.length(): + return space.w_False + return space.wrap(self.issubset(w_other_as_set)) + + def descr_issuperset(self, space, w_other): + """Report whether this set contains another set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() < w_other_as_set.length(): + return space.w_False + return space.wrap(w_other_as_set.issubset(self)) + + def descr_symmetric_difference(self, space, w_other): + """Return the symmetric difference of two sets as a new set. + + (i.e. all elements that are in exactly one of the sets.)""" + + if isinstance(w_other, W_BaseSetObject): + return self.symmetric_difference(w_other) + + w_other_as_set = self._newobj(space, w_other) + return self.symmetric_difference(w_other_as_set) + + @gateway.unwrap_spec(others_w='args_w') + def descr_union(self, space, others_w): + """Return a new set with elements from the set and all others.""" + result = self.copy_real() + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + result.update(w_other) + else: + for w_key in space.listview(w_other): + result.add(w_key) + return result + + def descr_reduce(self, space): + """Return state information for pickling.""" + return setreduce(space, self) + + def descr_isdisjoint(self, space, w_other): + """Return True if two sets have a null intersection.""" + + if isinstance(w_other, W_BaseSetObject): + return space.newbool(self.isdisjoint(w_other)) + + #XXX may be optimized when other strategies are added + for w_key in space.listview(w_other): + if self.has_key(w_key): + return space.w_False + return space.w_True + + def descr_add(self, space, w_other): + """Add an element to a set. + + This has no effect if the element is already present.""" + self.add(w_other) + + def descr_clear(self, space): + """Remove all elements from this set.""" + self.clear() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference_update(self, space, others_w): + """Update the set, removing elements found in others.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.difference_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + self.difference_update(w_other_as_set) + + def _discard_from_set(self, space, w_item): + """ + Discard an element from a set, with automatic conversion to + frozenset if the argument is a set. + Returns True if successfully removed. + """ + try: + deleted = self.remove(w_item) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + else: + w_f = _convert_set_to_frozenset(space, w_item) + if w_f is None: + raise + deleted = self.remove(w_f) + + if self.length() == 0: + self.switch_to_empty_strategy() + return deleted + + def descr_discard(self, space, w_item): + """Remove an element from a set if it is a member. + + If the element is not a member, do nothing.""" + self._discard_from_set(space, w_item) + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection_update(self, space, others_w): + """Update the set, keeping only elements found in it and all others.""" + result = self.descr_intersection(space, others_w) + self.strategy = result.strategy + self.sstorage = result.sstorage + + def descr_pop(self, space): + """Remove and return an arbitrary set element.""" + return self.popitem() + + def descr_remove(self, space, w_item): + """Remove an element from a set; it must be a member. + + If the element is not a member, raise a KeyError.""" + if not self._discard_from_set(space, w_item): + space.raise_key_error(w_item) + + def descr_symmetric_difference_update(self, space, w_other): + """Update a set with the symmetric difference of itself and another.""" + if isinstance(w_other, W_BaseSetObject): + self.symmetric_difference_update(w_other) + return + w_other_as_set = self._newobj(space, w_other) + self.symmetric_difference_update(w_other_as_set) + + @gateway.unwrap_spec(others_w='args_w') + def descr_update(self, space, others_w): + """Update a set with the union of itself and another.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.update(w_other) + else: + for w_key in space.listview(w_other): + self.add(w_key) + + class W_SetObject(W_BaseSetObject): - from pypy.objspace.std.settype import set_typedef as typedef - def _newobj(w_self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" if type(w_self) is W_SetObject: @@ -176,8 +510,71 @@ W_SetObject.__init__(w_obj, space, w_iterable) return w_obj + @staticmethod + def descr_new(space, w_settype, __args__): + w_obj = space.allocate_instance(W_SetObject, w_settype) + W_SetObject.__init__(w_obj, space) + return w_obj + +W_SetObject.typedef = StdTypeDef("set", + __doc__ = """set(iterable) --> set object + +Build an unordered collection.""", + __new__ = gateway.interp2app(W_SetObject.descr_new), + __init__ = gateway.interp2app(W_BaseSetObject.descr_init), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), + __hash__ = None, + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), + + # mutating operators + __isub__ = gateway.interp2app(W_BaseSetObject.descr_inplace_sub), + __iand__ = gateway.interp2app(W_BaseSetObject.descr_inplace_and), + __ior__ = gateway.interp2app(W_BaseSetObject.descr_inplace_or), + __ixor__ = gateway.interp2app(W_BaseSetObject.descr_inplace_xor), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint), + + # mutating methods + add = gateway.interp2app(W_BaseSetObject.descr_add), + clear = gateway.interp2app(W_BaseSetObject.descr_clear), + difference_update = gateway.interp2app(W_BaseSetObject.descr_difference_update), + discard = gateway.interp2app(W_BaseSetObject.descr_discard), + intersection_update = gateway.interp2app(W_BaseSetObject.descr_intersection_update), + pop = gateway.interp2app(W_BaseSetObject.descr_pop), + remove = gateway.interp2app(W_BaseSetObject.descr_remove), + symmetric_difference_update = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference_update), + update = gateway.interp2app(W_BaseSetObject.descr_update) + ) +set_typedef = W_SetObject.typedef + + class W_FrozensetObject(W_BaseSetObject): - from pypy.objspace.std.frozensettype import frozenset_typedef as typedef hash = 0 def _newobj(w_self, space, w_iterable): @@ -189,9 +586,77 @@ W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj -registerimplementation(W_BaseSetObject) -registerimplementation(W_SetObject) -registerimplementation(W_FrozensetObject) + @staticmethod + def descr_new2(space, w_frozensettype, w_iterable=None): + if (space.is_w(w_frozensettype, space.w_frozenset) and + w_iterable is not None and type(w_iterable) is W_FrozensetObject): + return w_iterable + w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) + W_FrozensetObject.__init__(w_obj, space, w_iterable) + return w_obj + + def descr_hash(self, space): + multi = r_uint(1822399083) + r_uint(1822399083) + 1 + if self.hash != 0: + return space.wrap(self.hash) + hash = r_uint(1927868237) + hash *= r_uint(self.length() + 1) + w_iterator = self.iter() + while True: + w_item = w_iterator.next_entry() + if w_item is None: + break + h = space.hash_w(w_item) + value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) + hash = hash ^ value + hash = hash * 69069 + 907133923 + if hash == 0: + hash = 590923713 + hash = intmask(hash) + self.hash = hash + + return space.wrap(hash) + +W_FrozensetObject.typedef = StdTypeDef("frozenset", + __doc__ = """frozenset(iterable) --> frozenset object + +Build an immutable unordered collection.""", + __new__ = gateway.interp2app(W_FrozensetObject.descr_new2), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), + __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint) + ) +frozenset_typedef = W_FrozensetObject.typedef + + class SetStrategy(object): def __init__(self, space): @@ -285,8 +750,8 @@ def popitem(self, w_set): raise NotImplementedError + class EmptySetStrategy(SetStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -377,6 +842,7 @@ raise OperationError(self.space.w_KeyError, self.space.wrap('pop from an empty set')) + class AbstractUnwrappedSetStrategy(object): _mixin_ = True @@ -432,7 +898,6 @@ w_set.add(w_key) def remove(self, w_set, w_item): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string d = self.unerase(w_set.sstorage) if not self.is_correct_type(w_item): #XXX check type of w_item and immediately return False in some cases @@ -464,7 +929,6 @@ return keys_w def has_key(self, w_set, w_key): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string if not self.is_correct_type(w_key): #XXX check type of w_item and immediately return False in some cases w_set.switch_to_object_strategy(self.space) @@ -718,6 +1182,7 @@ self.space.wrap('pop from an empty set')) return self.wrap(result[0]) + class StringSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) @@ -801,7 +1266,6 @@ return self.unerase(w_set.sstorage).keys() def is_correct_type(self, w_key): - from pypy.objspace.std.intobject import W_IntObject return type(w_key) is W_IntObject def may_contain_equal_elements(self, strategy): @@ -822,6 +1286,7 @@ def iter(self, w_set): return IntegerIteratorImplementation(self.space, self, w_set) + class ObjectSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) @@ -866,6 +1331,7 @@ break d_obj[w_item] = None + class IteratorImplementation(object): def __init__(self, space, strategy, implementation): self.space = space @@ -910,6 +1376,7 @@ return self.len - self.pos return 0 + class EmptyIteratorImplementation(IteratorImplementation): def next_entry(self): return None @@ -927,6 +1394,7 @@ else: return None + class UnicodeIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -939,6 +1407,7 @@ else: return None + class IntegerIteratorImplementation(IteratorImplementation): #XXX same implementation in dictmultiobject on dictstrategy-branch def __init__(self, space, strategy, w_set): @@ -953,6 +1422,7 @@ else: return None + class RDictIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -966,26 +1436,34 @@ else: return None -class W_SetIterObject(W_Object): - from pypy.objspace.std.settype import setiter_typedef as typedef - # XXX this class should be killed, and the various - # iterimplementations should be W_Objects directly. + +class W_SetIterObject(W_Root): def __init__(w_self, space, iterimplementation): w_self.space = space w_self.iterimplementation = iterimplementation -registerimplementation(W_SetIterObject) + def descr_length_hint(self, space): + return space.wrap(self.iterimplementation.length()) -def iter__SetIterObject(space, w_setiter): - return w_setiter + def descr_iter(self, space): + return self -def next__SetIterObject(space, w_setiter): - iterimplementation = w_setiter.iterimplementation - w_key = iterimplementation.next() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) + def descr_next(self, space): + iterimplementation = self.iterimplementation + w_key = iterimplementation.next() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) + +W_SetIterObject.typedef = StdTypeDef("setiterator", + __length_hint__ = gateway.interp2app(W_SetIterObject.descr_length_hint), + __iter__ = gateway.interp2app(W_SetIterObject.descr_iter), + next = gateway.interp2app(W_SetIterObject.descr_next) + ) +setiter_typedef = W_SetIterObject.typedef + + # some helper functions @@ -993,7 +1471,6 @@ return r_dict(space.eq_w, space.hash_w, force_non_null=True) def set_strategy_and_setdata(space, w_set, w_iterable): - from pypy.objspace.std.intobject import W_IntObject if w_iterable is None : w_set.strategy = strategy = space.fromcache(EmptySetStrategy) w_set.sstorage = strategy.get_empty_storage() @@ -1067,6 +1544,8 @@ w_set.strategy = space.fromcache(ObjectSetStrategy) w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w) +init_signature = Signature(['some_iterable'], None, None) +init_defaults = [None] def _initialize_set(space, w_obj, w_iterable=None): w_obj.clear() set_strategy_and_setdata(space, w_obj, w_iterable) @@ -1084,424 +1563,6 @@ else: return None -def set_update__Set(space, w_left, others_w): - """Update a set with the union of itself and another.""" - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - w_left.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - w_left.add(w_key) - -def inplace_or__Set_Set(space, w_left, w_other): - w_left.update(w_other) - return w_left - -inplace_or__Set_Frozenset = inplace_or__Set_Set - -def set_add__Set_ANY(space, w_left, w_other): - """Add an element to a set. - - This has no effect if the element is already present. - """ - w_left.add(w_other) - -def set_copy__Set(space, w_set): - return w_set.copy_real() - -def frozenset_copy__Frozenset(space, w_left): - if type(w_left) is W_FrozensetObject: - return w_left - else: - return set_copy__Set(space, w_left) - -def set_clear__Set(space, w_left): - w_left.clear() - -def sub__Set_Set(space, w_left, w_other): - return w_left.difference(w_other) - -sub__Set_Frozenset = sub__Set_Set -sub__Frozenset_Set = sub__Set_Set -sub__Frozenset_Frozenset = sub__Set_Set - -def set_difference__Set(space, w_left, others_w): - result = w_left.copy_real() - set_difference_update__Set(space, result, others_w) - return result - -frozenset_difference__Frozenset = set_difference__Set - - -def set_difference_update__Set(space, w_left, others_w): - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - # optimization only - w_left.difference_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - w_left.difference_update(w_other_as_set) - -def inplace_sub__Set_Set(space, w_left, w_other): - w_left.difference_update(w_other) - return w_left - -inplace_sub__Set_Frozenset = inplace_sub__Set_Set - -def eq__Set_Set(space, w_left, w_other): - # optimization only (the general case is eq__Set_settypedef) - return space.wrap(w_left.equals(w_other)) - -eq__Set_Frozenset = eq__Set_Set -eq__Frozenset_Frozenset = eq__Set_Set -eq__Frozenset_Set = eq__Set_Set - -def eq__Set_settypedef(space, w_left, w_other): - # tested in test_buildinshortcut.py - #XXX do not make new setobject here - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(w_left.equals(w_other_as_set)) - -eq__Set_frozensettypedef = eq__Set_settypedef -eq__Frozenset_settypedef = eq__Set_settypedef -eq__Frozenset_frozensettypedef = eq__Set_settypedef - -def eq__Set_ANY(space, w_left, w_other): - # workaround to have "set() == 42" return False instead of falling - # back to cmp(set(), 42) because the latter raises a TypeError - return space.w_False - -eq__Frozenset_ANY = eq__Set_ANY - -def ne__Set_Set(space, w_left, w_other): - return space.wrap(not w_left.equals(w_other)) - -ne__Set_Frozenset = ne__Set_Set -ne__Frozenset_Frozenset = ne__Set_Set -ne__Frozenset_Set = ne__Set_Set - -def ne__Set_settypedef(space, w_left, w_other): - #XXX this is not tested - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(not w_left.equals(w_other_as_set)) - -ne__Set_frozensettypedef = ne__Set_settypedef -ne__Frozenset_settypedef = ne__Set_settypedef -ne__Frozenset_frozensettypedef = ne__Set_settypedef - - -def ne__Set_ANY(space, w_left, w_other): - # more workarounds - return space.w_True - -ne__Frozenset_ANY = ne__Set_ANY - -def contains__Set_ANY(space, w_left, w_other): - try: - return space.newbool(w_left.has_key(w_other)) - except OperationError, e: - if e.match(space, space.w_TypeError): - w_f = _convert_set_to_frozenset(space, w_other) - if w_f is not None: - return space.newbool(w_left.has_key(w_f)) - raise - -contains__Frozenset_ANY = contains__Set_ANY - -def set_issubset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() > w_other.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other)) - -set_issubset__Set_Frozenset = set_issubset__Set_Set -frozenset_issubset__Frozenset_Set = set_issubset__Set_Set -frozenset_issubset__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issubset__Set_ANY(space, w_left, w_other): - # not checking whether w_left is w_other here, because if that were the - # case the more precise multimethod would have applied. - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() > w_other_as_set.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other_as_set)) - -frozenset_issubset__Frozenset_ANY = set_issubset__Set_ANY - -le__Set_Set = set_issubset__Set_Set -le__Set_Frozenset = set_issubset__Set_Set -le__Frozenset_Set = set_issubset__Set_Set -le__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issuperset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() < w_other.length(): - return space.w_False - return space.wrap(w_other.issubset(w_left)) - -set_issuperset__Set_Frozenset = set_issuperset__Set_Set -set_issuperset__Frozenset_Set = set_issuperset__Set_Set -set_issuperset__Frozenset_Frozenset = set_issuperset__Set_Set - -def set_issuperset__Set_ANY(space, w_left, w_other): - if space.is_w(w_left, w_other): - return space.w_True - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() < w_other_as_set.length(): - return space.w_False - return space.wrap(w_other_as_set.issubset(w_left)) - -frozenset_issuperset__Frozenset_ANY = set_issuperset__Set_ANY - -ge__Set_Set = set_issuperset__Set_Set -ge__Set_Frozenset = set_issuperset__Set_Set -ge__Frozenset_Set = set_issuperset__Set_Set -ge__Frozenset_Frozenset = set_issuperset__Set_Set - -# automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the -# correct answer here! -def lt__Set_Set(space, w_left, w_other): - if w_left.length() >= w_other.length(): - return space.w_False - else: - return le__Set_Set(space, w_left, w_other) - -lt__Set_Frozenset = lt__Set_Set -lt__Frozenset_Set = lt__Set_Set -lt__Frozenset_Frozenset = lt__Set_Set - -def gt__Set_Set(space, w_left, w_other): - if w_left.length() <= w_other.length(): - return space.w_False - else: - return ge__Set_Set(space, w_left, w_other) - -gt__Set_Frozenset = gt__Set_Set -gt__Frozenset_Set = gt__Set_Set -gt__Frozenset_Frozenset = gt__Set_Set - -def _discard_from_set(space, w_left, w_item): - """ - Discard an element from a set, with automatic conversion to - frozenset if the argument is a set. - Returns True if successfully removed. - """ - try: - deleted = w_left.remove(w_item) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - else: - w_f = _convert_set_to_frozenset(space, w_item) - if w_f is None: - raise - deleted = w_left.remove(w_f) - - if w_left.length() == 0: - w_left.switch_to_empty_strategy() - return deleted - -def set_discard__Set_ANY(space, w_left, w_item): - _discard_from_set(space, w_left, w_item) - -def set_remove__Set_ANY(space, w_left, w_item): - if not _discard_from_set(space, w_left, w_item): - space.raise_key_error(w_item) - -def hash__Frozenset(space, w_set): - multi = r_uint(1822399083) + r_uint(1822399083) + 1 - if w_set.hash != 0: - return space.wrap(w_set.hash) - hash = r_uint(1927868237) - hash *= r_uint(w_set.length() + 1) - w_iterator = w_set.iter() - while True: - w_item = w_iterator.next_entry() - if w_item is None: - break - h = space.hash_w(w_item) - value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) - hash = hash ^ value - hash = hash * 69069 + 907133923 - if hash == 0: - hash = 590923713 - hash = intmask(hash) - w_set.hash = hash - - return space.wrap(hash) - -def set_pop__Set(space, w_left): - return w_left.popitem() - -def and__Set_Set(space, w_left, w_other): - new_set = w_left.intersect(w_other) - return new_set - -and__Set_Frozenset = and__Set_Set -and__Frozenset_Set = and__Set_Set -and__Frozenset_Frozenset = and__Set_Set - -def set_intersection__Set(space, w_left, others_w): - #XXX find smarter implementations - others_w = [w_left] + others_w - - # find smallest set in others_w to reduce comparisons - startindex, startlength = 0, -1 - for i in range(len(others_w)): - w_other = others_w[i] - try: - length = space.int_w(space.len(w_other)) - except OperationError, e: - if (e.match(space, space.w_TypeError) or - e.match(space, space.w_AttributeError)): - continue - raise - - if startlength == -1 or length < startlength: - startindex = i - startlength = length - - others_w[startindex], others_w[0] = others_w[0], others_w[startindex] - - result = w_left._newobj(space, others_w[0]) - for i in range(1,len(others_w)): - w_other = others_w[i] - if isinstance(w_other, W_BaseSetObject): - # optimization only - result.intersect_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - result.intersect_update(w_other_as_set) - return result - -frozenset_intersection__Frozenset = set_intersection__Set - -def set_intersection_update__Set(space, w_left, others_w): - result = set_intersection__Set(space, w_left, others_w) - w_left.strategy = result.strategy - w_left.sstorage = result.sstorage - return - -def inplace_and__Set_Set(space, w_left, w_other): - w_left.intersect_update(w_other) - return w_left - -inplace_and__Set_Frozenset = inplace_and__Set_Set - -def set_isdisjoint__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - return space.newbool(w_left.isdisjoint(w_other)) - -set_isdisjoint__Set_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Set = set_isdisjoint__Set_Set - -def set_isdisjoint__Set_ANY(space, w_left, w_other): - #XXX may be optimized when other strategies are added - for w_key in space.listview(w_other): - if w_left.has_key(w_key): - return space.w_False - return space.w_True - -frozenset_isdisjoint__Frozenset_ANY = set_isdisjoint__Set_ANY - -def set_symmetric_difference__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_result = w_left.symmetric_difference(w_other) - return w_result - -set_symmetric_difference__Set_Frozenset = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Set = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Frozenset = \ - set_symmetric_difference__Set_Set - -xor__Set_Set = set_symmetric_difference__Set_Set -xor__Set_Frozenset = set_symmetric_difference__Set_Set -xor__Frozenset_Set = set_symmetric_difference__Set_Set -xor__Frozenset_Frozenset = set_symmetric_difference__Set_Set - - -def set_symmetric_difference__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_result = w_left.symmetric_difference(w_other_as_set) - return w_result - -frozenset_symmetric_difference__Frozenset_ANY = \ - set_symmetric_difference__Set_ANY - -def set_symmetric_difference_update__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_left.symmetric_difference_update(w_other) - -set_symmetric_difference_update__Set_Frozenset = \ - set_symmetric_difference_update__Set_Set - -def set_symmetric_difference_update__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_left.symmetric_difference_update(w_other_as_set) - -def inplace_xor__Set_Set(space, w_left, w_other): - set_symmetric_difference_update__Set_Set(space, w_left, w_other) - return w_left - -inplace_xor__Set_Frozenset = inplace_xor__Set_Set - -def or__Set_Set(space, w_left, w_other): - w_copy = w_left.copy_real() - w_copy.update(w_other) - return w_copy - -or__Set_Frozenset = or__Set_Set -or__Frozenset_Set = or__Set_Set -or__Frozenset_Frozenset = or__Set_Set - -def set_union__Set(space, w_left, others_w): - result = w_left.copy_real() - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - result.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - result.add(w_key) - return result - -frozenset_union__Frozenset = set_union__Set - -def len__Set(space, w_left): - return space.newint(w_left.length()) - -len__Frozenset = len__Set - -def iter__Set(space, w_left): - return W_SetIterObject(space, w_left.iter()) - -iter__Frozenset = iter__Set - -def cmp__Set_settypedef(space, w_left, w_other): - # hack hack until we get the expected result - raise OperationError(space.w_TypeError, - space.wrap('cannot compare sets using cmp()')) - -cmp__Set_frozensettypedef = cmp__Set_settypedef -cmp__Frozenset_settypedef = cmp__Set_settypedef -cmp__Frozenset_frozensettypedef = cmp__Set_settypedef - -init_signature = Signature(['some_iterable'], None, None) -init_defaults = [None] -def init__Set(space, w_set, __args__): - w_iterable, = __args__.parse_obj( - None, 'set', - init_signature, - init_defaults) - _initialize_set(space, w_set, w_iterable) app = gateway.applevel(""" def setrepr(currently_in_repr, s): @@ -1521,26 +1582,11 @@ setrepr = app.interphook("setrepr") -def repr__Set(space, w_set): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return setrepr(space, w_currently_in_repr, w_set) - -repr__Frozenset = repr__Set - app = gateway.applevel(""" - def reduce__Set(s): + def setreduce(s): dict = getattr(s,'__dict__', None) return (s.__class__, (tuple(s),), dict) """, filename=__file__) -set_reduce__Set = app.interphook('reduce__Set') -frozenset_reduce__Frozenset = app.interphook('reduce__Set') - -from pypy.objspace.std import frozensettype -from pypy.objspace.std import settype - -register_all(vars(), settype, frozensettype) +setreduce = app.interphook('setreduce') diff --git a/pypy/objspace/std/settype.py b/pypy/objspace/std/settype.py deleted file mode 100644 --- a/pypy/objspace/std/settype.py +++ /dev/null @@ -1,91 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -set_add = SMM('add', 2, - doc='Add an element to a set.\n\nThis' - ' has no effect if the element is' - ' already present.') -set_clear = SMM('clear', 1, - doc='Remove all elements from this set.') -set_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -set_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -set_difference_update = SMM('difference_update', 1, varargs_w=True, - doc='Update the set, removing elements' - ' found in others.') -set_discard = SMM('discard', 2, - doc='Remove an element from a set if it' - ' is a member.\n\nIf the element is' - ' not a member, do nothing.') -set_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -set_intersection_update = SMM('intersection_update', 1, varargs_w=True, - doc='Update the set, keeping only elements' - ' found in it and all others.') -set_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -set_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -set_pop = SMM('pop', 1, - doc='Remove and return an arbitrary set' - ' element.') -set_remove = SMM('remove', 2, - doc='Remove an element from a set; it' - ' must be a member.\n\nIf the' - ' element is not a member, raise a' - ' KeyError.') -set_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -set_symmetric_difference_update = SMM('symmetric_difference_update', 2, - doc='Update a set with the symmetric' - ' difference of itself and another.') -set_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -set_update = SMM('update', 1, varargs_w=True, - doc='Update the set, adding elements' - ' from all others.') -set_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -set_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__new__(space, w_settype, __args__): - from pypy.objspace.std.setobject import W_SetObject, newset - w_obj = space.allocate_instance(W_SetObject, w_settype) - W_SetObject.__init__(w_obj, space) - return w_obj - -set_typedef = StdTypeDef("set", - __doc__ = """set(iterable) --> set object - -Build an unordered collection.""", - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - ) - -set_typedef.registermethods(globals()) - -def descr_setiterator__length_hint__(space, w_self): - from pypy.objspace.std.setobject import W_SetIterObject - assert isinstance(w_self, W_SetIterObject) - return space.wrap(w_self.iterimplementation.length()) - -setiter_typedef = StdTypeDef("setiterator", - __length_hint__ = gateway.interp2app(descr_setiterator__length_hint__), - ) diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -12,9 +12,6 @@ from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject, IntegerSetStrategy from pypy.objspace.std.setobject import _initialize_set from pypy.objspace.std.setobject import newset -from pypy.objspace.std.setobject import and__Set_Set -from pypy.objspace.std.setobject import set_intersection__Set -from pypy.objspace.std.setobject import eq__Set_Set from pypy.objspace.std.listobject import W_ListObject letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -36,11 +33,11 @@ t0 = W_SetObject(self.space) _initialize_set(self.space, t0, self.otherword) t1 = W_FrozensetObject(self.space, self.otherword) - r0 = and__Set_Set(self.space, s, t0) - r1 = and__Set_Set(self.space, s, t1) - assert eq__Set_Set(self.space, r0, r1) == self.true - sr = set_intersection__Set(self.space, s, [self.otherword]) - assert eq__Set_Set(self.space, r0, sr) == self.true + r0 = s.descr_and(self.space, t0) + r1 = s.descr_and(self.space, t1) + assert r0.descr_eq(self.space, r1) == self.true + sr = s.descr_intersection(self.space, [self.otherword]) + assert r0.descr_eq(self.space, sr) == self.true def test_compare(self): s = W_SetObject(self.space) @@ -66,7 +63,7 @@ b = W_SetObject(self.space) _initialize_set(self.space, b, self.space.wrap("abc")) - result = set_intersection__Set(space, a, [b]) + result = a.descr_intersection(space, [b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("abc")))) c = W_SetObject(self.space) @@ -80,7 +77,7 @@ b.get_storage_copy = None d.get_storage_copy = None - result = set_intersection__Set(space, a, [d,c,b]) + result = a.descr_intersection(space, [d,c,b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("")))) def test_create_set_from_list(self): diff --git a/pypy/objspace/std/test/test_setstrategies.py b/pypy/objspace/std/test/test_setstrategies.py --- a/pypy/objspace/std/test/test_setstrategies.py +++ b/pypy/objspace/std/test/test_setstrategies.py @@ -65,18 +65,16 @@ assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_remove(self): - from pypy.objspace.std.setobject import set_remove__Set_ANY s1 = W_SetObject(self.space, self.wrapped([1])) - set_remove__Set_ANY(self.space, s1, self.space.wrap(1)) + self.space.call_method(s1, 'remove', self.space.wrap(1)) assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_union(self): - from pypy.objspace.std.setobject import set_union__Set s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) s2 = W_SetObject(self.space, self.wrapped([4,5,6,7])) s3 = W_SetObject(self.space, self.wrapped([4,'5','6',7])) - s4 = set_union__Set(self.space, s1, [s2]) - s5 = set_union__Set(self.space, s1, [s3]) + s4 = s1.descr_union(self.space, [s2]) + s5 = s1.descr_union(self.space, [s3]) assert s4.strategy is self.space.fromcache(IntegerSetStrategy) assert s5.strategy is self.space.fromcache(ObjectSetStrategy) @@ -91,10 +89,8 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) - set_discard__Set_ANY(self.space, s1, self.space.wrap("five")) + s1.descr_discard(self.space, self.space.wrap("five")) skip("currently not supported") assert s1.strategy is self.space.fromcache(IntegerSetStrategy) @@ -112,8 +108,6 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) assert not s1.has_key(self.space.wrap("five")) skip("currently not supported") diff --git a/rpython/jit/metainterp/test/test_compile.py b/rpython/jit/metainterp/test/test_compile.py --- a/rpython/jit/metainterp/test/test_compile.py +++ b/rpython/jit/metainterp/test/test_compile.py @@ -1,10 +1,10 @@ from rpython.config.translationoption import get_combined_translation_config -from rpython.jit.metainterp.history import TargetToken, ConstInt, History, Stats -from rpython.jit.metainterp.history import BoxInt, INT +from rpython.jit.metainterp.history import ConstInt, History, Stats +from rpython.jit.metainterp.history import INT from rpython.jit.metainterp.compile import compile_loop -from rpython.jit.metainterp.compile import ResumeGuardDescr from rpython.jit.metainterp.compile import ResumeGuardCountersInt from rpython.jit.metainterp.compile import compile_tmp_callback +from rpython.jit.metainterp import jitexc from rpython.jit.metainterp import jitprof, typesystem, compile from rpython.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin from rpython.jit.tool.oparser import parse @@ -13,7 +13,7 @@ class FakeCPU(object): class tracker: pass - + ts = typesystem.llhelper def __init__(self): self.seen = [] @@ -41,7 +41,7 @@ loopnumbering = 0 class FakeMetaInterpStaticData(object): - + logger_noopt = FakeLogger() logger_ops = FakeLogger() config = get_combined_translation_config(translating=True) @@ -192,14 +192,13 @@ assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), got) == llexc # class FakeMetaInterpSD: - class ExitFrameWithExceptionRef(Exception): - pass + pass FakeMetaInterpSD.cpu = cpu deadframe = cpu.execute_token(loop_token, -156, -178) fail_descr = cpu.get_latest_descr(deadframe) try: fail_descr.handle_fail(deadframe, FakeMetaInterpSD(), None) - except FakeMetaInterpSD.ExitFrameWithExceptionRef, e: - assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.args[1]) == llexc + except jitexc.ExitFrameWithExceptionRef, e: + assert lltype.cast_opaque_ptr(lltype.Ptr(EXC), e.value) == llexc else: assert 0, "should have raised" diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -170,12 +170,57 @@ jit2gc = gctransformer.translator._jit2gc self.frame_tid = jit2gc['frame_tid'] self.gctransformer = gctransformer + # + # unless overridden in need_thread_support(): + self.belongs_to_current_thread = lambda framedata: True def need_stacklet_support(self, gctransformer, getfn): + from rpython.annotator import model as annmodel + from rpython.rlib import _stacklet_asmgcc # stacklet support: BIG HACK for rlib.rstacklet - from rpython.rlib import _stacklet_asmgcc _stacklet_asmgcc._asmstackrootwalker = self # as a global! argh _stacklet_asmgcc.complete_destrptr(gctransformer) + # + def gc_detach_callback_pieces(): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + result = llmemory.NULL + framedata = anchor.address[1] + while framedata != anchor: + next = framedata.address[1] + if self.belongs_to_current_thread(framedata): + # detach it + prev = framedata.address[0] + prev.address[1] = next + next.address[0] = prev + # update the global stack counter + rffi.stackcounter.stacks_counter -= 1 + # reattach framedata into the singly-linked list 'result' + framedata.address[0] = rffi.cast(llmemory.Address, -1) + framedata.address[1] = result + result = framedata + framedata = next + return result + # + def gc_reattach_callback_pieces(pieces): + anchor = llmemory.cast_ptr_to_adr(gcrootanchor) + while pieces != llmemory.NULL: + framedata = pieces + pieces = pieces.address[1] + # attach 'framedata' into the normal doubly-linked list + following = anchor.address[1] + following.address[0] = framedata + framedata.address[1] = following + anchor.address[1] = framedata + framedata.address[0] = anchor + # update the global stack counter + rffi.stackcounter.stacks_counter += 1 + # + s_addr = annmodel.SomeAddress() + s_None = annmodel.s_None + self.gc_detach_callback_pieces_ptr = getfn(gc_detach_callback_pieces, + [], s_addr) + self.gc_reattach_callback_pieces_ptr=getfn(gc_reattach_callback_pieces, + [s_addr], s_None) def need_thread_support(self, gctransformer, getfn): # Threads supported "out of the box" by the rest of the code. @@ -227,6 +272,7 @@ stack_stop = llop.stack_current(llmemory.Address) return (stack_start <= framedata <= stack_stop or stack_start >= framedata >= stack_stop) + self.belongs_to_current_thread = belongs_to_current_thread def thread_before_fork(): # before fork(): collect all ASM_FRAMEDATA structures that do diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -800,6 +800,21 @@ def gct_gc_adr_of_root_stack_top(self, hop): self._gc_adr_of_gcdata_attr(hop, 'root_stack_top') + def gct_gc_detach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 0 + hop.genop("direct_call", + [self.root_walker.gc_detach_callback_pieces_ptr], + resultvar=op.result) + + def gct_gc_reattach_callback_pieces(self, hop): + op = hop.spaceop + assert len(op.args) == 1 + hop.genop("direct_call", + [self.root_walker.gc_reattach_callback_pieces_ptr, + op.args[0]], + resultvar=op.result) + def gct_gc_shadowstackref_new(self, hop): op = hop.spaceop livevars = self.push_roots(hop) diff --git a/rpython/rlib/_stacklet_asmgcc.py b/rpython/rlib/_stacklet_asmgcc.py --- a/rpython/rlib/_stacklet_asmgcc.py +++ b/rpython/rlib/_stacklet_asmgcc.py @@ -32,6 +32,7 @@ if not p.handle: return False self.context = llmemory.cast_ptr_to_adr(p.handle) + self.next_callback_piece = p.callback_pieces anchor = p.anchor del p self.curframe = lltype.malloc(WALKFRAME, flavor='raw') @@ -50,11 +51,19 @@ retaddraddr = self.translateptr(retaddraddr) curframe.frame_address = retaddraddr.address[0] From noreply at buildbot.pypy.org Wed May 15 21:14:47 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 21:14:47 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: hg merge default Message-ID: <20130515191447.A58C81C1306@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64199:21ba419290ae Date: 2013-05-15 21:01 +0200 http://bitbucket.org/pypy/pypy/changeset/21ba419290ae/ Log: hg merge default diff too long, truncating to 2000 out of 2580 lines diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -1387,7 +1387,8 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if (encoding not in broken_incremental_coders and + hasattr(_testcapi, 'codec_incrementalencoder')): # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_descr.py b/lib-python/2.7/test/test_descr.py --- a/lib-python/2.7/test/test_descr.py +++ b/lib-python/2.7/test/test_descr.py @@ -2080,8 +2080,9 @@ except ImportError: pass else: - class X(object): - p = property(_testcapi.test_with_docstring) + if hasattr(_testcapi, 'test_with_docstring'): + class X(object): + p = property(_testcapi.test_with_docstring) def test_properties_plus(self): class C(object): diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print +try: + from _testcapi import traceback_print +except ImportError: + traceback_print = None from StringIO import StringIO import sys import unittest @@ -176,6 +179,8 @@ class TracebackFormatTests(unittest.TestCase): def test_traceback_format(self): + if traceback_print is None: + return try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1609,7 +1609,10 @@ self.assertEqual("{}".format(u), '__unicode__ overridden') def test_encode_decimal(self): - from _testcapi import unicode_encodedecimal + try: + from _testcapi import unicode_encodedecimal + except ImportError: + return self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -54,4 +54,9 @@ fp, filename, description = imp.find_module('_testcapi', path=[output_dir]) imp.load_module('_testcapi', fp, filename, description) -compile_shared() +try: + import cpyext +except ImportError: + pass +else: + compile_shared() 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 @@ -7,3 +7,12 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) + +.. branch: remove-array-smm +Remove multimethods in the arraymodule + +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback + +.. branch: remove-set-smm +Remove multi-methods on sets diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -666,7 +666,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -55,6 +55,7 @@ 'validate_fd' : 'interp_magic.validate_fd', 'resizelist_hint' : 'interp_magic.resizelist_hint', 'newlist_hint' : 'interp_magic.newlist_hint', + 'add_memory_pressure' : 'interp_magic.add_memory_pressure', 'newdict' : 'interp_dict.newdict', 'dictstrategy' : 'interp_dict.dictstrategy', } diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py --- a/pypy/module/__pypy__/interp_magic.py +++ b/pypy/module/__pypy__/interp_magic.py @@ -4,7 +4,7 @@ from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.typeobject import MethodCache from pypy.objspace.std.mapdict import IndexCache -from rpython.rlib import rposix +from rpython.rlib import rposix, rgc def internal_repr(space, w_object): @@ -100,3 +100,7 @@ @unwrap_spec(sizehint=int) def newlist_hint(space, sizehint): return space.newlist_hint(sizehint) + + at unwrap_spec(estimate=int) +def add_memory_pressure(estimate): + rgc.add_memory_pressure(estimate) 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 @@ -100,11 +100,11 @@ return space.w_True if comp_op == LT or comp_op == LE: if arr1.len < arr2.len: - return space.w_False + return space.w_True + return space.w_False + if arr1.len > arr2.len: return space.w_True - if arr1.len > arr2.len: - return space.w_False - return space.w_True + return space.w_False UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar, hints={'nolength': True})) diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py --- a/pypy/module/array/test/test_array.py +++ b/pypy/module/array/test/test_array.py @@ -552,6 +552,15 @@ assert (a >= c) is False assert (c >= a) is True + a = self.array('i', [-1, 0, 1, 42, 0x7f]) + assert not a == 2*a + assert a != 2*a + assert a < 2*a + assert a <= 2*a + assert not a > 2*a + assert not a >= 2*a + + def test_reduce(self): import pickle a = self.array('i', [1, 2, 3]) diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -14,6 +14,7 @@ from pypy.module.micronumpy.interp_arrayops import where from pypy.module.micronumpy import interp_ufuncs from rpython.rlib.objectmodel import specialize, instantiate +from rpython.rlib.nonconst import NonConstant class BogusBytecode(Exception): @@ -40,6 +41,10 @@ TWO_ARG_FUNCTIONS = ["dot", 'take'] THREE_ARG_FUNCTIONS = ['where'] +class W_TypeObject(W_Root): + def __init__(self, name): + self.name = name + class FakeSpace(object): w_ValueError = "ValueError" w_TypeError = "TypeError" @@ -48,17 +53,17 @@ w_NotImplementedError = "NotImplementedError" w_None = None - w_bool = "bool" - w_int = "int" - w_float = "float" - w_list = "list" - w_long = "long" - w_tuple = 'tuple' - w_slice = "slice" - w_str = "str" - w_unicode = "unicode" - w_complex = "complex" - w_dict = "dict" + w_bool = W_TypeObject("bool") + w_int = W_TypeObject("int") + w_float = W_TypeObject("float") + w_list = W_TypeObject("list") + w_long = W_TypeObject("long") + w_tuple = W_TypeObject('tuple') + w_slice = W_TypeObject("slice") + w_str = W_TypeObject("str") + w_unicode = W_TypeObject("unicode") + w_complex = W_TypeObject("complex") + w_dict = W_TypeObject("dict") def __init__(self): """NOT_RPYTHON""" @@ -73,6 +78,13 @@ def issequence_w(self, w_obj): return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray) + def len(self, w_obj): + assert isinstance(w_obj, ListObject) + return self.wrap(len(w_obj.items)) + + def getattr(self, w_obj, w_attr): + return StringObject(NonConstant('foo')) + def isinstance_w(self, w_obj, w_tp): return w_obj.tp == w_tp diff --git a/pypy/module/sys/system.py b/pypy/module/sys/system.py --- a/pypy/module/sys/system.py +++ b/pypy/module/sys/system.py @@ -1,6 +1,6 @@ """Information about the current system.""" from pypy.interpreter import gateway -from rpython.rlib import rfloat, rbigint +from rpython.rlib import rbigint, rfloat from rpython.rtyper.lltypesystem import rffi @@ -47,7 +47,6 @@ return space.call_function(w_float_info, space.newtuple(info_w)) def get_long_info(space): - #assert rbigint.SHIFT == 31 bits_per_digit = rbigint.SHIFT sizeof_digit = rffi.sizeof(rbigint.STORE_TYPE) info_w = [ @@ -58,7 +57,4 @@ return space.call_function(w_long_info, space.newtuple(info_w)) def get_float_repr_style(space): - if rfloat.USE_SHORT_FLOAT_REPR: - return space.wrap("short") - else: - return space.wrap("legacy") + return space.wrap("short" if rfloat.USE_SHORT_FLOAT_REPR else "legacy") diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py --- a/pypy/objspace/fake/checkmodule.py +++ b/pypy/objspace/fake/checkmodule.py @@ -5,6 +5,7 @@ def checkmodule(*modnames): config = get_pypy_config(translating=True) space = FakeObjSpace(config) + space.setup() seeobj_w = [] for modname in modnames: mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__']) diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -55,6 +55,10 @@ from rpython.rlib.rbigint import rbigint return rbigint.fromint(NonConstant(42)) +class W_MyListObj(W_MyObject): + def append(self, w_other): + pass + class W_MyType(W_MyObject): def __init__(self): self.mro_w = [w_some_obj(), w_some_obj()] @@ -107,6 +111,9 @@ self._seen_extras = [] ObjSpace.__init__(self, config=config) + def _freeze_(self): + return True + def float_w(self, w_obj): is_root(w_obj) return NonConstant(42.5) @@ -131,7 +138,7 @@ def newlist(self, list_w): for w_x in list_w: is_root(w_x) - return w_some_obj() + return W_MyListObj() def newslice(self, w_start, w_end, w_step): is_root(w_start) @@ -316,38 +323,36 @@ t.buildrtyper().specialize() t.checkgraphs() + def setup(space): + for name in (ObjSpace.ConstantTable + + ObjSpace.ExceptionTable + + ['int', 'str', 'float', 'long', 'tuple', 'list', + 'dict', 'unicode', 'complex', 'slice', 'bool', + 'basestring', 'object', 'bytearray']): + setattr(space, 'w_' + name, w_some_obj()) + space.w_type = w_some_type() + # + for (name, _, arity, _) in ObjSpace.MethodTable: + if name == 'type': + continue + args = ['w_%d' % i for i in range(arity)] + params = args[:] + d = {'is_root': is_root, + 'w_some_obj': w_some_obj} + if name in ('get',): + params[-1] += '=None' + exec compile2("""\ + def meth(%s): + %s + return w_some_obj() + """ % (', '.join(params), + '; '.join(['is_root(%s)' % arg for arg in args]))) in d + meth = func_with_new_name(d['meth'], name) + setattr(space, name, meth) + # + for name in ObjSpace.IrregularOpTable: + assert hasattr(space, name) # missing? -def setup(): - for name in (ObjSpace.ConstantTable + - ObjSpace.ExceptionTable + - ['int', 'str', 'float', 'long', 'tuple', 'list', - 'dict', 'unicode', 'complex', 'slice', 'bool', - 'basestring', 'object', 'bytearray']): - setattr(FakeObjSpace, 'w_' + name, w_some_obj()) - FakeObjSpace.w_type = w_some_type() - # - for (name, _, arity, _) in ObjSpace.MethodTable: - if name == 'type': - continue - args = ['w_%d' % i for i in range(arity)] - params = args[:] - d = {'is_root': is_root, - 'w_some_obj': w_some_obj} - if name in ('get',): - params[-1] += '=None' - exec compile2("""\ - def meth(self, %s): - %s - return w_some_obj() - """ % (', '.join(params), - '; '.join(['is_root(%s)' % arg for arg in args]))) in d - meth = func_with_new_name(d['meth'], name) - setattr(FakeObjSpace, name, meth) - # - for name in ObjSpace.IrregularOpTable: - assert hasattr(FakeObjSpace, name) # missing? - -setup() # ____________________________________________________________ diff --git a/pypy/objspace/std/frozensettype.py b/pypy/objspace/std/frozensettype.py deleted file mode 100644 --- a/pypy/objspace/std/frozensettype.py +++ /dev/null @@ -1,55 +0,0 @@ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - - -frozenset_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -frozenset_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -frozenset_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -frozenset_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -frozenset_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -frozenset_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -frozenset_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -frozenset_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -frozenset_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__frozenset__new__(space, w_frozensettype, w_iterable=None): - from pypy.objspace.std.setobject import W_FrozensetObject - if (space.is_w(w_frozensettype, space.w_frozenset) and - w_iterable is not None and type(w_iterable) is W_FrozensetObject): - return w_iterable - w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) - W_FrozensetObject.__init__(w_obj, space, w_iterable) - return w_obj - -frozenset_typedef = StdTypeDef("frozenset", - __doc__ = """frozenset(iterable) --> frozenset object - -Build an immutable unordered collection.""", - __new__ = gateway.interp2app(descr__frozenset__new__), - ) - -frozenset_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -38,8 +38,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.settype import set_typedef - from pypy.objspace.std.frozensettype import frozenset_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.dictmultiobject import dict_typedef @@ -63,10 +61,10 @@ from pypy.objspace.std import intobject from pypy.objspace.std import floatobject from pypy.objspace.std import complexobject - from pypy.objspace.std import setobject from pypy.objspace.std import tupleobject from pypy.objspace.std import listobject from pypy.objspace.std import dictmultiobject + from pypy.objspace.std import setobject from pypy.objspace.std import stringobject from pypy.objspace.std import bytearrayobject from pypy.objspace.std import typeobject @@ -81,6 +79,11 @@ import pypy.objspace.std.marshal_impl # install marshal multimethods + # not-multimethod based types + + self.pythontypes.append(setobject.W_SetObject.typedef) + self.pythontypes.append(setobject.W_FrozensetObject.typedef) + # the set of implementation types self.typeorder = { objectobject.W_ObjectObject: [], @@ -100,10 +103,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - setobject.W_BaseSetObject: [], - setobject.W_SetObject: [], - setobject.W_FrozensetObject: [], - setobject.W_SetIterObject: [], iterobject.W_SeqIterObject: [], iterobject.W_FastListIterObject: [], iterobject.W_FastTupleIterObject: [], @@ -192,12 +191,7 @@ (complexobject.W_ComplexObject, complexobject.delegate_Float2Complex), ] - self.typeorder[setobject.W_SetObject] += [ - (setobject.W_BaseSetObject, None) - ] - self.typeorder[setobject.W_FrozensetObject] += [ - (setobject.W_BaseSetObject, None) - ] + self.typeorder[stringobject.W_StringObject] += [ (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode), ] @@ -339,8 +333,9 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(w_self, space): - raise UnwrapError, 'cannot unwrap %r' % (w_self,) + def unwrap(self, space): + raise UnwrapError('cannot unwrap %r' % self) + class UnwrapError(Exception): pass @@ -405,7 +400,7 @@ mm.dispatch_tree = merge(self.dispatch_tree, other.dispatch_tree) return mm -NOT_MULTIMETHODS = dict.fromkeys( +NOT_MULTIMETHODS = set( ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv', 'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift', 'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel', diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -1,13 +1,9 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter import gateway from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway -from pypy.objspace.std.settype import set_typedef as settypedef -from pypy.objspace.std.frozensettype import frozenset_typedef as frozensettypedef from pypy.interpreter.signature import Signature -from pypy.interpreter.generator import GeneratorIterator -from pypy.objspace.std.listobject import W_ListObject +from pypy.interpreter.baseobjspace import W_Root from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.unicodeobject import W_UnicodeObject @@ -15,20 +11,13 @@ from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib import rerased, jit + UNROLL_CUTOFF = 5 -class W_BaseSetObject(W_Object): + +class W_BaseSetObject(W_Root): typedef = None - # make sure that Base is used for Set and Frozenset in multimethod - # declarations - @classmethod - def is_implementation_for(cls, typedef): - if typedef is frozensettypedef or typedef is settypedef: - assert cls is W_BaseSetObject - return True - return False - def __init__(w_self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" w_self.space = space @@ -66,7 +55,6 @@ # _____________ strategy methods ________________ - def clear(self): """ Removes all elements from the set. """ self.strategy.clear(self) @@ -164,9 +152,355 @@ """ Removes an arbitrary element from the set. May raise KeyError if set is empty.""" return self.strategy.popitem(self) + # app-level operations + + def descr_init(self, space, __args__): + w_iterable, = __args__.parse_obj( + None, 'set', + init_signature, + init_defaults) + _initialize_set(space, self, w_iterable) + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return setrepr(space, w_currently_in_repr, self) + + def descr_cmp(self, space, w_other): + # hack hack until we get the expected result + raise OperationError(space.w_TypeError, + space.wrap('cannot compare sets using cmp()')) + + def descr_eq(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_False + + # XXX there is no test_buildinshortcut.py + # tested in test_buildinshortcut.py + # XXX do not make new setobject here + w_other_as_set = self._newobj(space, w_other) + return space.wrap(self.equals(w_other_as_set)) + + def descr_ne(self, space, w_other): + if isinstance(w_other, W_BaseSetObject): + return space.wrap(not self.equals(w_other)) + + if not space.isinstance_w(w_other, space.w_set): + return space.w_True + + # XXX this is not tested + w_other_as_set = self._newobj(space, w_other) + return space.wrap(not self.equals(w_other_as_set)) + + # automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the + # correct answer here! + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() >= w_other.length(): + return space.w_False + else: + return self.descr_issubset(space, w_other) + + def descr_le(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() <= w_other.length(): + return space.w_False + else: + return self.descr_issuperset(space, w_other) + + def descr_ge(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + raise OperationError(self.space.w_TypeError, + self.space.wrap('can only compare to a set')) + + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + def descr_len(self, space): + return space.newint(self.length()) + + def descr_iter(self, space): + return W_SetIterObject(space, self.iter()) + + def descr_contains(self, space, w_other): + try: + return space.newbool(self.has_key(w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + w_f = _convert_set_to_frozenset(space, w_other) + if w_f is not None: + return space.newbool(self.has_key(w_f)) + raise + + def descr_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.difference(w_other) + + def descr_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.intersect(w_other) + + def descr_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + w_copy = self.copy_real() + w_copy.update(w_other) + return w_copy + + def descr_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + return self.symmetric_difference(w_other) + + def descr_inplace_sub(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.difference_update(w_other) + return self + + def descr_inplace_and(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.intersect_update(w_other) + return self + + def descr_inplace_or(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.update(w_other) + return self + + def descr_inplace_xor(self, space, w_other): + if not isinstance(w_other, W_BaseSetObject): + return space.w_NotImplemented + self.descr_symmetric_difference_update(space, w_other) + return self + + def descr_copy(self, space): + """Return a shallow copy of a set.""" + if type(self) is W_FrozensetObject: + return self + return self.copy_real() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference(self, space, others_w): + """Return a new set with elements in the set that are not in the + others.""" + result = self.copy_real() + result.descr_difference_update(space, others_w) + return result + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection(self, space, others_w): + """Return a new set with elements common to the set and all others.""" + #XXX find smarter implementations + others_w = [self] + others_w + + # find smallest set in others_w to reduce comparisons + startindex, startlength = 0, -1 + for i in range(len(others_w)): + w_other = others_w[i] + try: + length = space.int_w(space.len(w_other)) + except OperationError, e: + if (e.match(space, space.w_TypeError) or + e.match(space, space.w_AttributeError)): + continue + raise + + if startlength == -1 or length < startlength: + startindex = i + startlength = length + + others_w[startindex], others_w[0] = others_w[0], others_w[startindex] + + result = self._newobj(space, others_w[0]) + for i in range(1,len(others_w)): + w_other = others_w[i] + if isinstance(w_other, W_BaseSetObject): + result.intersect_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + result.intersect_update(w_other_as_set) + return result + + def descr_issubset(self, space, w_other): + """Report whether another set contains this set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() > w_other.length(): + return space.w_False + return space.wrap(self.issubset(w_other)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() > w_other_as_set.length(): + return space.w_False + return space.wrap(self.issubset(w_other_as_set)) + + def descr_issuperset(self, space, w_other): + """Report whether this set contains another set.""" + if space.is_w(self, w_other): + return space.w_True + + if isinstance(w_other, W_BaseSetObject): + if self.length() < w_other.length(): + return space.w_False + return space.wrap(w_other.issubset(self)) + + w_other_as_set = self._newobj(space, w_other) + if self.length() < w_other_as_set.length(): + return space.w_False + return space.wrap(w_other_as_set.issubset(self)) + + def descr_symmetric_difference(self, space, w_other): + """Return the symmetric difference of two sets as a new set. + + (i.e. all elements that are in exactly one of the sets.)""" + + if isinstance(w_other, W_BaseSetObject): + return self.symmetric_difference(w_other) + + w_other_as_set = self._newobj(space, w_other) + return self.symmetric_difference(w_other_as_set) + + @gateway.unwrap_spec(others_w='args_w') + def descr_union(self, space, others_w): + """Return a new set with elements from the set and all others.""" + result = self.copy_real() + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + result.update(w_other) + else: + for w_key in space.listview(w_other): + result.add(w_key) + return result + + def descr_reduce(self, space): + """Return state information for pickling.""" + return setreduce(space, self) + + def descr_isdisjoint(self, space, w_other): + """Return True if two sets have a null intersection.""" + + if isinstance(w_other, W_BaseSetObject): + return space.newbool(self.isdisjoint(w_other)) + + #XXX may be optimized when other strategies are added + for w_key in space.listview(w_other): + if self.has_key(w_key): + return space.w_False + return space.w_True + + def descr_add(self, space, w_other): + """Add an element to a set. + + This has no effect if the element is already present.""" + self.add(w_other) + + def descr_clear(self, space): + """Remove all elements from this set.""" + self.clear() + + @gateway.unwrap_spec(others_w='args_w') + def descr_difference_update(self, space, others_w): + """Update the set, removing elements found in others.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.difference_update(w_other) + else: + w_other_as_set = self._newobj(space, w_other) + self.difference_update(w_other_as_set) + + def _discard_from_set(self, space, w_item): + """ + Discard an element from a set, with automatic conversion to + frozenset if the argument is a set. + Returns True if successfully removed. + """ + try: + deleted = self.remove(w_item) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + else: + w_f = _convert_set_to_frozenset(space, w_item) + if w_f is None: + raise + deleted = self.remove(w_f) + + if self.length() == 0: + self.switch_to_empty_strategy() + return deleted + + def descr_discard(self, space, w_item): + """Remove an element from a set if it is a member. + + If the element is not a member, do nothing.""" + self._discard_from_set(space, w_item) + + @gateway.unwrap_spec(others_w='args_w') + def descr_intersection_update(self, space, others_w): + """Update the set, keeping only elements found in it and all others.""" + result = self.descr_intersection(space, others_w) + self.strategy = result.strategy + self.sstorage = result.sstorage + + def descr_pop(self, space): + """Remove and return an arbitrary set element.""" + return self.popitem() + + def descr_remove(self, space, w_item): + """Remove an element from a set; it must be a member. + + If the element is not a member, raise a KeyError.""" + if not self._discard_from_set(space, w_item): + space.raise_key_error(w_item) + + def descr_symmetric_difference_update(self, space, w_other): + """Update a set with the symmetric difference of itself and another.""" + if isinstance(w_other, W_BaseSetObject): + self.symmetric_difference_update(w_other) + return + w_other_as_set = self._newobj(space, w_other) + self.symmetric_difference_update(w_other_as_set) + + @gateway.unwrap_spec(others_w='args_w') + def descr_update(self, space, others_w): + """Update a set with the union of itself and another.""" + for w_other in others_w: + if isinstance(w_other, W_BaseSetObject): + self.update(w_other) + else: + for w_key in space.listview(w_other): + self.add(w_key) + + class W_SetObject(W_BaseSetObject): - from pypy.objspace.std.settype import set_typedef as typedef - def _newobj(w_self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" if type(w_self) is W_SetObject: @@ -176,8 +510,71 @@ W_SetObject.__init__(w_obj, space, w_iterable) return w_obj + @staticmethod + def descr_new(space, w_settype, __args__): + w_obj = space.allocate_instance(W_SetObject, w_settype) + W_SetObject.__init__(w_obj, space) + return w_obj + +W_SetObject.typedef = StdTypeDef("set", + __doc__ = """set(iterable) --> set object + +Build an unordered collection.""", + __new__ = gateway.interp2app(W_SetObject.descr_new), + __init__ = gateway.interp2app(W_BaseSetObject.descr_init), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), + __hash__ = None, + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), + + # mutating operators + __isub__ = gateway.interp2app(W_BaseSetObject.descr_inplace_sub), + __iand__ = gateway.interp2app(W_BaseSetObject.descr_inplace_and), + __ior__ = gateway.interp2app(W_BaseSetObject.descr_inplace_or), + __ixor__ = gateway.interp2app(W_BaseSetObject.descr_inplace_xor), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint), + + # mutating methods + add = gateway.interp2app(W_BaseSetObject.descr_add), + clear = gateway.interp2app(W_BaseSetObject.descr_clear), + difference_update = gateway.interp2app(W_BaseSetObject.descr_difference_update), + discard = gateway.interp2app(W_BaseSetObject.descr_discard), + intersection_update = gateway.interp2app(W_BaseSetObject.descr_intersection_update), + pop = gateway.interp2app(W_BaseSetObject.descr_pop), + remove = gateway.interp2app(W_BaseSetObject.descr_remove), + symmetric_difference_update = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference_update), + update = gateway.interp2app(W_BaseSetObject.descr_update) + ) +set_typedef = W_SetObject.typedef + + class W_FrozensetObject(W_BaseSetObject): - from pypy.objspace.std.frozensettype import frozenset_typedef as typedef hash = 0 def _newobj(w_self, space, w_iterable): @@ -189,9 +586,77 @@ W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj -registerimplementation(W_BaseSetObject) -registerimplementation(W_SetObject) -registerimplementation(W_FrozensetObject) + @staticmethod + def descr_new2(space, w_frozensettype, w_iterable=None): + if (space.is_w(w_frozensettype, space.w_frozenset) and + w_iterable is not None and type(w_iterable) is W_FrozensetObject): + return w_iterable + w_obj = space.allocate_instance(W_FrozensetObject, w_frozensettype) + W_FrozensetObject.__init__(w_obj, space, w_iterable) + return w_obj + + def descr_hash(self, space): + multi = r_uint(1822399083) + r_uint(1822399083) + 1 + if self.hash != 0: + return space.wrap(self.hash) + hash = r_uint(1927868237) + hash *= r_uint(self.length() + 1) + w_iterator = self.iter() + while True: + w_item = w_iterator.next_entry() + if w_item is None: + break + h = space.hash_w(w_item) + value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) + hash = hash ^ value + hash = hash * 69069 + 907133923 + if hash == 0: + hash = 590923713 + hash = intmask(hash) + self.hash = hash + + return space.wrap(hash) + +W_FrozensetObject.typedef = StdTypeDef("frozenset", + __doc__ = """frozenset(iterable) --> frozenset object + +Build an immutable unordered collection.""", + __new__ = gateway.interp2app(W_FrozensetObject.descr_new2), + __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr), + __hash__ = gateway.interp2app(W_FrozensetObject.descr_hash), + __cmp__ = gateway.interp2app(W_BaseSetObject.descr_cmp), + + # comparison operators + __eq__ = gateway.interp2app(W_BaseSetObject.descr_eq), + __ne__ = gateway.interp2app(W_BaseSetObject.descr_ne), + __lt__ = gateway.interp2app(W_BaseSetObject.descr_lt), + __le__ = gateway.interp2app(W_BaseSetObject.descr_le), + __gt__ = gateway.interp2app(W_BaseSetObject.descr_gt), + __ge__ = gateway.interp2app(W_BaseSetObject.descr_ge), + + # non-mutating operators + __len__ = gateway.interp2app(W_BaseSetObject.descr_len), + __iter__ = gateway.interp2app(W_BaseSetObject.descr_iter), + __contains__ = gateway.interp2app(W_BaseSetObject.descr_contains), + __sub__ = gateway.interp2app(W_BaseSetObject.descr_sub), + __and__ = gateway.interp2app(W_BaseSetObject.descr_and), + __or__ = gateway.interp2app(W_BaseSetObject.descr_or), + __xor__ = gateway.interp2app(W_BaseSetObject.descr_xor), + + # non-mutating methods + __reduce__ = gateway.interp2app(W_BaseSetObject.descr_reduce), + copy = gateway.interp2app(W_BaseSetObject.descr_copy), + difference = gateway.interp2app(W_BaseSetObject.descr_difference), + intersection = gateway.interp2app(W_BaseSetObject.descr_intersection), + issubset = gateway.interp2app(W_BaseSetObject.descr_issubset), + issuperset = gateway.interp2app(W_BaseSetObject.descr_issuperset), + symmetric_difference = gateway.interp2app(W_BaseSetObject.descr_symmetric_difference), + union = gateway.interp2app(W_BaseSetObject.descr_union), + isdisjoint = gateway.interp2app(W_BaseSetObject.descr_isdisjoint) + ) +frozenset_typedef = W_FrozensetObject.typedef + + class SetStrategy(object): def __init__(self, space): @@ -285,8 +750,8 @@ def popitem(self, w_set): raise NotImplementedError + class EmptySetStrategy(SetStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -377,6 +842,7 @@ raise OperationError(self.space.w_KeyError, self.space.wrap('pop from an empty set')) + class AbstractUnwrappedSetStrategy(object): _mixin_ = True @@ -432,7 +898,6 @@ w_set.add(w_key) def remove(self, w_set, w_item): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string d = self.unerase(w_set.sstorage) if not self.is_correct_type(w_item): #XXX check type of w_item and immediately return False in some cases @@ -464,7 +929,6 @@ return keys_w def has_key(self, w_set, w_key): - from pypy.objspace.std.dictmultiobject import _never_equal_to_string if not self.is_correct_type(w_key): #XXX check type of w_item and immediately return False in some cases w_set.switch_to_object_strategy(self.space) @@ -718,6 +1182,7 @@ self.space.wrap('pop from an empty set')) return self.wrap(result[0]) + class StringSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) @@ -801,7 +1266,6 @@ return self.unerase(w_set.sstorage).keys() def is_correct_type(self, w_key): - from pypy.objspace.std.intobject import W_IntObject return type(w_key) is W_IntObject def may_contain_equal_elements(self, strategy): @@ -822,6 +1286,7 @@ def iter(self, w_set): return IntegerIteratorImplementation(self.space, self, w_set) + class ObjectSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy): erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) @@ -866,6 +1331,7 @@ break d_obj[w_item] = None + class IteratorImplementation(object): def __init__(self, space, strategy, implementation): self.space = space @@ -910,6 +1376,7 @@ return self.len - self.pos return 0 + class EmptyIteratorImplementation(IteratorImplementation): def next_entry(self): return None @@ -927,6 +1394,7 @@ else: return None + class UnicodeIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -939,6 +1407,7 @@ else: return None + class IntegerIteratorImplementation(IteratorImplementation): #XXX same implementation in dictmultiobject on dictstrategy-branch def __init__(self, space, strategy, w_set): @@ -953,6 +1422,7 @@ else: return None + class RDictIteratorImplementation(IteratorImplementation): def __init__(self, space, strategy, w_set): IteratorImplementation.__init__(self, space, strategy, w_set) @@ -966,26 +1436,34 @@ else: return None -class W_SetIterObject(W_Object): - from pypy.objspace.std.settype import setiter_typedef as typedef - # XXX this class should be killed, and the various - # iterimplementations should be W_Objects directly. + +class W_SetIterObject(W_Root): def __init__(w_self, space, iterimplementation): w_self.space = space w_self.iterimplementation = iterimplementation -registerimplementation(W_SetIterObject) + def descr_length_hint(self, space): + return space.wrap(self.iterimplementation.length()) -def iter__SetIterObject(space, w_setiter): - return w_setiter + def descr_iter(self, space): + return self -def next__SetIterObject(space, w_setiter): - iterimplementation = w_setiter.iterimplementation - w_key = iterimplementation.next() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) + def descr_next(self, space): + iterimplementation = self.iterimplementation + w_key = iterimplementation.next() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) + +W_SetIterObject.typedef = StdTypeDef("setiterator", + __length_hint__ = gateway.interp2app(W_SetIterObject.descr_length_hint), + __iter__ = gateway.interp2app(W_SetIterObject.descr_iter), + next = gateway.interp2app(W_SetIterObject.descr_next) + ) +setiter_typedef = W_SetIterObject.typedef + + # some helper functions @@ -993,7 +1471,6 @@ return r_dict(space.eq_w, space.hash_w, force_non_null=True) def set_strategy_and_setdata(space, w_set, w_iterable): - from pypy.objspace.std.intobject import W_IntObject if w_iterable is None : w_set.strategy = strategy = space.fromcache(EmptySetStrategy) w_set.sstorage = strategy.get_empty_storage() @@ -1067,6 +1544,8 @@ w_set.strategy = space.fromcache(ObjectSetStrategy) w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w) +init_signature = Signature(['some_iterable'], None, None) +init_defaults = [None] def _initialize_set(space, w_obj, w_iterable=None): w_obj.clear() set_strategy_and_setdata(space, w_obj, w_iterable) @@ -1084,424 +1563,6 @@ else: return None -def set_update__Set(space, w_left, others_w): - """Update a set with the union of itself and another.""" - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - w_left.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - w_left.add(w_key) - -def inplace_or__Set_Set(space, w_left, w_other): - w_left.update(w_other) - return w_left - -inplace_or__Set_Frozenset = inplace_or__Set_Set - -def set_add__Set_ANY(space, w_left, w_other): - """Add an element to a set. - - This has no effect if the element is already present. - """ - w_left.add(w_other) - -def set_copy__Set(space, w_set): - return w_set.copy_real() - -def frozenset_copy__Frozenset(space, w_left): - if type(w_left) is W_FrozensetObject: - return w_left - else: - return set_copy__Set(space, w_left) - -def set_clear__Set(space, w_left): - w_left.clear() - -def sub__Set_Set(space, w_left, w_other): - return w_left.difference(w_other) - -sub__Set_Frozenset = sub__Set_Set -sub__Frozenset_Set = sub__Set_Set -sub__Frozenset_Frozenset = sub__Set_Set - -def set_difference__Set(space, w_left, others_w): - result = w_left.copy_real() - set_difference_update__Set(space, result, others_w) - return result - -frozenset_difference__Frozenset = set_difference__Set - - -def set_difference_update__Set(space, w_left, others_w): - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - # optimization only - w_left.difference_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - w_left.difference_update(w_other_as_set) - -def inplace_sub__Set_Set(space, w_left, w_other): - w_left.difference_update(w_other) - return w_left - -inplace_sub__Set_Frozenset = inplace_sub__Set_Set - -def eq__Set_Set(space, w_left, w_other): - # optimization only (the general case is eq__Set_settypedef) - return space.wrap(w_left.equals(w_other)) - -eq__Set_Frozenset = eq__Set_Set -eq__Frozenset_Frozenset = eq__Set_Set -eq__Frozenset_Set = eq__Set_Set - -def eq__Set_settypedef(space, w_left, w_other): - # tested in test_buildinshortcut.py - #XXX do not make new setobject here - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(w_left.equals(w_other_as_set)) - -eq__Set_frozensettypedef = eq__Set_settypedef -eq__Frozenset_settypedef = eq__Set_settypedef -eq__Frozenset_frozensettypedef = eq__Set_settypedef - -def eq__Set_ANY(space, w_left, w_other): - # workaround to have "set() == 42" return False instead of falling - # back to cmp(set(), 42) because the latter raises a TypeError - return space.w_False - -eq__Frozenset_ANY = eq__Set_ANY - -def ne__Set_Set(space, w_left, w_other): - return space.wrap(not w_left.equals(w_other)) - -ne__Set_Frozenset = ne__Set_Set -ne__Frozenset_Frozenset = ne__Set_Set -ne__Frozenset_Set = ne__Set_Set - -def ne__Set_settypedef(space, w_left, w_other): - #XXX this is not tested - w_other_as_set = w_left._newobj(space, w_other) - return space.wrap(not w_left.equals(w_other_as_set)) - -ne__Set_frozensettypedef = ne__Set_settypedef -ne__Frozenset_settypedef = ne__Set_settypedef -ne__Frozenset_frozensettypedef = ne__Set_settypedef - - -def ne__Set_ANY(space, w_left, w_other): - # more workarounds - return space.w_True - -ne__Frozenset_ANY = ne__Set_ANY - -def contains__Set_ANY(space, w_left, w_other): - try: - return space.newbool(w_left.has_key(w_other)) - except OperationError, e: - if e.match(space, space.w_TypeError): - w_f = _convert_set_to_frozenset(space, w_other) - if w_f is not None: - return space.newbool(w_left.has_key(w_f)) - raise - -contains__Frozenset_ANY = contains__Set_ANY - -def set_issubset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() > w_other.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other)) - -set_issubset__Set_Frozenset = set_issubset__Set_Set -frozenset_issubset__Frozenset_Set = set_issubset__Set_Set -frozenset_issubset__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issubset__Set_ANY(space, w_left, w_other): - # not checking whether w_left is w_other here, because if that were the - # case the more precise multimethod would have applied. - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() > w_other_as_set.length(): - return space.w_False - return space.wrap(w_left.issubset(w_other_as_set)) - -frozenset_issubset__Frozenset_ANY = set_issubset__Set_ANY - -le__Set_Set = set_issubset__Set_Set -le__Set_Frozenset = set_issubset__Set_Set -le__Frozenset_Set = set_issubset__Set_Set -le__Frozenset_Frozenset = set_issubset__Set_Set - -def set_issuperset__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - if space.is_w(w_left, w_other): - return space.w_True - if w_left.length() < w_other.length(): - return space.w_False - return space.wrap(w_other.issubset(w_left)) - -set_issuperset__Set_Frozenset = set_issuperset__Set_Set -set_issuperset__Frozenset_Set = set_issuperset__Set_Set -set_issuperset__Frozenset_Frozenset = set_issuperset__Set_Set - -def set_issuperset__Set_ANY(space, w_left, w_other): - if space.is_w(w_left, w_other): - return space.w_True - - w_other_as_set = w_left._newobj(space, w_other) - - if w_left.length() < w_other_as_set.length(): - return space.w_False - return space.wrap(w_other_as_set.issubset(w_left)) - -frozenset_issuperset__Frozenset_ANY = set_issuperset__Set_ANY - -ge__Set_Set = set_issuperset__Set_Set -ge__Set_Frozenset = set_issuperset__Set_Set -ge__Frozenset_Set = set_issuperset__Set_Set -ge__Frozenset_Frozenset = set_issuperset__Set_Set - -# automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the -# correct answer here! -def lt__Set_Set(space, w_left, w_other): - if w_left.length() >= w_other.length(): - return space.w_False - else: - return le__Set_Set(space, w_left, w_other) - -lt__Set_Frozenset = lt__Set_Set -lt__Frozenset_Set = lt__Set_Set -lt__Frozenset_Frozenset = lt__Set_Set - -def gt__Set_Set(space, w_left, w_other): - if w_left.length() <= w_other.length(): - return space.w_False - else: - return ge__Set_Set(space, w_left, w_other) - -gt__Set_Frozenset = gt__Set_Set -gt__Frozenset_Set = gt__Set_Set -gt__Frozenset_Frozenset = gt__Set_Set - -def _discard_from_set(space, w_left, w_item): - """ - Discard an element from a set, with automatic conversion to - frozenset if the argument is a set. - Returns True if successfully removed. - """ - try: - deleted = w_left.remove(w_item) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - else: - w_f = _convert_set_to_frozenset(space, w_item) - if w_f is None: - raise - deleted = w_left.remove(w_f) - - if w_left.length() == 0: - w_left.switch_to_empty_strategy() - return deleted - -def set_discard__Set_ANY(space, w_left, w_item): - _discard_from_set(space, w_left, w_item) - -def set_remove__Set_ANY(space, w_left, w_item): - if not _discard_from_set(space, w_left, w_item): - space.raise_key_error(w_item) - -def hash__Frozenset(space, w_set): - multi = r_uint(1822399083) + r_uint(1822399083) + 1 - if w_set.hash != 0: - return space.wrap(w_set.hash) - hash = r_uint(1927868237) - hash *= r_uint(w_set.length() + 1) - w_iterator = w_set.iter() - while True: - w_item = w_iterator.next_entry() - if w_item is None: - break - h = space.hash_w(w_item) - value = (r_uint(h ^ (h << 16) ^ 89869747) * multi) - hash = hash ^ value - hash = hash * 69069 + 907133923 - if hash == 0: - hash = 590923713 - hash = intmask(hash) - w_set.hash = hash - - return space.wrap(hash) - -def set_pop__Set(space, w_left): - return w_left.popitem() - -def and__Set_Set(space, w_left, w_other): - new_set = w_left.intersect(w_other) - return new_set - -and__Set_Frozenset = and__Set_Set -and__Frozenset_Set = and__Set_Set -and__Frozenset_Frozenset = and__Set_Set - -def set_intersection__Set(space, w_left, others_w): - #XXX find smarter implementations - others_w = [w_left] + others_w - - # find smallest set in others_w to reduce comparisons - startindex, startlength = 0, -1 - for i in range(len(others_w)): - w_other = others_w[i] - try: - length = space.int_w(space.len(w_other)) - except OperationError, e: - if (e.match(space, space.w_TypeError) or - e.match(space, space.w_AttributeError)): - continue - raise - - if startlength == -1 or length < startlength: - startindex = i - startlength = length - - others_w[startindex], others_w[0] = others_w[0], others_w[startindex] - - result = w_left._newobj(space, others_w[0]) - for i in range(1,len(others_w)): - w_other = others_w[i] - if isinstance(w_other, W_BaseSetObject): - # optimization only - result.intersect_update(w_other) - else: - w_other_as_set = w_left._newobj(space, w_other) - result.intersect_update(w_other_as_set) - return result - -frozenset_intersection__Frozenset = set_intersection__Set - -def set_intersection_update__Set(space, w_left, others_w): - result = set_intersection__Set(space, w_left, others_w) - w_left.strategy = result.strategy - w_left.sstorage = result.sstorage - return - -def inplace_and__Set_Set(space, w_left, w_other): - w_left.intersect_update(w_other) - return w_left - -inplace_and__Set_Frozenset = inplace_and__Set_Set - -def set_isdisjoint__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - return space.newbool(w_left.isdisjoint(w_other)) - -set_isdisjoint__Set_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Frozenset = set_isdisjoint__Set_Set -set_isdisjoint__Frozenset_Set = set_isdisjoint__Set_Set - -def set_isdisjoint__Set_ANY(space, w_left, w_other): - #XXX may be optimized when other strategies are added - for w_key in space.listview(w_other): - if w_left.has_key(w_key): - return space.w_False - return space.w_True - -frozenset_isdisjoint__Frozenset_ANY = set_isdisjoint__Set_ANY - -def set_symmetric_difference__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_result = w_left.symmetric_difference(w_other) - return w_result - -set_symmetric_difference__Set_Frozenset = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Set = set_symmetric_difference__Set_Set -set_symmetric_difference__Frozenset_Frozenset = \ - set_symmetric_difference__Set_Set - -xor__Set_Set = set_symmetric_difference__Set_Set -xor__Set_Frozenset = set_symmetric_difference__Set_Set -xor__Frozenset_Set = set_symmetric_difference__Set_Set -xor__Frozenset_Frozenset = set_symmetric_difference__Set_Set - - -def set_symmetric_difference__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_result = w_left.symmetric_difference(w_other_as_set) - return w_result - -frozenset_symmetric_difference__Frozenset_ANY = \ - set_symmetric_difference__Set_ANY - -def set_symmetric_difference_update__Set_Set(space, w_left, w_other): - # optimization only (the general case works too) - w_left.symmetric_difference_update(w_other) - -set_symmetric_difference_update__Set_Frozenset = \ - set_symmetric_difference_update__Set_Set - -def set_symmetric_difference_update__Set_ANY(space, w_left, w_other): - w_other_as_set = w_left._newobj(space, w_other) - w_left.symmetric_difference_update(w_other_as_set) - -def inplace_xor__Set_Set(space, w_left, w_other): - set_symmetric_difference_update__Set_Set(space, w_left, w_other) - return w_left - -inplace_xor__Set_Frozenset = inplace_xor__Set_Set - -def or__Set_Set(space, w_left, w_other): - w_copy = w_left.copy_real() - w_copy.update(w_other) - return w_copy - -or__Set_Frozenset = or__Set_Set -or__Frozenset_Set = or__Set_Set -or__Frozenset_Frozenset = or__Set_Set - -def set_union__Set(space, w_left, others_w): - result = w_left.copy_real() - for w_other in others_w: - if isinstance(w_other, W_BaseSetObject): - result.update(w_other) # optimization only - else: - for w_key in space.listview(w_other): - result.add(w_key) - return result - -frozenset_union__Frozenset = set_union__Set - -def len__Set(space, w_left): - return space.newint(w_left.length()) - -len__Frozenset = len__Set - -def iter__Set(space, w_left): - return W_SetIterObject(space, w_left.iter()) - -iter__Frozenset = iter__Set - -def cmp__Set_settypedef(space, w_left, w_other): - # hack hack until we get the expected result - raise OperationError(space.w_TypeError, - space.wrap('cannot compare sets using cmp()')) - -cmp__Set_frozensettypedef = cmp__Set_settypedef -cmp__Frozenset_settypedef = cmp__Set_settypedef -cmp__Frozenset_frozensettypedef = cmp__Set_settypedef - -init_signature = Signature(['some_iterable'], None, None) -init_defaults = [None] -def init__Set(space, w_set, __args__): - w_iterable, = __args__.parse_obj( - None, 'set', - init_signature, - init_defaults) - _initialize_set(space, w_set, w_iterable) app = gateway.applevel(""" def setrepr(currently_in_repr, s): @@ -1521,26 +1582,11 @@ setrepr = app.interphook("setrepr") -def repr__Set(space, w_set): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return setrepr(space, w_currently_in_repr, w_set) - -repr__Frozenset = repr__Set - app = gateway.applevel(""" - def reduce__Set(s): + def setreduce(s): dict = getattr(s,'__dict__', None) return (s.__class__, (tuple(s),), dict) """, filename=__file__) -set_reduce__Set = app.interphook('reduce__Set') -frozenset_reduce__Frozenset = app.interphook('reduce__Set') - -from pypy.objspace.std import frozensettype -from pypy.objspace.std import settype - -register_all(vars(), settype, frozensettype) +setreduce = app.interphook('setreduce') diff --git a/pypy/objspace/std/settype.py b/pypy/objspace/std/settype.py deleted file mode 100644 --- a/pypy/objspace/std/settype.py +++ /dev/null @@ -1,91 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -set_add = SMM('add', 2, - doc='Add an element to a set.\n\nThis' - ' has no effect if the element is' - ' already present.') -set_clear = SMM('clear', 1, - doc='Remove all elements from this set.') -set_copy = SMM('copy', 1, - doc='Return a shallow copy of a set.') -set_difference = SMM('difference', 1, varargs_w=True, - doc='Return a new set with elements in' - ' the set that are not in the others.') -set_difference_update = SMM('difference_update', 1, varargs_w=True, - doc='Update the set, removing elements' - ' found in others.') -set_discard = SMM('discard', 2, - doc='Remove an element from a set if it' - ' is a member.\n\nIf the element is' - ' not a member, do nothing.') -set_intersection = SMM('intersection', 1, varargs_w=True, - doc='Return a new set with elements common' - ' to the set and all others.') -set_intersection_update = SMM('intersection_update', 1, varargs_w=True, - doc='Update the set, keeping only elements' - ' found in it and all others.') -set_issubset = SMM('issubset', 2, - doc='Report whether another set contains' - ' this set.') -set_issuperset = SMM('issuperset', 2, - doc='Report whether this set contains' - ' another set.') -set_pop = SMM('pop', 1, - doc='Remove and return an arbitrary set' - ' element.') -set_remove = SMM('remove', 2, - doc='Remove an element from a set; it' - ' must be a member.\n\nIf the' - ' element is not a member, raise a' - ' KeyError.') -set_symmetric_difference = SMM('symmetric_difference', 2, - doc='Return the symmetric difference of' - ' two sets as a new set.\n\n(i.e.' - ' all elements that are in exactly' - ' one of the sets.)') -set_symmetric_difference_update = SMM('symmetric_difference_update', 2, - doc='Update a set with the symmetric' - ' difference of itself and another.') -set_union = SMM('union', 1, varargs_w=True, - doc='Return a new set with elements' - ' from the set and all others.') -set_update = SMM('update', 1, varargs_w=True, - doc='Update the set, adding elements' - ' from all others.') -set_reduce = SMM('__reduce__',1, - doc='Return state information for' - ' pickling.') -# 2.6 methods -set_isdisjoint = SMM('isdisjoint', 2, - doc='Return True if two sets have a' - ' null intersection.') - -register_all(vars(), globals()) - -def descr__new__(space, w_settype, __args__): - from pypy.objspace.std.setobject import W_SetObject, newset - w_obj = space.allocate_instance(W_SetObject, w_settype) - W_SetObject.__init__(w_obj, space) - return w_obj - -set_typedef = StdTypeDef("set", - __doc__ = """set(iterable) --> set object - -Build an unordered collection.""", - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - ) - -set_typedef.registermethods(globals()) - -def descr_setiterator__length_hint__(space, w_self): - from pypy.objspace.std.setobject import W_SetIterObject - assert isinstance(w_self, W_SetIterObject) - return space.wrap(w_self.iterimplementation.length()) - -setiter_typedef = StdTypeDef("setiterator", - __length_hint__ = gateway.interp2app(descr_setiterator__length_hint__), - ) diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -12,9 +12,6 @@ from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject, IntegerSetStrategy from pypy.objspace.std.setobject import _initialize_set from pypy.objspace.std.setobject import newset -from pypy.objspace.std.setobject import and__Set_Set -from pypy.objspace.std.setobject import set_intersection__Set -from pypy.objspace.std.setobject import eq__Set_Set from pypy.objspace.std.listobject import W_ListObject letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' @@ -36,11 +33,11 @@ t0 = W_SetObject(self.space) _initialize_set(self.space, t0, self.otherword) t1 = W_FrozensetObject(self.space, self.otherword) - r0 = and__Set_Set(self.space, s, t0) - r1 = and__Set_Set(self.space, s, t1) - assert eq__Set_Set(self.space, r0, r1) == self.true - sr = set_intersection__Set(self.space, s, [self.otherword]) - assert eq__Set_Set(self.space, r0, sr) == self.true + r0 = s.descr_and(self.space, t0) + r1 = s.descr_and(self.space, t1) + assert r0.descr_eq(self.space, r1) == self.true + sr = s.descr_intersection(self.space, [self.otherword]) + assert r0.descr_eq(self.space, sr) == self.true def test_compare(self): s = W_SetObject(self.space) @@ -66,7 +63,7 @@ b = W_SetObject(self.space) _initialize_set(self.space, b, self.space.wrap("abc")) - result = set_intersection__Set(space, a, [b]) + result = a.descr_intersection(space, [b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("abc")))) c = W_SetObject(self.space) @@ -80,7 +77,7 @@ b.get_storage_copy = None d.get_storage_copy = None - result = set_intersection__Set(space, a, [d,c,b]) + result = a.descr_intersection(space, [d,c,b]) assert space.is_true(self.space.eq(result, W_SetObject(space, self.space.wrap("")))) def test_create_set_from_list(self): diff --git a/pypy/objspace/std/test/test_setstrategies.py b/pypy/objspace/std/test/test_setstrategies.py --- a/pypy/objspace/std/test/test_setstrategies.py +++ b/pypy/objspace/std/test/test_setstrategies.py @@ -65,18 +65,16 @@ assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_remove(self): - from pypy.objspace.std.setobject import set_remove__Set_ANY s1 = W_SetObject(self.space, self.wrapped([1])) - set_remove__Set_ANY(self.space, s1, self.space.wrap(1)) + self.space.call_method(s1, 'remove', self.space.wrap(1)) assert s1.strategy is self.space.fromcache(EmptySetStrategy) def test_union(self): - from pypy.objspace.std.setobject import set_union__Set s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) s2 = W_SetObject(self.space, self.wrapped([4,5,6,7])) s3 = W_SetObject(self.space, self.wrapped([4,'5','6',7])) - s4 = set_union__Set(self.space, s1, [s2]) - s5 = set_union__Set(self.space, s1, [s3]) + s4 = s1.descr_union(self.space, [s2]) + s5 = s1.descr_union(self.space, [s3]) assert s4.strategy is self.space.fromcache(IntegerSetStrategy) assert s5.strategy is self.space.fromcache(ObjectSetStrategy) @@ -91,10 +89,8 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) - set_discard__Set_ANY(self.space, s1, self.space.wrap("five")) + s1.descr_discard(self.space, self.space.wrap("five")) skip("currently not supported") assert s1.strategy is self.space.fromcache(IntegerSetStrategy) @@ -112,8 +108,6 @@ return True return False - from pypy.objspace.std.setobject import set_discard__Set_ANY - s1 = W_SetObject(self.space, self.wrapped([1,2,3,4,5])) assert not s1.has_key(self.space.wrap("five")) skip("currently not supported") diff --git a/rpython/jit/backend/x86/test/test_del.py b/rpython/jit/backend/arm/test/test_del.py copy from rpython/jit/backend/x86/test/test_del.py copy to rpython/jit/backend/arm/test/test_del.py --- a/rpython/jit/backend/x86/test/test_del.py +++ b/rpython/jit/backend/arm/test/test_del.py @@ -1,8 +1,8 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_del import DelTests -class TestDel(Jit386Mixin, DelTests): +class TestDel(JitARMMixin, DelTests): # for the individual tests see # ====> ../../../metainterp/test/test_del.py pass diff --git a/rpython/jit/backend/x86/test/test_dict.py b/rpython/jit/backend/arm/test/test_dict.py copy from rpython/jit/backend/x86/test/test_dict.py copy to rpython/jit/backend/arm/test/test_dict.py --- a/rpython/jit/backend/x86/test/test_dict.py +++ b/rpython/jit/backend/arm/test/test_dict.py @@ -1,9 +1,9 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_dict import DictTests -class TestDict(Jit386Mixin, DictTests): +class TestDict(JitARMMixin, DictTests): # for the individual tests see # ====> ../../../metainterp/test/test_dict.py pass diff --git a/rpython/jit/backend/x86/test/test_quasiimmut.py b/rpython/jit/backend/arm/test/test_quasiimmut.py copy from rpython/jit/backend/x86/test/test_quasiimmut.py copy to rpython/jit/backend/arm/test/test_quasiimmut.py --- a/rpython/jit/backend/x86/test/test_quasiimmut.py +++ b/rpython/jit/backend/arm/test/test_quasiimmut.py @@ -1,9 +1,9 @@ import py -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test import test_quasiimmut -class TestLoopSpec(Jit386Mixin, test_quasiimmut.QuasiImmutTests): +class TestLoopSpec(JitARMMixin, test_quasiimmut.QuasiImmutTests): # for the individual tests see # ====> ../../../metainterp/test/test_loop.py pass diff --git a/rpython/jit/backend/x86/test/test_rawmem.py b/rpython/jit/backend/arm/test/test_rawmem.py copy from rpython/jit/backend/x86/test/test_rawmem.py copy to rpython/jit/backend/arm/test/test_rawmem.py --- a/rpython/jit/backend/x86/test/test_rawmem.py +++ b/rpython/jit/backend/arm/test/test_rawmem.py @@ -1,9 +1,9 @@ -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.jit.metainterp.test.test_rawmem import RawMemTests -class TestRawMem(Jit386Mixin, RawMemTests): +class TestRawMem(JitARMMixin, RawMemTests): # for the individual tests see # ====> ../../../metainterp/test/test_rawmem.py pass diff --git a/rpython/jit/backend/x86/test/test_send.py b/rpython/jit/backend/arm/test/test_send.py copy from rpython/jit/backend/x86/test/test_send.py copy to rpython/jit/backend/arm/test/test_send.py --- a/rpython/jit/backend/x86/test/test_send.py +++ b/rpython/jit/backend/arm/test/test_send.py @@ -1,10 +1,10 @@ import py from rpython.jit.metainterp.test.test_send import SendTests -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin from rpython.rlib import jit -class TestSend(Jit386Mixin, SendTests): +class TestSend(JitARMMixin, SendTests): # for the individual tests see # ====> ../../../metainterp/test/test_send.py def test_call_with_additional_args(self): diff --git a/rpython/jit/backend/x86/test/test_slist.py b/rpython/jit/backend/arm/test/test_slist.py copy from rpython/jit/backend/x86/test/test_slist.py copy to rpython/jit/backend/arm/test/test_slist.py --- a/rpython/jit/backend/x86/test/test_slist.py +++ b/rpython/jit/backend/arm/test/test_slist.py @@ -1,8 +1,8 @@ import py from rpython.jit.metainterp.test import test_slist -from rpython.jit.backend.x86.test.test_basic import Jit386Mixin +from rpython.jit.backend.arm.test.support import JitARMMixin -class TestSList(Jit386Mixin, test_slist.ListTests): +class TestSList(JitARMMixin, test_slist.ListTests): # for the individual tests see # ====> ../../../metainterp/test/test_slist.py def test_list_of_voids(self): diff --git a/rpython/jit/backend/x86/test/test_tl.py b/rpython/jit/backend/arm/test/test_tl.py copy from rpython/jit/backend/x86/test/test_tl.py copy to rpython/jit/backend/arm/test/test_tl.py From noreply at buildbot.pypy.org Wed May 15 21:14:48 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 15 May 2013 21:14:48 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove dict from multi-method table. Message-ID: <20130515191448.E7BDD1C1106@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64200:fb15279ae6e2 Date: 2013-05-15 21:12 +0200 http://bitbucket.org/pypy/pypy/changeset/fb15279ae6e2/ Log: Remove dict from multi-method table. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,8 +1,8 @@ from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature -from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.stdtypedef import StdTypeDef from rpython.rlib import rerased, jit @@ -40,7 +40,7 @@ w_dct.length() <= UNROLL_CUTOFF) -class W_DictMultiObject(W_Object): +class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, strdict=False, kwargs=False): @@ -414,9 +414,6 @@ setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), update = gateway.interp2app(W_DictMultiObject.descr_update), ) -dict_typedef = W_DictMultiObject.typedef - -registerimplementation(W_DictMultiObject) class DictStrategy(object): @@ -1106,7 +1103,7 @@ # ____________________________________________________________ # Iteration -class W_BaseDictMultiIterObject(W_Object): +class W_BaseDictMultiIterObject(W_Root): _immutable_fields_ = ["iteratorimplementation"] ignore_for_isinstance_cache = True @@ -1203,10 +1200,6 @@ return space.newtuple([w_key, w_value]) raise OperationError(space.w_StopIteration, space.w_None) -registerimplementation(W_DictMultiIterKeysObject) -registerimplementation(W_DictMultiIterValuesObject) -registerimplementation(W_DictMultiIterItemsObject) - W_DictMultiIterItemsObject.typedef = StdTypeDef( "dict_iteritems", __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), @@ -1229,7 +1222,7 @@ # ____________________________________________________________ # Views -class W_DictViewObject(W_Object): +class W_DictViewObject(W_Root): def __init__(w_self, space, w_dict): w_self.w_dict = w_dict @@ -1276,17 +1269,14 @@ class W_DictViewItemsObject(W_DictViewObject): def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) -registerimplementation(W_DictViewItemsObject) class W_DictViewKeysObject(W_DictViewObject): def descr_iter(self, space): return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) -registerimplementation(W_DictViewKeysObject) class W_DictViewValuesObject(W_DictViewObject): def descr_iter(self, space): return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) -registerimplementation(W_DictViewValuesObject) W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -40,7 +40,6 @@ from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef - from pypy.objspace.std.dictmultiobject import dict_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -81,6 +80,7 @@ # not-multimethod based types + self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -92,10 +92,6 @@ floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], listobject.W_ListObject: [], - dictmultiobject.W_DictMultiObject: [], - dictmultiobject.W_DictMultiIterKeysObject: [], - dictmultiobject.W_DictMultiIterValuesObject: [], - dictmultiobject.W_DictMultiIterItemsObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -108,9 +104,6 @@ iterobject.W_FastTupleIterObject: [], iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], - dictmultiobject.W_DictViewKeysObject: [], - dictmultiobject.W_DictViewItemsObject: [], - dictmultiobject.W_DictViewValuesObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], } From noreply at buildbot.pypy.org Wed May 15 21:19:55 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 21:19:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Attempt to fix stacklet+thread+asmgcc+callbacks: the ordering Message-ID: <20130515191955.176BC1C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64201:ba2ad0ee741f Date: 2013-05-15 21:16 +0200 http://bitbucket.org/pypy/pypy/changeset/ba2ad0ee741f/ Log: Attempt to fix stacklet+thread+asmgcc+callbacks: the ordering was wrong, causing self.belongs_to_current_thread to resolve too early as the constant "lambda:True". diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -331,6 +331,11 @@ [annmodel.SomeInteger(), annmodel.SomeAddress()], annmodel.s_None) + # + # check that the order of the need_*() is correct for us: if we + # need both threads and stacklets, need_thread_support() must be + # called first, to initialize self.belongs_to_current_thread. + assert not hasattr(self, 'gc_detach_callback_pieces_ptr') def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -236,9 +236,10 @@ # thread support if translator.config.translation.continuation: root_walker.stacklet_support = True - root_walker.need_stacklet_support(self, getfn) if translator.config.translation.thread: root_walker.need_thread_support(self, getfn) + if root_walker.stacklet_support: + root_walker.need_stacklet_support(self, getfn) self.layoutbuilder.encode_type_shapes_now() From noreply at buildbot.pypy.org Wed May 15 21:19:56 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 21:19:56 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Attempt to fix stacklet+thread+asmgcc+callbacks: the ordering Message-ID: <20130515191956.4F4BB1C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64202:4aa84f3d3965 Date: 2013-05-15 21:16 +0200 http://bitbucket.org/pypy/pypy/changeset/4aa84f3d3965/ Log: Attempt to fix stacklet+thread+asmgcc+callbacks: the ordering was wrong, causing self.belongs_to_current_thread to resolve too early as the constant "lambda:True". diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -331,6 +331,11 @@ [annmodel.SomeInteger(), annmodel.SomeAddress()], annmodel.s_None) + # + # check that the order of the need_*() is correct for us: if we + # need both threads and stacklets, need_thread_support() must be + # called first, to initialize self.belongs_to_current_thread. + assert not hasattr(self, 'gc_detach_callback_pieces_ptr') def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -236,9 +236,10 @@ # thread support if translator.config.translation.continuation: root_walker.stacklet_support = True - root_walker.need_stacklet_support(self, getfn) if translator.config.translation.thread: root_walker.need_thread_support(self, getfn) + if root_walker.stacklet_support: + root_walker.need_stacklet_support(self, getfn) self.layoutbuilder.encode_type_shapes_now() From noreply at buildbot.pypy.org Wed May 15 21:37:26 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 15 May 2013 21:37:26 +0200 (CEST) Subject: [pypy-commit] buildbot default: An essential fix: this lone quote was copied from a Python file, and has Message-ID: <20130515193726.BFF541C1306@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r817:392d4aab1f48 Date: 2013-05-15 21:27 +0200 http://bitbucket.org/pypy/buildbot/changeset/392d4aab1f48/ Log: An essential fix: this lone quote was copied from a Python file, and has lived since then in our html page's section. At least firefox prints it anyway. diff --git a/master/templates/summary.html b/master/templates/summary.html --- a/master/templates/summary.html +++ b/master/templates/summary.html @@ -1,7 +1,7 @@ {% extends "layout.html" %} {% block morehead %} -' + - diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -15,7 +15,6 @@ - diff --git a/contact.html b/contact.html --- a/contact.html +++ b/contact.html @@ -15,7 +15,6 @@ - diff --git a/css/site.css b/css/site.css --- a/css/site.css +++ b/css/site.css @@ -353,6 +353,7 @@ #menu-follow { float: right; + margin-top: 17px; } #menu-follow div { @@ -379,6 +380,11 @@ font-size: 1em; padding-bottom: 10px; text-align: center; + line-height:1.75em; +} + +#menu-sub a{ + white-space: nowrap; } .menu-sub-sep { diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -15,7 +15,6 @@ - diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -15,7 +15,6 @@ - diff --git a/howtohelp.html b/howtohelp.html --- a/howtohelp.html +++ b/howtohelp.html @@ -15,7 +15,6 @@ - diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -15,7 +15,6 @@ - diff --git a/js/detect.js b/js/detect.js deleted file mode 100644 --- a/js/detect.js +++ /dev/null @@ -1,25 +0,0 @@ - -$(document).ready(function() { - var download_url, download_text; - var base = 'https://bitbucket.org/pypy/pypy/downloads/'; - if (navigator.platform.indexOf('Linux') != -1) { - if (navigator.platform.indexOf('64') != -1) { - download_url = base + 'pypy-1.7-linux64.tar.bz2'; - download_text = 'Download linux x86-64 bin'; - } else { - download_url = base + 'pypy-1.7-linux.tar.bz2'; - download_text = 'Download linux x86 bin (32 bit)'; - } - } else if (navigator.platform.indexOf('Win') != -1) { - download_url = base + 'pypy-1.7-win32.zip'; - download_text = 'Download Windows x86 bin (BETA)'; - } else if (navigator.platform.indexOf('Mac') != 1) { - download_url = base + 'pypy-1.7-osx64.tar.bz2'; - download_text = 'Download Mac OS X 10.6 bin (64 bit)'; - } else { - download_url = "download.html"; - download_text = "Download page"; - } - $("#main_download").attr('href', download_url); - $("#main_download").text(download_text); -}); diff --git a/js/script2.js b/js/script2.js --- a/js/script2.js +++ b/js/script2.js @@ -1,28 +1,21 @@ +function set_sidebar_html(html) { + $("#sidebar").html(html); +} function py3k_donate() { - $.get("don1.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don1.html", set_sidebar_html); } function stm_donate() { - $.get("don4.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don4.html", set_sidebar_html); } function general_donate() { - $.get("don2.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don2.html", set_sidebar_html); } function numpy_donate() { - $.get("don3.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don3.html", set_sidebar_html); } -$(document).ready(function() { - stm_donate(); -}); \ No newline at end of file +$(document).ready(stm_donate); diff --git a/numpydonate.html b/numpydonate.html --- a/numpydonate.html +++ b/numpydonate.html @@ -15,7 +15,6 @@ - diff --git a/people.html b/people.html --- a/people.html +++ b/people.html @@ -15,7 +15,6 @@ - diff --git a/performance.html b/performance.html --- a/performance.html +++ b/performance.html @@ -15,7 +15,6 @@ - diff --git a/py3donate.html b/py3donate.html --- a/py3donate.html +++ b/py3donate.html @@ -15,7 +15,6 @@ - diff --git a/source/_layouts/site.genshi b/source/_layouts/site.genshi --- a/source/_layouts/site.genshi +++ b/source/_layouts/site.genshi @@ -46,7 +46,6 @@ diff --git a/sponsor.html b/sponsor.html --- a/sponsor.html +++ b/sponsor.html @@ -15,7 +15,6 @@ - diff --git a/success.html b/success.html --- a/success.html +++ b/success.html @@ -15,7 +15,6 @@ - diff --git a/tmdonate.html b/tmdonate.html --- a/tmdonate.html +++ b/tmdonate.html @@ -15,7 +15,6 @@ - From noreply at buildbot.pypy.org Thu May 16 18:25:47 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 18:25:47 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: The Windows build is here too. Message-ID: <20130516162547.DDB9F1C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r434:a96b6d915470 Date: 2013-05-16 18:24 +0200 http://bitbucket.org/pypy/pypy.org/changeset/a96b6d915470/ Log: The Windows build is here too. diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -74,7 +74,7 @@ * `Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS)`__ (see ``[1]`` below) * `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ (see ``[1]`` below) * `Mac OS/X binary (64bit)`__ -* Windows binary (32bit) COMING AROUND THE NEXT HOUR (you might need the `VS 2008 runtime library +* `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) * `Source (tar.bz2)`__ * `Source (zip)`__ @@ -82,7 +82,7 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-linux.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-linux64.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-osx64.tar.bz2 -.. disable __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-win32.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-win32.zip .. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-src.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-src.zip @@ -242,7 +242,7 @@ 5c11d727579443d0834caadb4dfe53e3 pypy-2.0.1-linux64.tar.bz2 8d11952e0356ea751321e7d2a1d4f17a pypy-2.0.1-linux.tar.bz2 e666450bcfbd936b016a2dd7312f9853 pypy-2.0.1-osx64.tar.bz2 - f0d051c2b612b64dff496a6c0f3654fb pypy-2.0-win32.zip + 4c40b19ea1ec5c8c8c2a1f94f59bdf02 pypy-2.0.1-win32.zip b9c36b99296c85a590c3e480b05d5a13 pypy-2.0-alpha-arm-armel.tar.bz2 2565ce68b4032eb306d998e722495694 pypy-2.0-alpha-arm-armhf.tar.bz2 b39d98de75f4948bfd2d606a8263ac1f pypy-upstream_2.0~alpha+arm_armhf.deb @@ -254,7 +254,7 @@ cbcd60a78d90caca98fdc2562fc7fcbe76c6e699 pypy-2.0.1-linux64.tar.bz2 a909742d41fb540d9c12ce010bdc7f9e19353fcc pypy-2.0.1-linux.tar.bz2 811fd377ab2eda9233a0c34340f981f9aba1ba9a pypy-2.0.1-osx64.tar.bz2 - cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc pypy-2.0-win32.zip + 0fa90e240648e628c6ac3dfed467f88563897a2a pypy-2.0.1-win32.zip dc09a293b85ab4f0032f6943815aaf5bbbceb645 pypy-2.0-alpha-arm-armel.tar.bz2 0971c4b668bfd2fcd52aa35087aa995e03bd5842 pypy-2.0-alpha-arm-armhf.tar.bz2 91910eb654ffbe0509bec2a7aeb460984acf8d82 pypy-upstream_2.0~alpha+arm_armhf.deb From noreply at buildbot.pypy.org Thu May 16 18:25:49 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 18:25:49 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: regen Message-ID: <20130516162549.02BDF1C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r435:cbe9032f8cde Date: 2013-05-16 18:25 +0200 http://bitbucket.org/pypy/pypy.org/changeset/cbe9032f8cde/ Log: regen diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -50,9 +50,8 @@ performance improvements. Note that the OS X nightly builds (but not the release) are slightly miscompiled due to buildslave being old. Contributions are welcomed.

      -

      Here are the binaries of the current release — PyPy 2.0 — (what's -new in PyPy 2.0?) for x86 Linux, Mac OS/X, Windows. ARM support in -2.0 is alpha-level.

      +

      Here are the binaries of the current release — PyPy 2.0.1 — +(what's new in PyPy 2.0? and fixes of PyPy 2.0.1) for x86 Linux, Mac OS/X, Windows. The support for ARM in 2.0 and 2.0.1 is alpha-level.

      • Download
        • Default (with a JIT Compiler)
        • @@ -70,11 +69,11 @@ x86 CPUs that have the SSE2 instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain stackless extensions, like greenlets. -(This is the official release 2.0; +(This is the official release 2.0.1; for the most up-to-date version see below.)

    -

    2.0

    +

    2.0.1

    Note that Linux binaries are dynamically linked, as is usual, and thus might not be usable due to the sad story of linux binary compatibility. This means that Linux binaries are only usable on the distributions written next to @@ -85,16 +84,16 @@ Fedora, Gentoo and Arch are known to package PyPy, with various degrees of being up-to-date. If you feel like trying a more statically linked binary (which we do not recommend using -in production due to potential future security issues), you can find -32bit Linux and 64bit Linux.

    +in production due to potential future security issues), you can find the +older 32bit Linux and 64bit Linux at an earlier time of release 2.0.

    If your CPU is really old, it may not have SSE2. In this case, you need to translate yourself with the option --jit-backend=x86-without-sse2.

    @@ -141,7 +140,7 @@ uncompressed, they run in-place. For now you can uncompress them either somewhere in your home directory or, say, in /opt, and if you want, put a symlink from somewhere like -/usr/local/bin/pypy to /path/to/pypy-2.0/bin/pypy. Do +/usr/local/bin/pypy to /path/to/pypy-2.0.1/bin/pypy. Do not move or copy the executable pypy outside the tree – put a symlink to it, otherwise it will not find its libraries.

    @@ -151,8 +150,8 @@
  • Get the source code. The following packages contain the source at the same revision as the above binaries:

    Or you can checkout the current trunk using Mercurial (the trunk usually works and is of course more up-to-date):

    @@ -219,28 +218,28 @@

    Checksums

    Here are the checksums for each of the downloads (md5 and sha1):

    -756d738d8f35924357150fe1b6d33f86  pypy-2.0-linux64.tar.bz2
    -267c46ed8c591da19b6091aa90fa9acf  pypy-2.0-linux.tar.bz2
    -39837722da4a03ca03eda187aafa13bb  pypy-2.0-osx64.tar.bz2
    -f0d051c2b612b64dff496a6c0f3654fb  pypy-2.0-win32.zip
    +5c11d727579443d0834caadb4dfe53e3  pypy-2.0.1-linux64.tar.bz2
    +8d11952e0356ea751321e7d2a1d4f17a  pypy-2.0.1-linux.tar.bz2
    +e666450bcfbd936b016a2dd7312f9853  pypy-2.0.1-osx64.tar.bz2
    +4c40b19ea1ec5c8c8c2a1f94f59bdf02  pypy-2.0.1-win32.zip
     b9c36b99296c85a590c3e480b05d5a13  pypy-2.0-alpha-arm-armel.tar.bz2
     2565ce68b4032eb306d998e722495694  pypy-2.0-alpha-arm-armhf.tar.bz2
     b39d98de75f4948bfd2d606a8263ac1f  pypy-upstream_2.0~alpha+arm_armhf.deb
     2c9f0054f3b93a6473f10be35277825a  pypy-1.8-sandbox-linux64.tar.bz2
     009c970b5fa75754ae4c32a5d108a8d4  pypy-1.8-sandbox-linux.tar.bz2
    -4dc82e2240dd2b5be313119672988538  pypy-2.0-src.tar.bz2
    -f965b50bc34c97891af77e6b743038f2  pypy-2.0-src.zip
    -88aacc21c6c552b3ff3a157a7575a9dca7e4a7c3  pypy-2.0-linux64.tar.bz2
    -b2e64ca5e38a59c3402185cca08ca5a4d507ff7e  pypy-2.0-linux.tar.bz2
    -65ecb2ba570f05691978c64469cfe3e76bfd8e01  pypy-2.0-osx64.tar.bz2
    -cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc  pypy-2.0-win32.zip
    +34072be1eeb63f9d37cf387e58aae81d  pypy-2.0.1-src.tar.bz2
    +ea8764e387e74c62e898536a862c66c7  pypy-2.0.1-src.zip
    +cbcd60a78d90caca98fdc2562fc7fcbe76c6e699  pypy-2.0.1-linux64.tar.bz2
    +a909742d41fb540d9c12ce010bdc7f9e19353fcc  pypy-2.0.1-linux.tar.bz2
    +811fd377ab2eda9233a0c34340f981f9aba1ba9a  pypy-2.0.1-osx64.tar.bz2
    +0fa90e240648e628c6ac3dfed467f88563897a2a  pypy-2.0.1-win32.zip
     dc09a293b85ab4f0032f6943815aaf5bbbceb645  pypy-2.0-alpha-arm-armel.tar.bz2
     0971c4b668bfd2fcd52aa35087aa995e03bd5842  pypy-2.0-alpha-arm-armhf.tar.bz2
     91910eb654ffbe0509bec2a7aeb460984acf8d82  pypy-upstream_2.0~alpha+arm_armhf.deb
     895aaf7bba5787dd30adda5cc0e0e7fc297c0ca7  pypy-1.8-sandbox-linux64.tar.bz2
     be94460bed8b2682880495435c309b6611ae2c31  pypy-1.8-sandbox-linux.tar.bz2
    -d694824eeaa6169bce8d112149c9a5c7897534ed  pypy-2.0-src.tar.bz2
    -dc44cc9141a729ccc39b98432062bbe29c938432  pypy-2.0-src.zip
    +8bc02e922e758048f294a5c6848f97125b0b557f  pypy-2.0.1-src.tar.bz2
    +61b7326c1379af0914b81936bc057dfec0292458  pypy-2.0.1-src.zip
     
    diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -63,7 +63,7 @@
  • As well as other features.
  • -

    Download and try out the PyPy release 2.0!

    +

    Download and try out the PyPy release 2.0.1!

    Want to know more? A good place to start is our detailed speed and compatibility reports!

    diff --git a/numpydonate.html b/numpydonate.html --- a/numpydonate.html +++ b/numpydonate.html @@ -65,7 +65,7 @@ at the latest, we will try our best to make PyPy support NumPy anyway. We however reserve the right to shift any unused funds to other PyPy activities when that date is reached. Of course, since the Conservancy is a -501(c)(3) charitable organization incorporated in NY, USA, all funds will, +501©(3) charitable organization incorporated in NY, USA, all funds will, regardless of their use, be spent in a way that benefits the general public, the advancement of Open Source and Free Software, and in particular the PyPy community and the PyPy codebase.

    diff --git a/py3donate.html b/py3donate.html --- a/py3donate.html +++ b/py3donate.html @@ -74,7 +74,7 @@ at the latest, we will try our best to make PyPy support Python 3 anyway. We however reserve the right to shift any unused funds to other PyPy activities when that date is reached. Of course, since the Conservancy is a -501(c)(3) charitable organization incorporated in NY, USA, all funds will, +501©(3) charitable organization incorporated in NY, USA, all funds will, regardless of their use, be spent in a way that benefits the general public, the advancement of Open Source and Free Software, and in particular the PyPy community and the PyPy codebase.

    From noreply at buildbot.pypy.org Thu May 16 18:28:37 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 18:28:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Update Message-ID: <20130516162837.8B7BD1C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64233:3805f14a7579 Date: 2013-05-16 18:27 +0200 http://bitbucket.org/pypy/pypy/changeset/3805f14a7579/ Log: Update diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst --- a/pypy/doc/release-2.0.1.rst +++ b/pypy/doc/release-2.0.1.rst @@ -3,7 +3,7 @@ ============================== We're pleased to announce PyPy 2.0.1. This is a stable bugfix release -over 2.0. You can download it here: +over `2.0`_. You can download it here: http://pypy.org/download.html @@ -40,6 +40,7 @@ .. __: https://bugs.pypy.org/issue1482 .. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html .. __: https://bugs.pypy.org/issue1468 +.. _2.0: release-2.0.0.html Cheers, arigo et. al. for the PyPy team From noreply at buildbot.pypy.org Thu May 16 18:36:49 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 18:36:49 +0200 (CEST) Subject: [pypy-commit] pypy default: typo Message-ID: <20130516163649.A483A1C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64234:9c28835d3e50 Date: 2013-05-16 18:36 +0200 http://bitbucket.org/pypy/pypy/changeset/9c28835d3e50/ Log: typo diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst --- a/pypy/doc/release-2.0.1.rst +++ b/pypy/doc/release-2.0.1.rst @@ -28,7 +28,7 @@ - fix an occasional crash in the JIT that ends in `RPython Fatal error: NotImplementedError`__. -- `id(x)` is now always a positive number (expect on int/float/long/complex). +- `id(x)` is now always a positive number (except on int/float/long/complex). This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux). - fix crashes of callback-from-C-functions (with cffi) when used together From noreply at buildbot.pypy.org Thu May 16 18:39:13 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 18:39:13 +0200 (CEST) Subject: [pypy-commit] pypy default: Update Message-ID: <20130516163913.02A591C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64235:0f2686b8989c Date: 2013-05-16 18:38 +0200 http://bitbucket.org/pypy/pypy/changeset/0f2686b8989c/ Log: Update diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.0' +release = '2.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From noreply at buildbot.pypy.org Thu May 16 18:41:05 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 18:41:05 +0200 (CEST) Subject: [pypy-commit] pypy default: Write down this step Message-ID: <20130516164105.B6B701C01D1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64236:74133f05685b Date: 2013-05-16 18:40 +0200 http://bitbucket.org/pypy/pypy/changeset/74133f05685b/ Log: Write down this step diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,7 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release From noreply at buildbot.pypy.org Thu May 16 18:42:29 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 18:42:29 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Update the version number here too Message-ID: <20130516164229.283201C01D1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r436:48567f8dfc1e Date: 2013-05-16 18:42 +0200 http://bitbucket.org/pypy/pypy.org/changeset/48567f8dfc1e/ Log: Update the version number here too diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -45,7 +45,7 @@

    Features

    -

    PyPy 2.0 implements Python 2.7.3 and runs on Intel +

    PyPy 2.0.1 implements Python 2.7.3 and runs on Intel x86 (IA-32) , x86_64 and ARM platforms (alpha), with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/source/features.txt b/source/features.txt --- a/source/features.txt +++ b/source/features.txt @@ -6,7 +6,7 @@ PyPy features =========================================================== -**PyPy 2.0** implements **Python 2.7.3** and runs on Intel +**PyPy 2.0.1** implements **Python 2.7.3** and runs on Intel `x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms (alpha), with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python From noreply at buildbot.pypy.org Thu May 16 19:06:35 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 19:06:35 +0200 (CEST) Subject: [pypy-commit] pypy default: Update the version number here Message-ID: <20130516170635.6958A1C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64237:57fded393ab6 Date: 2013-05-16 19:05 +0200 http://bitbucket.org/pypy/pypy/changeset/57fded393ab6/ Log: Update the version number here diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0`_: the latest official release +* `Release 2.0.1`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0`: http://pypy.org/download.html +.. _`Release 2.0.1`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html From noreply at buildbot.pypy.org Thu May 16 19:12:08 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 16 May 2013 19:12:08 +0200 (CEST) Subject: [pypy-commit] pypy default: mention the version number here too Message-ID: <20130516171208.246D01C02E4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64238:4c6317d15410 Date: 2013-05-16 19:11 +0200 http://bitbucket.org/pypy/pypy/changeset/4c6317d15410/ Log: mention the version number here too diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary; also update the version number in pypy/doc/conf.py + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release From noreply at buildbot.pypy.org Thu May 16 20:25:56 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 16 May 2013 20:25:56 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed the tests messed up by the last changes Message-ID: <20130516182556.91B001C0A11@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r394:408a13e4f78f Date: 2013-05-16 20:25 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/408a13e4f78f/ Log: fixed the tests messed up by the last changes diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py --- a/spyvm/test/test_primitives.py +++ b/spyvm/test/test_primitives.py @@ -51,7 +51,8 @@ interp, w_frame, argument_count = mock(stack, context) prim_table[code](interp, w_frame.as_context_get_shadow(space), argument_count-1) res = w_frame.as_context_get_shadow(space).pop() - assert not w_frame.as_context_get_shadow(space).stackdepth() # check args are consumed + s_frame = w_frame.as_context_get_shadow(space) + assert not s_frame.stackdepth() - s_frame.tempsize() # check args are consumed return res def prim_fails(code, stack): diff --git a/spyvm/test/test_shadow.py b/spyvm/test/test_shadow.py --- a/spyvm/test/test_shadow.py +++ b/spyvm/test/test_shadow.py @@ -127,7 +127,7 @@ assert s_object2.gettemp(1) == 'b' assert s_object2.gettemp(0) == 'a' assert s_object.w_method() == w_m - idx = s_object.stackstart() + idx = s_object.stackstart() + s_object.tempsize() w_object.store(space, idx, space.wrap_string('f')) w_object.store(space, idx + 1, space.wrap_string('g')) w_object.store(space, idx + 2, space.wrap_string('h')) @@ -139,7 +139,8 @@ assert s_object.pop() == 'i' assert map(lambda x: x.as_string(), s_object.pop_and_return_n(2)) == ['g', 'h'] assert s_object.pop().as_string() == 'f' - assert s_object.external_stackpointer() == s_object.stackstart() + assert s_object.external_stackpointer() == s_object.stackstart() + s_object.tempsize() + assert s_object.stackdepth() == s_object.tempsize() def test_methodcontext(): w_m = method() From noreply at buildbot.pypy.org Thu May 16 21:26:31 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 16 May 2013 21:26:31 +0200 (CEST) Subject: [pypy-commit] pypy py3k: oops Message-ID: <20130516192631.5B3331C1306@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64240:c7563e3140b1 Date: 2013-05-16 12:25 -0700 http://bitbucket.org/pypy/pypy/changeset/c7563e3140b1/ Log: oops diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -123,6 +123,7 @@ RegrTest('test_bz2.py', usemodules='bz2'), RegrTest('test_calendar.py'), RegrTest('test_call.py', core=True), + RegrTest('test_capi.py', usemodules='cpyext'), RegrTest('test_cfgparser.py'), RegrTest('test_cgi.py'), RegrTest('test_charmapcodec.py', core=True), From noreply at buildbot.pypy.org Thu May 16 21:26:29 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 16 May 2013 21:26:29 +0200 (CEST) Subject: [pypy-commit] pypy py3k: add _testcapi skips from default + others Message-ID: <20130516192629.BAA0C1C1106@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64239:c81479fc13b0 Date: 2013-05-16 11:48 -0700 http://bitbucket.org/pypy/pypy/changeset/c81479fc13b0/ Log: add _testcapi skips from default + others diff --git a/lib-python/3/test/test_code.py b/lib-python/3/test/test_code.py --- a/lib-python/3/test/test_code.py +++ b/lib-python/3/test/test_code.py @@ -104,7 +104,10 @@ import unittest import weakref -import _testcapi +try: + import _testcapi +except ImportError: + _testcapi = None from test import support @@ -127,6 +130,7 @@ class CodeTest(unittest.TestCase): + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_newempty(self): co = _testcapi.code_newempty("filename", "funcname", 15) self.assertEqual(co.co_filename, "filename") diff --git a/lib-python/3/test/test_codecs.py b/lib-python/3/test/test_codecs.py --- a/lib-python/3/test/test_codecs.py +++ b/lib-python/3/test/test_codecs.py @@ -2,7 +2,11 @@ import unittest import codecs import locale -import sys, _testcapi, io +import sys, io +try: + import _testcapi +except ImportError: + _testcapi = None class Queue(object): """ @@ -1417,7 +1421,7 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if encoding not in broken_incremental_coders and _testcapi: # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/3/test/test_exceptions.py b/lib-python/3/test/test_exceptions.py --- a/lib-python/3/test/test_exceptions.py +++ b/lib-python/3/test/test_exceptions.py @@ -6,6 +6,10 @@ import pickle import weakref import errno +try: + import _testcapi +except ImportError: + _testcapi = None from test.support import (TESTFN, unlink, run_unittest, captured_output, gc_collect, cpython_only) @@ -762,6 +766,7 @@ self.assertIn("maximum recursion depth exceeded", str(v)) + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_MemoryError(self): # PyErr_NoMemory always raises the same exception instance. # Check that the traceback is not doubled. @@ -820,6 +825,7 @@ self.assertEqual(error5.a, 1) self.assertEqual(error5.__doc__, "") + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_memory_error_cleanup(self): # Issue #5437: preallocated MemoryError instances should not keep # traceback objects alive. diff --git a/lib-python/3/test/test_traceback.py b/lib-python/3/test/test_traceback.py --- a/lib-python/3/test/test_traceback.py +++ b/lib-python/3/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print, exception_print +try: + import _testcapi +except ImportError: + _testcapi = None from io import StringIO import sys import unittest @@ -154,6 +157,7 @@ class TracebackFormatTests(unittest.TestCase): + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_traceback_format(self): try: raise KeyError('blah') @@ -162,7 +166,7 @@ traceback_fmt = 'Traceback (most recent call last):\n' + \ ''.join(traceback.format_tb(tb)) file_ = StringIO() - traceback_print(tb, file_) + _testcapi.traceback_print(tb, file_) python_fmt = file_.getvalue() else: raise Error("unable to create test traceback string") @@ -326,10 +330,11 @@ # This checks built-in reporting by the interpreter. # + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def get_report(self, e): e = self.get_exception(e) with captured_output("stderr") as s: - exception_print(e) + _testcapi.exception_print(e) return s.getvalue() diff --git a/lib-python/3/test/test_unicode.py b/lib-python/3/test/test_unicode.py --- a/lib-python/3/test/test_unicode.py +++ b/lib-python/3/test/test_unicode.py @@ -12,6 +12,10 @@ import warnings from test import support, string_tests import _string +try: + import _testcapi +except ImportError: + _testcapi = None # decorator to skip tests on narrow builds requires_wide_build = unittest.skipIf(sys.maxunicode == 65535, @@ -1659,6 +1663,7 @@ self.assertEqual(text, 'repr=abc\ufffd') # Test PyUnicode_AsWideChar() + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_aswidechar(self): from _testcapi import unicode_aswidechar support.import_module('ctypes') @@ -1696,6 +1701,7 @@ self.assertEqual(wchar, nonbmp + '\0') # Test PyUnicode_AsWideCharString() + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_aswidecharstring(self): from _testcapi import unicode_aswidecharstring support.import_module('ctypes') @@ -1769,6 +1775,7 @@ ]]) self.assertRaises(TypeError, _string.formatter_field_name_split, 1) + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_encode_decimal(self): from _testcapi import unicode_encodedecimal self.assertEqual(unicode_encodedecimal('123'), @@ -1794,6 +1801,7 @@ self.assertEqual(unicode_encodedecimal("123\u20ac\u0660", "replace"), b'123?0') + @unittest.skipUnless(_testcapi, 'Requires _testcapi') def test_transform_decimal(self): from _testcapi import unicode_transformdecimaltoascii as transform_decimal self.assertEqual(transform_decimal('123'), From noreply at buildbot.pypy.org Thu May 16 22:07:51 2013 From: noreply at buildbot.pypy.org (mattip) Date: Thu, 16 May 2013 22:07:51 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: fix failing test Message-ID: <20130516200751.291901C02E4@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r64241:aadb4a3cdb25 Date: 2013-05-16 23:06 +0300 http://bitbucket.org/pypy/pypy/changeset/aadb4a3cdb25/ Log: fix failing test diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,8 +268,20 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: @@ -373,7 +385,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", From noreply at buildbot.pypy.org Thu May 16 22:57:42 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 16 May 2013 22:57:42 +0200 (CEST) Subject: [pypy-commit] pypy py3k: loosen set's rich comparisons Message-ID: <20130516205742.C5E271C01D1@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64242:5ea7a1017b30 Date: 2013-05-16 13:24 -0700 http://bitbucket.org/pypy/pypy/changeset/5ea7a1017b30/ Log: loosen set's rich comparisons diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -196,8 +196,7 @@ # correct answer here! def descr_lt(self, space, w_other): if not isinstance(w_other, W_BaseSetObject): - raise OperationError(self.space.w_TypeError, - self.space.wrap('can only compare to a set')) + return space.w_NotImplemented if self.length() >= w_other.length(): return space.w_False @@ -206,8 +205,7 @@ def descr_le(self, space, w_other): if not isinstance(w_other, W_BaseSetObject): - raise OperationError(self.space.w_TypeError, - self.space.wrap('can only compare to a set')) + return space.w_NotImplemented if self.length() > w_other.length(): return space.w_False @@ -215,8 +213,7 @@ def descr_gt(self, space, w_other): if not isinstance(w_other, W_BaseSetObject): - raise OperationError(self.space.w_TypeError, - self.space.wrap('can only compare to a set')) + return space.w_NotImplemented if self.length() <= w_other.length(): return space.w_False @@ -225,8 +222,7 @@ def descr_ge(self, space, w_other): if not isinstance(w_other, W_BaseSetObject): - raise OperationError(self.space.w_TypeError, - self.space.wrap('can only compare to a set')) + return space.w_NotImplemented if self.length() < w_other.length(): return space.w_False diff --git a/pypy/objspace/std/test/test_setobject.py b/pypy/objspace/std/test/test_setobject.py --- a/pypy/objspace/std/test/test_setobject.py +++ b/pypy/objspace/std/test/test_setobject.py @@ -385,6 +385,42 @@ assert set() != set('abc') assert set('abc') != set('abd') + def test_compare_other(self): + class TestRichSetCompare: + def __gt__(self, some_set): + self.gt_called = True + return False + def __lt__(self, some_set): + self.lt_called = True + return False + def __ge__(self, some_set): + self.ge_called = True + return False + def __le__(self, some_set): + self.le_called = True + return False + + # This first tries the builtin rich set comparison, which doesn't know + # how to handle the custom object. Upon returning NotImplemented, the + # corresponding comparison on the right object is invoked. + myset = set(range(3)) + + myobj = TestRichSetCompare() + myset < myobj + assert myobj.gt_called + + myobj = TestRichSetCompare() + myset > myobj + assert myobj.lt_called + + myobj = TestRichSetCompare() + myset <= myobj + assert myobj.ge_called + + myobj = TestRichSetCompare() + myset >= myobj + assert myobj.le_called + def test_libpython_equality(self): for thetype in [frozenset, set]: word = "aaaaaaaaawfpasrtarspawparst" From noreply at buildbot.pypy.org Thu May 16 22:57:44 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 16 May 2013 22:57:44 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130516205744.590941C1106@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64243:f4bb9fce9847 Date: 2013-05-16 13:56 -0700 http://bitbucket.org/pypy/pypy/changeset/f4bb9fce9847/ Log: merge default diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -324,7 +324,12 @@ if self._close: self._sock.close() else: - self._sock._decref_socketios() + try: + self._sock._decref_socketios() + except AttributeError: + pass # bah, someone built a _fileobject manually + # with some unexpected replacement of the + # _socketobject class self._sock = None def __del__(self): diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -180,7 +180,7 @@ def test_traceback_format(self): if traceback_print is None: - return + raise unittest.SkipTest('Requires _testcapi') try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1612,7 +1612,7 @@ try: from _testcapi import unicode_encodedecimal except ImportError: - return + raise unittest.SkipTest('Requires _testcapi') self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.0' +release = '2.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0`_: the latest official release +* `Release 2.0.1`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0`: http://pypy.org/download.html +.. _`Release 2.0.1`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.1.rst @@ -0,0 +1,46 @@ +============================== +PyPy 2.0.1 - Bohr Smørrebrød +============================== + +We're pleased to announce PyPy 2.0.1. This is a stable bugfix release +over `2.0`_. You can download it here: + + http://pypy.org/download.html + +The fixes are mainly about fatal errors or crashes in our stdlib. See +below for more details. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +- fix an occasional crash in the JIT that ends in `RPython Fatal error: + NotImplementedError`__. + +- `id(x)` is now always a positive number (except on int/float/long/complex). + This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux). + +- fix crashes of callback-from-C-functions (with cffi) when used together + with Stackless features, on asmgcc (i.e. Linux only). Now `gevent should + work better`__. + +- work around an eventlet issue with `socket._decref_socketios()`__. + +.. __: https://bugs.pypy.org/issue1482 +.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html +.. __: https://bugs.pypy.org/issue1468 +.. _2.0: release-2.0.0.html + +Cheers, +arigo et. al. for the PyPy team 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,6 @@ .. branch: remove-set-smm Remove multi-methods on sets + +.. branch: numpy-subarrays +Implement subarrays for numpy diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -114,8 +114,11 @@ ge = _make_comparison('ge') def hash(self): - h = (objectmodel.compute_identity_hash(self.ctype) ^ - rffi.cast(lltype.Signed, self._cdata)) + h = rffi.cast(lltype.Signed, self._cdata) + # To hash pointers in dictionaries. Assumes that h shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + h = h ^ (h >> 4) return self.space.wrap(h) def getitem(self, w_index): 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,8 +365,9 @@ BInt = new_primitive_type("int") BFloat = new_primitive_type("float") for i in range(1, 20): - if (hash(cast(BChar, chr(i))) != - hash(cast(BInt, i))): + x1 = cast(BChar, chr(i)) + x2 = cast(BInt, i) + if hash(x1) != hash(x2): break else: raise AssertionError("hashes are equal") @@ -2723,6 +2724,14 @@ assert x.__name__ == '' assert hasattr(x, '__doc__') +def test_different_types_of_ptr_equality(): + BVoidP = new_pointer_type(new_void_type()) + BIntP = new_pointer_type(new_primitive_type("int")) + x = cast(BVoidP, 12345) + assert x == cast(BIntP, 12345) + assert x != cast(BIntP, 12344) + assert hash(x) == hash(cast(BIntP, 12345)) + def test_version(): # this test is here mostly for PyPy assert __version__ == "0.6" diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py --- a/pypy/module/_ffi/test/test_funcptr.py +++ b/pypy/module/_ffi/test/test_funcptr.py @@ -74,9 +74,9 @@ from _ffi import CDLL, types # this should return *all* loaded libs, dlopen(NULL) dll = CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.getfunc('Py_IsInitialized', [], types.slong)() - assert res == 1 + # libm should be loaded + res = dll.getfunc('sqrt', [types.double], types.double)(1.0) + assert res == 1.0 def test_callfunc(self): from _ffi import CDLL, types @@ -139,7 +139,7 @@ def test_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr() { return &dummy; } DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; } """ @@ -158,7 +158,7 @@ def test_convert_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto """ @@ -170,7 +170,7 @@ def _as_ffi_pointer_(self, ffitype): assert ffitype is types.void_p return self.value - + libfoo = CDLL(self.libfoo_name) get_dummy = libfoo.getfunc('get_dummy', [], types.sint) get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) @@ -259,7 +259,7 @@ def test_typed_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto """ @@ -551,7 +551,7 @@ from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) raises(TypeError, "libfoo.getfunc('sum_xy', [types.void], types.sint)") - + def test_OSError_loading(self): from _ffi import CDLL, types raises(OSError, "CDLL('I do not exist')") @@ -606,7 +606,7 @@ from _rawffi import FUNCFLAG_STDCALL libm = CDLL(self.libm_name) pow_addr = libm.getaddressindll('pow') - wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', + wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double], types.double, FUNCFLAG_STDCALL) try: wrong_pow(2, 3) == 8 @@ -622,7 +622,7 @@ from _rawffi import FUNCFLAG_STDCALL kernel = WinDLL('Kernel32.dll') sleep_addr = kernel.getaddressindll('Sleep') - sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], + sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], types.void, FUNCFLAG_STDCALL) sleep(10) diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py --- a/pypy/module/sys/initpath.py +++ b/pypy/module/sys/initpath.py @@ -68,7 +68,7 @@ If it cannot be found, return (None, None). """ if executable == '': - return None, None + executable = 'pypy-c' search = executable while True: dirname = resolvedirof(search) diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py --- a/pypy/module/sys/test/test_initpath.py +++ b/pypy/module/sys/test/test_initpath.py @@ -16,9 +16,12 @@ build_hierarchy(tmpdir) path, prefix = find_stdlib(None, str(pypy)) assert prefix == tmpdir - # shouldn't find stdlib if executable == '' even if parent dir has a stdlib - monkeypatch.chdir(tmpdir.join('bin')) - assert find_stdlib(None, '') == (None, None) + # in executable is None look for stdlib based on the working directory + # see lib-python/2.7/test/test_sys.py:test_executable + _, prefix = find_stdlib(None, '') + cwd = os.path.dirname(os.path.realpath(__file__)) + assert prefix is not None + assert cwd.startswith(str(prefix)) @py.test.mark.skipif('not hasattr(os, "symlink")') def test_find_stdlib_follow_symlink(tmpdir): diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py --- a/pypy/objspace/fake/checkmodule.py +++ b/pypy/objspace/fake/checkmodule.py @@ -5,7 +5,6 @@ def checkmodule(*modnames): config = get_pypy_config(translating=True) space = FakeObjSpace(config) - space.setup() seeobj_w = [] for modname in modnames: mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__']) diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -111,6 +111,7 @@ def __init__(self, config=None): self._seen_extras = [] ObjSpace.__init__(self, config=config) + self.setup() # Be sure to annotate W_SliceObject constructor. # In Python2, this is triggered by W_InstanceObject.__getslice__. diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -57,7 +57,8 @@ # This thing is imported by any target which has any API, so it'll get # registered -RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void) +RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void, + _nowrapper=True) @entrypoint('main', [], c_name='rpython_startup_code') def rpython_startup_code(): From noreply at buildbot.pypy.org Fri May 17 10:05:12 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 17 May 2013 10:05:12 +0200 (CEST) Subject: [pypy-commit] pypy default: because we try harder to find stdlib, goal_dir is not in sys.path in this case Message-ID: <20130517080512.875E01C147F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64244:00cec60f096e Date: 2013-05-17 10:04 +0200 http://bitbucket.org/pypy/pypy/changeset/00cec60f096e/ Log: because we try harder to find stdlib, goal_dir is not in sys.path in this case 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 @@ -920,7 +920,7 @@ import app_main app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + [self.goal_dir] + assert sys.path == old_sys_path app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe From noreply at buildbot.pypy.org Fri May 17 10:25:33 2013 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 17 May 2013 10:25:33 +0200 (CEST) Subject: [pypy-commit] pypy remove-array-smm: reclose branch fixed on default Message-ID: <20130517082533.533221C01D1@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: remove-array-smm Changeset: r64245:455dc44f6b29 Date: 2013-05-16 23:18 +0300 http://bitbucket.org/pypy/pypy/changeset/455dc44f6b29/ Log: reclose branch fixed on default From noreply at buildbot.pypy.org Fri May 17 10:25:34 2013 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 17 May 2013 10:25:34 +0200 (CEST) Subject: [pypy-commit] pypy closed-branches: merge closed branch into closed-branches Message-ID: <20130517082534.A54191C01D1@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: closed-branches Changeset: r64246:d39a1ddf7fd0 Date: 2013-05-16 23:25 +0300 http://bitbucket.org/pypy/pypy/changeset/d39a1ddf7fd0/ Log: merge closed branch into closed-branches From noreply at buildbot.pypy.org Fri May 17 10:25:35 2013 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 17 May 2013 10:25:35 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: simplify assertion, still trying to work out why it is necessary for translation Message-ID: <20130517082535.E5BFD1C01D1@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r64247:e08dfdfdcfbe Date: 2013-05-17 11:24 +0300 http://bitbucket.org/pypy/pypy/changeset/e08dfdfdcfbe/ Log: simplify assertion, still trying to work out why it is necessary for translation diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -80,7 +80,9 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + assert isinstance(item, interp_boxes.W_GenericBox) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -12,7 +12,6 @@ from pypy.module.micronumpy.iter import PureShapeIterator from pypy.module.micronumpy import constants from pypy.module.micronumpy.support import int_w -from pypy.module.micronumpy.interp_boxes import W_GenericBox call2_driver = jit.JitDriver(name='numpy_call2', greens = ['shapelen', 'func', 'calc_dtype', @@ -34,12 +33,8 @@ out=out, left_iter=left_iter, right_iter=right_iter, out_iter=out_iter) - item_l = left_iter.getitem() - item_r = right_iter.getitem() - assert isinstance(item_l, W_GenericBox) - assert isinstance(item_r, W_GenericBox) - w_left = item_l.convert_to(calc_dtype) - w_right = item_r.convert_to(calc_dtype) + w_left = left_iter.getitem().convert_to(calc_dtype) + w_right = right_iter.getitem().convert_to(calc_dtype) out_iter.setitem(func(calc_dtype, w_left, w_right).convert_to( res_dtype)) left_iter.next() @@ -64,9 +59,7 @@ calc_dtype=calc_dtype, res_dtype=res_dtype, shape=shape, w_obj=w_obj, out=out, obj_iter=obj_iter, out_iter=out_iter) - item = obj_iter.getitem() - assert isinstance(item, W_GenericBox) - elem = item.convert_to(calc_dtype) + elem = obj_iter.getitem().convert_to(calc_dtype) out_iter.setitem(func(calc_dtype, elem).convert_to(res_dtype)) out_iter.next() obj_iter.next() @@ -93,9 +86,7 @@ shapelen = len(shape) while not target_iter.done(): setslice_driver1.jit_merge_point(shapelen=shapelen, dtype=dtype) - item = source_iter.getitem() - assert isinstance(item, W_GenericBox) - target_iter.setitem(item.convert_to(dtype)) + target_iter.setitem(source_iter.getitem().convert_to(dtype)) target_iter.next() source_iter.next() return target @@ -109,9 +100,7 @@ shapelen = len(shape) while not target_iter.done(): setslice_driver2.jit_merge_point(shapelen=shapelen, dtype=dtype) - item = source_iter.getitem() - assert isinstance(item, W_GenericBox) - target_iter.setitem(dtype.build_and_convert(space, item)) + target_iter.setitem(dtype.build_and_convert(space, source_iter.getitem())) target_iter.next() source_iter.next() return target @@ -124,9 +113,7 @@ def compute_reduce(obj, calc_dtype, func, done_func, identity): obj_iter = obj.create_iter() if identity is None: - item = obj_iter.getitem() - assert isinstance(item, W_GenericBox) - cur_value = item.convert_to(calc_dtype) + cur_value = obj_iter.getitem().convert_to(calc_dtype) obj_iter.next() else: cur_value = identity.convert_to(calc_dtype) @@ -136,9 +123,7 @@ done_func=done_func, calc_dtype=calc_dtype, identity=identity, ) - item = obj_iter.getitem() - assert isinstance(item, W_GenericBox) - rval = item.convert_to(calc_dtype) + rval = obj_iter.getitem().convert_to(calc_dtype) if done_func is not None and done_func(calc_dtype, rval): return rval cur_value = func(calc_dtype, cur_value, rval) @@ -157,9 +142,7 @@ reduce_cum_driver.jit_merge_point(shapelen=shapelen, func=func, dtype=calc_dtype, ) - item = obj_iter.getitem() - assert isinstance(item, W_GenericBox) - rval = item.convert_to(calc_dtype) + rval = obj_iter.getitem().convert_to(calc_dtype) cur_value = func(calc_dtype, cur_value, rval) out_iter.setitem(cur_value) out_iter.next() @@ -190,16 +173,13 @@ iter = x_iter shapelen = len(shape) while not iter.done(): - where_driver.jit_merge_point(shapelen=shapelen, dtype=dtype, + where_driver.jit_merge_point(shapelen=shapelen, dtype=dtype, arr_dtype=arr_dtype) w_cond = arr_iter.getitem() - assert isinstance(w_cond, W_GenericBox) if arr_dtype.itemtype.bool(w_cond): - item = x_iter.getitem() + w_val = x_iter.getitem().convert_to(dtype) else: - item = y_iter.getitem() - assert isinstance(item, W_GenericBox) - w_val = item.convert_to(dtype) + w_val = y_iter.getitem().convert_to(dtype) out_iter.setitem(w_val) out_iter.next() arr_iter.next() @@ -208,7 +188,7 @@ return out axis_reduce__driver = jit.JitDriver(name='numpy_axis_reduce', - greens=['shapelen', + greens=['shapelen', 'func', 'dtype', 'identity'], reds='auto') @@ -228,15 +208,12 @@ axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func, dtype=dtype, identity=identity, ) - item = arr_iter.getitem() - assert isinstance(item, W_GenericBox) - w_val = item.convert_to(dtype) + w_val = arr_iter.getitem().convert_to(dtype) if out_iter.first_line: if identity is not None: w_val = func(dtype, identity, w_val) else: cur = temp_iter.getitem() - assert isinstance(cur, W_GenericBox) w_val = func(dtype, cur, w_val) out_iter.setitem(w_val) if cumultative: @@ -251,21 +228,19 @@ arg_driver = jit.JitDriver(name='numpy_' + op_name, greens = ['shapelen', 'dtype'], reds = 'auto') - + def argmin_argmax(arr): result = 0 idx = 1 dtype = arr.get_dtype() iter = arr.create_iter() cur_best = iter.getitem() - assert isinstance(cur_best, W_GenericBox) iter.next() shapelen = len(arr.get_shape()) while not iter.done(): arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype, ) w_val = iter.getitem() - assert isinstance(w_val, W_GenericBox) new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val) if dtype.itemtype.ne(new_best, cur_best): result = idx @@ -290,7 +265,7 @@ result.shape == [3, 5, 2, 4] broadcast shape should be [3, 5, 2, 7, 4] result should skip dims 3 which is len(result_shape) - 1 - (note that if right is 1d, result should + (note that if right is 1d, result should skip len(result_shape)) left should skip 2, 4 which is a.ndims-1 + range(right.ndims) except where it==(right.ndims-2) @@ -308,13 +283,9 @@ righti = right.create_dot_iter(broadcast_shape, right_skip) while not outi.done(): dot_driver.jit_merge_point(dtype=dtype) - litem = lefti.getitem() - ritem = righti.getitem() - oitem = outi.getitem() - assert isinstance(litem, W_GenericBox) and isinstance(ritem, W_GenericBox) and isinstance(oitem, W_GenericBox) - lval = litem.convert_to(dtype) - rval = ritem.convert_to(dtype) - outval = oitem.convert_to(dtype) + lval = lefti.getitem().convert_to(dtype) + rval = righti.getitem().convert_to(dtype) + outval = outi.getitem().convert_to(dtype) v = dtype.itemtype.mul(lval, rval) value = dtype.itemtype.add(v, outval).convert_to(dtype) outi.setitem(value) @@ -384,7 +355,7 @@ setitem_filter_driver.jit_merge_point(shapelen=shapelen, index_dtype=index_dtype, arr_dtype=arr_dtype, - ) + ) if index_iter.getitem_bool(): arr_iter.setitem(value_iter.getitem()) value_iter.next() @@ -426,9 +397,7 @@ arr_iter.next_skip_x(start) while length > 0: flatiter_setitem_driver1.jit_merge_point(dtype=dtype) - item = val_iter.getitem() - assert isinstance(item, W_GenericBox) - arr_iter.setitem(item.convert_to(dtype)) + arr_iter.setitem(val_iter.getitem().convert_to(dtype)) # need to repeat i_nput values until all assignments are done arr_iter.next_skip_x(step) length -= 1 @@ -572,9 +541,7 @@ index = 0 else: index = len(iterators) - 1 - item = iterators[index].getitem() - assert isinstance(item, W_GenericBox) - out_iter.setitem(item.convert_to(dtype)) + out_iter.setitem(iterators[index].getitem().convert_to(dtype)) for iter in iterators: iter.next() out_iter.next() @@ -592,13 +559,9 @@ out_iter = out.create_iter(shape) while not arr_iter.done(): clip_driver.jit_merge_point(shapelen=shapelen, dtype=dtype) - i_arr = arr_iter.getitem() - i_min = min_iter.getitem() - i_max = max_iter.getitem() - assert isinstance(i_arr, W_GenericBox) and isinstance(i_min, W_GenericBox) and isinstance(i_max, W_GenericBox) - w_v = i_arr.convert_to(dtype) - w_min = i_min.convert_to(dtype) - w_max = i_max.convert_to(dtype) + w_v = arr_iter.getitem().convert_to(dtype) + w_min = min_iter.getitem().convert_to(dtype) + w_max = max_iter.getitem().convert_to(dtype) if dtype.itemtype.lt(w_v, w_min): w_v = w_min elif dtype.itemtype.gt(w_v, w_max): @@ -650,4 +613,4 @@ out_iter.setitem(arr.getitem_index(space, indexes)) iter.next() out_iter.next() - + From noreply at buildbot.pypy.org Fri May 17 11:01:55 2013 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 17 May 2013 11:01:55 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: test, implement numpy-comatible base attribute Message-ID: <20130517090155.B5E221C147F@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r64248:ca3ad0ac48d3 Date: 2013-05-17 12:00 +0300 http://bitbucket.org/pypy/pypy/changeset/ca3ad0ac48d3/ Log: test, implement numpy-comatible base attribute diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -65,6 +65,10 @@ self.float_type = None self.shape = list(shape) self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -115,6 +119,9 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + def descr_get_subdtype(self, space): return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) @@ -423,6 +430,7 @@ fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -778,6 +778,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -808,7 +809,8 @@ assert dt.shape == (10,) assert dt.kind == 'V' assert dt.fields == None - assert dt.subdtype == (dtype("float64"), (10,)) + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): From noreply at buildbot.pypy.org Fri May 17 11:26:56 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 11:26:56 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Fix translation. Message-ID: <20130517092656.462FC1C0848@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64249:aeb9cb3101c1 Date: 2013-05-17 11:24 +0200 http://bitbucket.org/pypy/pypy/changeset/aeb9cb3101c1/ Log: Fix translation. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -40,6 +40,19 @@ w_dct.length() <= UNROLL_CUTOFF) +def negate(f): + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator + class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, @@ -193,6 +206,10 @@ w_res = space.lt(w_leftval, w_rightval) return w_res + descr_ne = negate(descr_eq) + descr_le = negate(descr_gt) + descr_ge = negate(descr_lt) + def descr_len(self, space): return space.wrap(self.length()) @@ -373,19 +390,6 @@ dictrepr = app.interphook("dictrepr") -def negate(f): - def _negator(space, w_self, w_other): - # no need to use space.is_ / space.not_ - tmp = f(w_self, space, w_other) - if tmp == space.w_NotImplemented: - return space.w_NotImplemented - elif tmp == space.w_False: - return space.w_True - else: - return space.w_False - _negator.func_name = 'negate-%s' % f - return _negator - W_DictMultiObject.typedef = StdTypeDef("dict", __doc__ = '''dict() -> new empty dictionary. dict(mapping) -> new dictionary initialized from a mapping object\'s @@ -404,11 +408,11 @@ __init__ = gateway.interp2app(W_DictMultiObject.descr_init), __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), - __ne__ = gateway.interp2app(negate(W_DictMultiObject.descr_eq)), + __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), - __le__ = gateway.interp2app(negate(W_DictMultiObject.descr_gt)), + __le__ = gateway.interp2app(W_DictMultiObject.descr_le), __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), - __ge__ = gateway.interp2app(negate(W_DictMultiObject.descr_lt)), + __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), __len__ = gateway.interp2app(W_DictMultiObject.descr_len), __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), From noreply at buildbot.pypy.org Fri May 17 11:26:57 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 11:26:57 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: hg merge default Message-ID: <20130517092657.B27901C0848@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64250:73e4f8cf4839 Date: 2013-05-17 11:25 +0200 http://bitbucket.org/pypy/pypy/changeset/73e4f8cf4839/ Log: hg merge default diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.0' +release = '2.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0`_: the latest official release +* `Release 2.0.1`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0`: http://pypy.org/download.html +.. _`Release 2.0.1`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.1.rst @@ -0,0 +1,46 @@ +============================== +PyPy 2.0.1 - Bohr Smørrebrød +============================== + +We're pleased to announce PyPy 2.0.1. This is a stable bugfix release +over `2.0`_. You can download it here: + + http://pypy.org/download.html + +The fixes are mainly about fatal errors or crashes in our stdlib. See +below for more details. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +- fix an occasional crash in the JIT that ends in `RPython Fatal error: + NotImplementedError`__. + +- `id(x)` is now always a positive number (except on int/float/long/complex). + This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux). + +- fix crashes of callback-from-C-functions (with cffi) when used together + with Stackless features, on asmgcc (i.e. Linux only). Now `gevent should + work better`__. + +- work around an eventlet issue with `socket._decref_socketios()`__. + +.. __: https://bugs.pypy.org/issue1482 +.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html +.. __: https://bugs.pypy.org/issue1468 +.. _2.0: release-2.0.0.html + +Cheers, +arigo et. al. for the PyPy team 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 @@ -920,7 +920,7 @@ import app_main app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + [self.goal_dir] + assert sys.path == old_sys_path app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -114,8 +114,11 @@ ge = _make_comparison('ge') def hash(self): - h = (objectmodel.compute_identity_hash(self.ctype) ^ - rffi.cast(lltype.Signed, self._cdata)) + h = rffi.cast(lltype.Signed, self._cdata) + # To hash pointers in dictionaries. Assumes that h shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + h = h ^ (h >> 4) return self.space.wrap(h) def getitem(self, w_index): 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,8 +365,9 @@ BInt = new_primitive_type("int") BFloat = new_primitive_type("float") for i in range(1, 20): - if (hash(cast(BChar, chr(i))) != - hash(cast(BInt, i))): + x1 = cast(BChar, chr(i)) + x2 = cast(BInt, i) + if hash(x1) != hash(x2): break else: raise AssertionError("hashes are equal") @@ -2723,6 +2724,14 @@ assert x.__name__ == '' assert hasattr(x, '__doc__') +def test_different_types_of_ptr_equality(): + BVoidP = new_pointer_type(new_void_type()) + BIntP = new_pointer_type(new_primitive_type("int")) + x = cast(BVoidP, 12345) + assert x == cast(BIntP, 12345) + assert x != cast(BIntP, 12344) + assert hash(x) == hash(cast(BIntP, 12345)) + def test_version(): # this test is here mostly for PyPy assert __version__ == "0.6" diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py --- a/pypy/module/sys/initpath.py +++ b/pypy/module/sys/initpath.py @@ -68,7 +68,7 @@ If it cannot be found, return (None, None). """ if executable == '': - return None, None + executable = 'pypy-c' search = executable while True: dirname = resolvedirof(search) diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py --- a/pypy/module/sys/test/test_initpath.py +++ b/pypy/module/sys/test/test_initpath.py @@ -16,9 +16,12 @@ build_hierarchy(tmpdir) path, prefix = find_stdlib(None, str(pypy)) assert prefix == tmpdir - # shouldn't find stdlib if executable == '' even if parent dir has a stdlib - monkeypatch.chdir(tmpdir.join('bin')) - assert find_stdlib(None, '') == (None, None) + # in executable is None look for stdlib based on the working directory + # see lib-python/2.7/test/test_sys.py:test_executable + _, prefix = find_stdlib(None, '') + cwd = os.path.dirname(os.path.realpath(__file__)) + assert prefix is not None + assert cwd.startswith(str(prefix)) @py.test.mark.skipif('not hasattr(os, "symlink")') def test_find_stdlib_follow_symlink(tmpdir): From noreply at buildbot.pypy.org Fri May 17 11:58:04 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 11:58:04 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Fix translation. Message-ID: <20130517095804.746DB1C32ED@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64251:ebe7cb75112a Date: 2013-05-17 11:56 +0200 http://bitbucket.org/pypy/pypy/changeset/ebe7cb75112a/ Log: Fix translation. diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -12,6 +12,7 @@ from pypy.objspace.std.register_all import register_all from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint, intmask from pypy.objspace.std import model +from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.interpreter.special import Ellipsis from pypy.interpreter.pycode import PyCode from pypy.interpreter import gateway, unicodehelper @@ -309,6 +310,8 @@ register(TYPE_LIST, unmarshal_List) def marshal_w_dict(space, w_dict, m): + if not isinstance(w_dict, W_DictMultiObject): + raise_exception(space, "unmarshallable object") m.start(TYPE_DICT) for w_tuple in w_dict.items(): w_key, w_value = space.fixedview(w_tuple, 2) From noreply at buildbot.pypy.org Fri May 17 13:55:03 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 13:55:03 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Fix __length__hint__ of dict iterators. Message-ID: <20130517115503.C907D1C0A11@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64252:72ed81f0b566 Date: 2013-05-17 13:45 +0200 http://bitbucket.org/pypy/pypy/changeset/72ed81f0b566/ Log: Fix __length__hint__ of dict iterators. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1230,19 +1230,22 @@ W_DictMultiIterItemsObject.typedef = StdTypeDef( "dict_iteritems", __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next) + next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterKeysObject.typedef = StdTypeDef( "dict_iterkeys", __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next) + next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterValuesObject.typedef = StdTypeDef( "dict_itervalues", __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next) + next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) From noreply at buildbot.pypy.org Fri May 17 13:55:05 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 13:55:05 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Document branch. Message-ID: <20130517115505.0D0701C32ED@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64253:984b24ea8403 Date: 2013-05-17 13:52 +0200 http://bitbucket.org/pypy/pypy/changeset/984b24ea8403/ Log: Document branch. 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 @@ -19,3 +19,6 @@ .. branch: numpy-subarrays Implement subarrays for numpy + +.. branch: remove-set-smm +Remove multi-methods on dict From noreply at buildbot.pypy.org Fri May 17 14:00:20 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 14:00:20 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Remove W_BaseDictMultiIterObject's typedef. Message-ID: <20130517120020.95D7E1C02E4@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64254:5e13749f21f6 Date: 2013-05-17 13:58 +0200 http://bitbucket.org/pypy/pypy/changeset/5e13749f21f6/ Log: Remove W_BaseDictMultiIterObject's typedef. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1197,11 +1197,6 @@ w_ret = space.newtuple([new_inst, space.newtuple(tup)]) return w_ret -W_BaseDictMultiIterObject.typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint), - __reduce__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_reduce), - ) - class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): def descr_next(self, space): From noreply at buildbot.pypy.org Fri May 17 14:31:59 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 17 May 2013 14:31:59 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: fix Message-ID: <20130517123159.44D671C01D1@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: remove-dict-smm Changeset: r64255:a47264323c6e Date: 2013-05-17 14:31 +0200 http://bitbucket.org/pypy/pypy/changeset/a47264323c6e/ Log: fix 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 @@ -20,5 +20,5 @@ .. branch: numpy-subarrays Implement subarrays for numpy -.. branch: remove-set-smm +.. branch: remove-dict-smm Remove multi-methods on dict From noreply at buildbot.pypy.org Fri May 17 14:37:46 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Fri, 17 May 2013 14:37:46 +0200 (CEST) Subject: [pypy-commit] lang-js default: implemented [].lastIndexOf Message-ID: <20130517123746.2B1EA1C0A11@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r382:b90fd00e0981 Date: 2013-05-17 00:41 -0300 http://bitbucket.org/pypy/lang-js/changeset/b90fd00e0981/ Log: implemented [].lastIndexOf diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -44,6 +44,8 @@ put_native_function(w_ArrayPrototype, u'indexOf', index_of) + put_native_function(w_ArrayPrototype, u'lastIndexOf', last_index_of) + # 15.4.4.7 @w_return @@ -167,6 +169,28 @@ @w_return +def last_index_of(this, args): + obj = this + elem = get_arg(args, 0) + length = this.get(u'length').ToUInt32() + from_index = length + + if len(args) > 1: + findex = get_arg(args, 1).ToInt32() + if findex < 0: + from_index = length + findex + else: + from_index = findex + + from js.jsobj import W_IntNumber + for i in xrange(from_index, -1, -1): + y = obj.get(unicode(i)) + if elem == y: + return W_IntNumber(i) + return W_IntNumber(-1) + + + at w_return def index_of(this, args): obj = this length = this.get(u'length').ToUInt32() diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,15 @@ from test.test_interp import assertv, assertp +def test_arrya_last_index_of(capsys): + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2));", "3", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(7));", "-1", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, 3));", "3", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, 2));", "0", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, -2));", "0", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, -1));", "3", capsys) + + def test_array_index_of(capsys): assertp("var a = [1,2,3]; print(a.indexOf(1));", "0", capsys) assertp("var a = [1,2,3]; print(a.indexOf(3));", "2", capsys) From noreply at buildbot.pypy.org Fri May 17 14:58:48 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 14:58:48 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Make space.unwrap call w_obj.unwrap(space) on W_Root which returns w_obj by default. Message-ID: <20130517125848.45B5B1C01D1@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64256:b93bb30957b8 Date: 2013-05-17 14:50 +0200 http://bitbucket.org/pypy/pypy/changeset/b93bb30957b8/ Log: Make space.unwrap call w_obj.unwrap(space) on W_Root which returns w_obj by default. diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -326,9 +326,6 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(self, space): - raise UnwrapError('cannot unwrap %r' % self) - class UnwrapError(Exception): pass diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -253,10 +253,9 @@ def unwrap(self, w_obj): """NOT_RPYTHON""" - if isinstance(w_obj, model.W_Object): + # _____ this code is here to support testing only _____ + if isinstance(w_obj, W_Root): return w_obj.unwrap(self) - if isinstance(w_obj, W_Root): - return w_obj raise model.UnwrapError("cannot unwrap: %r" % w_obj) def newint(self, intval): From noreply at buildbot.pypy.org Fri May 17 15:08:58 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 17 May 2013 15:08:58 +0200 (CEST) Subject: [pypy-commit] pypy default: crucial clarification Message-ID: <20130517130858.301171C01D1@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64257:cd4858fb3522 Date: 2013-05-17 15:08 +0200 http://bitbucket.org/pypy/pypy/changeset/cd4858fb3522/ Log: crucial clarification diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python From noreply at buildbot.pypy.org Fri May 17 15:16:06 2013 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 17 May 2013 15:16:06 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: fix VoidType. When not part of a RecordType it simply expands a new ndarray by its shape, using base type Message-ID: <20130517131606.2D47B1C1513@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpy-subarrays Changeset: r64258:12e7922e4209 Date: 2013-05-17 16:15 +0300 http://bitbucket.org/pypy/pypy/changeset/12e7922e4209/ Log: fix VoidType. When not part of a RecordType it simply expands a new ndarray by its shape, using base type diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -269,6 +269,7 @@ class W_VoidBox(W_FlexibleBox): def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType if space.isinstance_w(w_item, space.w_str): item = space.str_w(w_item) elif space.isinstance_w(w_item, space.w_int): @@ -287,7 +288,10 @@ except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -85,7 +85,6 @@ def getitem(self, arr, i): item = self.itemtype.read(arr, i, 0) - assert isinstance(item, interp_boxes.W_GenericBox) return item def getitem_bool(self, arr, i): diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2700,7 +2702,7 @@ assert a[1]['y'] == 1 def test_subarrays(self): - from numpypy import dtype, array + from numpypy import dtype, array, zeros d = dtype([("x", "int", 3), ("y", "float", 5)]) a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) @@ -2715,6 +2717,13 @@ assert len(list(a[0])) == 2 + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1721,7 +1721,7 @@ for k in range(self.get_element_size()): arr.storage[k + ofs] = box.arr.storage[k + box.ofs] - def read(self, arr, i, offset, dtype=None): + def readarray(self, arr, i, offset, dtype=None): from pypy.module.micronumpy.base import W_NDimArray if dtype is None: dtype = arr.dtype From noreply at buildbot.pypy.org Fri May 17 16:24:47 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 16:24:47 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: hg merge remove-dict-smm Message-ID: <20130517142447.BB21E1C32E8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64259:45c2aa4fb0ed Date: 2013-05-17 15:18 +0200 http://bitbucket.org/pypy/pypy/changeset/45c2aa4fb0ed/ Log: hg merge remove-dict-smm diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -324,7 +324,12 @@ if self._close: self._sock.close() else: - self._sock._decref_socketios() + try: + self._sock._decref_socketios() + except AttributeError: + pass # bah, someone built a _fileobject manually + # with some unexpected replacement of the + # _socketobject class self._sock = None def __del__(self): diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -2,7 +2,11 @@ import unittest import codecs import locale -import sys, StringIO, _testcapi +import sys, StringIO +try: + import _testcapi +except ImportError: + _testcapi = None class Queue(object): """ @@ -1387,8 +1391,7 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if (encoding not in broken_incremental_coders and - hasattr(_testcapi, 'codec_incrementalencoder')): + if encoding not in broken_incremental_coders and _testcapi: # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_descr.py b/lib-python/2.7/test/test_descr.py --- a/lib-python/2.7/test/test_descr.py +++ b/lib-python/2.7/test/test_descr.py @@ -2080,9 +2080,8 @@ except ImportError: pass else: - if hasattr(_testcapi, 'test_with_docstring'): - class X(object): - p = property(_testcapi.test_with_docstring) + class X(object): + p = property(_testcapi.test_with_docstring) def test_properties_plus(self): class C(object): diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -180,7 +180,7 @@ def test_traceback_format(self): if traceback_print is None: - return + raise unittest.SkipTest('Requires _testcapi') try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1612,7 +1612,7 @@ try: from _testcapi import unicode_encodedecimal except ImportError: - return + raise unittest.SkipTest('Requires _testcapi') self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -130,7 +130,7 @@ RegrTest('test_bz2.py', usemodules='bz2'), RegrTest('test_calendar.py'), RegrTest('test_call.py', core=True), - RegrTest('test_capi.py'), + RegrTest('test_capi.py', usemodules='cpyext'), RegrTest('test_cd.py'), RegrTest('test_cfgparser.py'), RegrTest('test_cgi.py'), @@ -177,7 +177,7 @@ RegrTest('test_cprofile.py'), RegrTest('test_crypt.py', usemodules='crypt'), RegrTest('test_csv.py', usemodules='_csv'), - RegrTest('test_ctypes.py', usemodules="_rawffi thread"), + RegrTest('test_ctypes.py', usemodules="_rawffi thread cpyext"), RegrTest('test_curses.py'), RegrTest('test_datetime.py', usemodules='binascii struct'), RegrTest('test_dbm.py'), diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -57,6 +57,6 @@ try: import cpyext except ImportError: - pass + raise ImportError("No module named '_testcapi'") else: compile_shared() diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.0' +release = '2.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0`_: the latest official release +* `Release 2.0.1`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0`: http://pypy.org/download.html +.. _`Release 2.0.1`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.1.rst @@ -0,0 +1,46 @@ +============================== +PyPy 2.0.1 - Bohr Smørrebrød +============================== + +We're pleased to announce PyPy 2.0.1. This is a stable bugfix release +over `2.0`_. You can download it here: + + http://pypy.org/download.html + +The fixes are mainly about fatal errors or crashes in our stdlib. See +below for more details. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +- fix an occasional crash in the JIT that ends in `RPython Fatal error: + NotImplementedError`__. + +- `id(x)` is now always a positive number (except on int/float/long/complex). + This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux). + +- fix crashes of callback-from-C-functions (with cffi) when used together + with Stackless features, on asmgcc (i.e. Linux only). Now `gevent should + work better`__. + +- work around an eventlet issue with `socket._decref_socketios()`__. + +.. __: https://bugs.pypy.org/issue1482 +.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html +.. __: https://bugs.pypy.org/issue1468 +.. _2.0: release-2.0.0.html + +Cheers, +arigo et. al. for the PyPy team 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,9 @@ .. branch: remove-set-smm Remove multi-methods on sets + +.. branch: numpy-subarrays +Implement subarrays for numpy + +.. branch: remove-dict-smm +Remove multi-methods on dict diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): 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 @@ -920,7 +920,7 @@ import app_main app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + [self.goal_dir] + assert sys.path == old_sys_path app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -114,8 +114,11 @@ ge = _make_comparison('ge') def hash(self): - h = (objectmodel.compute_identity_hash(self.ctype) ^ - rffi.cast(lltype.Signed, self._cdata)) + h = rffi.cast(lltype.Signed, self._cdata) + # To hash pointers in dictionaries. Assumes that h shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + h = h ^ (h >> 4) return self.space.wrap(h) def getitem(self, w_index): 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,8 +365,9 @@ BInt = new_primitive_type("int") BFloat = new_primitive_type("float") for i in range(1, 20): - if (hash(cast(BChar, chr(i))) != - hash(cast(BInt, i))): + x1 = cast(BChar, chr(i)) + x2 = cast(BInt, i) + if hash(x1) != hash(x2): break else: raise AssertionError("hashes are equal") @@ -2723,6 +2724,14 @@ assert x.__name__ == '' assert hasattr(x, '__doc__') +def test_different_types_of_ptr_equality(): + BVoidP = new_pointer_type(new_void_type()) + BIntP = new_pointer_type(new_primitive_type("int")) + x = cast(BVoidP, 12345) + assert x == cast(BIntP, 12345) + assert x != cast(BIntP, 12344) + assert hash(x) == hash(cast(BIntP, 12345)) + def test_version(): # this test is here mostly for PyPy assert __version__ == "0.6" diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py --- a/pypy/module/_ffi/test/test_funcptr.py +++ b/pypy/module/_ffi/test/test_funcptr.py @@ -74,9 +74,9 @@ from _ffi import CDLL, types # this should return *all* loaded libs, dlopen(NULL) dll = CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.getfunc('Py_IsInitialized', [], types.slong)() - assert res == 1 + # libm should be loaded + res = dll.getfunc('sqrt', [types.double], types.double)(1.0) + assert res == 1.0 def test_callfunc(self): from _ffi import CDLL, types @@ -139,7 +139,7 @@ def test_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr() { return &dummy; } DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; } """ @@ -158,7 +158,7 @@ def test_convert_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto """ @@ -170,7 +170,7 @@ def _as_ffi_pointer_(self, ffitype): assert ffitype is types.void_p return self.value - + libfoo = CDLL(self.libfoo_name) get_dummy = libfoo.getfunc('get_dummy', [], types.sint) get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) @@ -259,7 +259,7 @@ def test_typed_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto """ @@ -551,7 +551,7 @@ from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) raises(TypeError, "libfoo.getfunc('sum_xy', [types.void], types.sint)") - + def test_OSError_loading(self): from _ffi import CDLL, types raises(OSError, "CDLL('I do not exist')") @@ -606,7 +606,7 @@ from _rawffi import FUNCFLAG_STDCALL libm = CDLL(self.libm_name) pow_addr = libm.getaddressindll('pow') - wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', + wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double], types.double, FUNCFLAG_STDCALL) try: wrong_pow(2, 3) == 8 @@ -622,7 +622,7 @@ from _rawffi import FUNCFLAG_STDCALL kernel = WinDLL('Kernel32.dll') sleep_addr = kernel.getaddressindll('Sleep') - sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], + sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], types.void, FUNCFLAG_STDCALL) sleep(10) diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py --- a/pypy/module/sys/initpath.py +++ b/pypy/module/sys/initpath.py @@ -68,7 +68,7 @@ If it cannot be found, return (None, None). """ if executable == '': - return None, None + executable = 'pypy-c' search = executable while True: dirname = resolvedirof(search) diff --git a/pypy/module/sys/system.py b/pypy/module/sys/system.py --- a/pypy/module/sys/system.py +++ b/pypy/module/sys/system.py @@ -1,6 +1,6 @@ """Information about the current system.""" from pypy.interpreter import gateway -from rpython.rlib import rfloat, rbigint +from rpython.rlib import rbigint, rfloat from rpython.rtyper.lltypesystem import rffi @@ -47,7 +47,6 @@ return space.call_function(w_float_info, space.newtuple(info_w)) def get_long_info(space): - #assert rbigint.SHIFT == 31 bits_per_digit = rbigint.SHIFT sizeof_digit = rffi.sizeof(rbigint.STORE_TYPE) info_w = [ @@ -58,7 +57,4 @@ return space.call_function(w_long_info, space.newtuple(info_w)) def get_float_repr_style(space): - if rfloat.USE_SHORT_FLOAT_REPR: - return space.wrap("short") - else: - return space.wrap("legacy") + return space.wrap("short" if rfloat.USE_SHORT_FLOAT_REPR else "legacy") diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py --- a/pypy/module/sys/test/test_initpath.py +++ b/pypy/module/sys/test/test_initpath.py @@ -16,9 +16,12 @@ build_hierarchy(tmpdir) path, prefix = find_stdlib(None, str(pypy)) assert prefix == tmpdir - # shouldn't find stdlib if executable == '' even if parent dir has a stdlib - monkeypatch.chdir(tmpdir.join('bin')) - assert find_stdlib(None, '') == (None, None) + # in executable is None look for stdlib based on the working directory + # see lib-python/2.7/test/test_sys.py:test_executable + _, prefix = find_stdlib(None, '') + cwd = os.path.dirname(os.path.realpath(__file__)) + assert prefix is not None + assert cwd.startswith(str(prefix)) @py.test.mark.skipif('not hasattr(os, "symlink")') def test_find_stdlib_follow_symlink(tmpdir): diff --git a/pypy/objspace/fake/checkmodule.py b/pypy/objspace/fake/checkmodule.py --- a/pypy/objspace/fake/checkmodule.py +++ b/pypy/objspace/fake/checkmodule.py @@ -5,7 +5,6 @@ def checkmodule(*modnames): config = get_pypy_config(translating=True) space = FakeObjSpace(config) - space.setup() seeobj_w = [] for modname in modnames: mod = __import__('pypy.module.%s' % modname, None, None, ['__doc__']) diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py --- a/pypy/objspace/fake/objspace.py +++ b/pypy/objspace/fake/objspace.py @@ -110,6 +110,7 @@ def __init__(self, config=None): self._seen_extras = [] ObjSpace.__init__(self, config=config) + self.setup() def _freeze_(self): return True diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,19 +1,19 @@ -import py, sys -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.setobject import set_typedef as settypedef -from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef +from rpython.rlib import rerased, jit +from rpython.rlib.debug import mark_dict_non_null from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint -from rpython.rlib.debug import mark_dict_non_null from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib import rerased, jit UNROLL_CUTOFF = 5 + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -40,9 +40,20 @@ w_dct.length() <= UNROLL_CUTOFF) -class W_DictMultiObject(W_Object): - from pypy.objspace.std.dicttype import dict_typedef as typedef +def negate(f): + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator +class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, strdict=False, kwargs=False): @@ -108,6 +119,230 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + @staticmethod + def descr_new(space, w_dicttype, __args__): + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + + @staticmethod + def descr_fromkeys(space, w_type, w_keys, w_fill=None): + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + + def descr_init(self, space, __args__): + init_or_update(space, self, __args__, 'dict') + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if space.is_w(self, w_other): + return space.w_True + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + + if self.length() != w_other.length(): + return space.w_False + iteratorimplementation = self.iteritems() + while 1: + w_key, w_val = iteratorimplementation.next_item() + if w_key is None: + break + w_rightval = w_other.getitem(w_key) + if w_rightval is None: + return space.w_False + if not space.eq_w(w_val, w_rightval): + return space.w_False + return space.w_True + + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return self._compare_lt(space, w_other) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return w_other._compare_lt(space, self) + + def _compare_lt(self, space, w_other): + # Different sizes, no problem + if self.length() < w_other.length(): + return space.w_True + if self.length() > w_other.length(): + return space.w_False + + # Same size + w_leftdiff, w_leftval = characterize(space, self, w_other) + if w_leftdiff is None: + return space.w_False + w_rightdiff, w_rightval = characterize(space, w_other, self) + if w_rightdiff is None: + # w_leftdiff is not None, w_rightdiff is None + return space.w_True + w_res = space.lt(w_leftdiff, w_rightdiff) + if (not space.is_true(w_res) and + space.eq_w(w_leftdiff, w_rightdiff) and + w_rightval is not None): + w_res = space.lt(w_leftval, w_rightval) + return w_res + + descr_ne = negate(descr_eq) + descr_le = negate(descr_gt) + descr_ge = negate(descr_lt) + + def descr_len(self, space): + return space.wrap(self.length()) + + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_contains(self, space, w_key): + return space.newbool(self.getitem(w_key) is not None) + + def descr_getitem(self, space, w_key): + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + + w_missing_item = self.missing_method(space, w_key) + if w_missing_item is not None: + return w_missing_item + + space.raise_key_error(w_key) + + def descr_setitem(self, space, w_newkey, w_newvalue): + self.setitem(w_newkey, w_newvalue) + + def descr_delitem(self, space, w_key): + try: + self.delitem(w_key) + except KeyError: + space.raise_key_error(w_key) + + def descr_reversed(self, space): + raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + + def descr_copy(self, space): + """D.copy() -> a shallow copy of D""" + w_new = W_DictMultiObject.allocate_and_init_instance(space) + update1_dict_dict(space, w_new, self) + return w_new + + def descr_items(self, space): + """D.items() -> list of D's (key, value) pairs, as 2-tuples""" + return space.newlist(self.items()) + + def descr_keys(self, space): + """D.keys() -> list of D's keys""" + return self.w_keys() + + def descr_values(self, space): + """D.values() -> list of D's values""" + return space.newlist(self.values()) + + def descr_iteritems(self, space): + """D.iteritems() -> an iterator over the (key, value) items of D""" + return W_DictMultiIterItemsObject(space, self.iteritems()) + + def descr_iterkeys(self, space): + """D.iterkeys() -> an iterator over the keys of D""" + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_itervalues(self, space): + """D.itervalues() -> an iterator over the values of D""" + return W_DictMultiIterValuesObject(space, self.itervalues()) + + def descr_viewitems(self, space): + """D.viewitems() -> a set-like object providing a view on D's items""" + return W_DictViewItemsObject(space, self) + + def descr_viewkeys(self, space): + """D.viewkeys() -> a set-like object providing a view on D's keys""" + return W_DictViewKeysObject(space, self) + + def descr_viewvalues(self, space): + """D.viewvalues() -> an object providing a view on D's values""" + return W_DictViewValuesObject(space, self) + + def descr_has_key(self, space, w_key): + """D.has_key(k) -> True if D has a key k, else False""" + return space.newbool(self.getitem(w_key) is not None) + + def descr_clear(self, space): + """D.clear() -> None. Remove all items from D.""" + self.clear() + + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_get(self, space, w_key, w_default): + """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + else: + return w_default + + @gateway.unwrap_spec(defaults_w='args_w') + def descr_pop(self, space, w_key, defaults_w): + """D.pop(k[,d]) -> v, remove specified key and return the + corresponding value\nIf key is not found, d is returned if given, + otherwise KeyError is raised + """ + len_defaults = len(defaults_w) + if len_defaults > 1: + raise operationerrfmt(space.w_TypeError, + "pop expected at most 2 arguments, got %d", + 1 + len_defaults) + w_item = self.getitem(w_key) + if w_item is None: + if len_defaults > 0: + return defaults_w[0] + else: + space.raise_key_error(w_key) + else: + self.delitem(w_key) + return w_item + + def descr_popitem(self, space): + """D.popitem() -> (k, v), remove and return some (key, value) pair as + a\n2-tuple; but raise KeyError if D is empty""" + try: + w_key, w_value = self.popitem() + except KeyError: + raise OperationError(space.w_KeyError, + space.wrap("popitem(): dictionary is empty")) + return space.newtuple([w_key, w_value]) + + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_setdefault(self, space, w_key, w_default): + """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" + return self.setdefault(w_key, w_default) + + def descr_update(self, space, __args__): + """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] + = E[k]\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in + F: D[k] = F[k]""" + init_or_update(space, self, __args__, 'dict.update') + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -128,8 +363,87 @@ _add_indirections() + +app = gateway.applevel(''' + def dictrepr(currently_in_repr, d): + if len(d) == 0: + return "{}" + dict_id = id(d) + if dict_id in currently_in_repr: + return '{...}' + currently_in_repr[dict_id] = 1 + try: + items = [] + # XXX for now, we cannot use iteritems() at app-level because + # we want a reasonable result instead of a RuntimeError + # even if the dict is mutated by the repr() in the loop. + for k, v in dict.items(d): + items.append(repr(k) + ": " + repr(v)) + return "{" + ', '.join(items) + "}" + finally: + try: + del currently_in_repr[dict_id] + except: + pass +''', filename=__file__) + +dictrepr = app.interphook("dictrepr") + + +W_DictMultiObject.typedef = StdTypeDef("dict", + __doc__ = '''dict() -> new empty dictionary. +dict(mapping) -> new dictionary initialized from a mapping object\'s + (key, value) pairs. +dict(seq) -> new dictionary initialized as if via: + d = {} + for k, v in seq: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)''', + __new__ = gateway.interp2app(W_DictMultiObject.descr_new), + fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), + __hash__ = None, + __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), + __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + + __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), + __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), + __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), + __le__ = gateway.interp2app(W_DictMultiObject.descr_le), + __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), + __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), + + __len__ = gateway.interp2app(W_DictMultiObject.descr_len), + __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), + __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + + __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), + copy = gateway.interp2app(W_DictMultiObject.descr_copy), + items = gateway.interp2app(W_DictMultiObject.descr_items), + keys = gateway.interp2app(W_DictMultiObject.descr_keys), + values = gateway.interp2app(W_DictMultiObject.descr_values), + iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), + has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), + clear = gateway.interp2app(W_DictMultiObject.descr_clear), + get = gateway.interp2app(W_DictMultiObject.descr_get), + pop = gateway.interp2app(W_DictMultiObject.descr_pop), + popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), + setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), + update = gateway.interp2app(W_DictMultiObject.descr_update), + ) + + class DictStrategy(object): - def __init__(self, space): self.space = space @@ -171,7 +485,6 @@ # it ends up taking n**2 time, because the next() calls below # will take longer and longer. But all interesting strategies # provide a better one. - space = self.space iterator = self.iteritems(w_dict) w_key, w_value = iterator.next_item() self.delitem(w_dict, w_key) @@ -195,8 +508,8 @@ def view_as_kwargs(self, w_dict): return (None, None) + class EmptyDictStrategy(DictStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -301,6 +614,7 @@ def getiteritems(self, w_dict): return iter([(None, None)]) + # Iterator Implementation base classes def _new_next(TP): @@ -308,7 +622,7 @@ EMPTY = None else: EMPTY = None, None - + def next(self): if self.dictimplementation is None: return EMPTY @@ -372,7 +686,7 @@ wrapvalue = lambda space, key : key else: wrapvalue = dictimpl.wrapvalue.im_func - + class IterClassKeys(BaseKeyIterator): def __init__(self, space, strategy, impl): self.iterator = strategy.getiterkeys(impl) @@ -424,11 +738,6 @@ create_iterator_classes(EmptyDictStrategy) -registerimplementation(W_DictMultiObject) - -# DictImplementation lattice -# XXX fix me - # concrete subclasses of the above @@ -543,7 +852,6 @@ class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -576,8 +884,8 @@ create_iterator_classes(ObjectDictStrategy) + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -642,7 +950,6 @@ class UnicodeDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("unicode") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -744,9 +1051,6 @@ create_iterator_classes(IntDictStrategy) -init_signature = Signature(['seq_or_map'], None, 'kwargs') -init_defaults = [None] - def update1(space, w_dict, w_data): if space.findattr(w_data, space.wrap("keys")) is None: @@ -788,6 +1092,9 @@ w_dict.setitem(w_key, w_value) +init_signature = Signature(['seq_or_map'], None, 'kwargs') +init_defaults = [None] + def init_or_update(space, w_dict, __args__, funcname): w_src, w_kwds = __args__.parse_obj( None, funcname, @@ -798,61 +1105,6 @@ if space.is_true(w_kwds): update1(space, w_dict, w_kwds) -def init__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict') - -def dict_update__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict.update') - -def getitem__DictMulti_ANY(space, w_dict, w_key): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - - w_missing_item = w_dict.missing_method(space, w_key) - if w_missing_item is not None: - return w_missing_item - - space.raise_key_error(w_key) - -def setitem__DictMulti_ANY_ANY(space, w_dict, w_newkey, w_newvalue): - w_dict.setitem(w_newkey, w_newvalue) - -def delitem__DictMulti_ANY(space, w_dict, w_key): - try: - w_dict.delitem(w_key) - except KeyError: - space.raise_key_error(w_key) - -def len__DictMulti(space, w_dict): - return space.wrap(w_dict.length()) - -def contains__DictMulti_ANY(space, w_dict, w_key): - return space.newbool(w_dict.getitem(w_key) is not None) - -dict_has_key__DictMulti_ANY = contains__DictMulti_ANY - -def iter__DictMulti(space, w_dict): - return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) - -def eq__DictMulti_DictMulti(space, w_left, w_right): - if space.is_w(w_left, w_right): - return space.w_True - - if w_left.length() != w_right.length(): - return space.w_False - iteratorimplementation = w_left.iteritems() - while 1: - w_key, w_val = iteratorimplementation.next_item() - if w_key is None: - break - w_rightval = w_right.getitem(w_key) - if w_rightval is None: - return space.w_False - if not space.eq_w(w_val, w_rightval): - return space.w_False - return space.w_True - def characterize(space, w_a, w_b): """ (similar to CPython) returns the smallest key in acontent for which b's value is different or absent and this value """ @@ -874,105 +1126,11 @@ w_smallest_diff_a_key = w_key return w_smallest_diff_a_key, w_its_value -def lt__DictMulti_DictMulti(space, w_left, w_right): - # Different sizes, no problem - if w_left.length() < w_right.length(): - return space.w_True - if w_left.length() > w_right.length(): - return space.w_False - - # Same size - w_leftdiff, w_leftval = characterize(space, w_left, w_right) - if w_leftdiff is None: - return space.w_False - w_rightdiff, w_rightval = characterize(space, w_right, w_left) - if w_rightdiff is None: - # w_leftdiff is not None, w_rightdiff is None - return space.w_True - w_res = space.lt(w_leftdiff, w_rightdiff) - if (not space.is_true(w_res) and - space.eq_w(w_leftdiff, w_rightdiff) and - w_rightval is not None): - w_res = space.lt(w_leftval, w_rightval) - return w_res - -def dict_copy__DictMulti(space, w_self): - w_new = W_DictMultiObject.allocate_and_init_instance(space) - update1_dict_dict(space, w_new, w_self) - return w_new - -def dict_items__DictMulti(space, w_self): - return space.newlist(w_self.items()) - -def dict_keys__DictMulti(space, w_self): - return w_self.w_keys() - -def dict_values__DictMulti(space, w_self): - return space.newlist(w_self.values()) - -def dict_iteritems__DictMulti(space, w_self): - return W_DictMultiIterItemsObject(space, w_self.iteritems()) - -def dict_iterkeys__DictMulti(space, w_self): - return W_DictMultiIterKeysObject(space, w_self.iterkeys()) - -def dict_itervalues__DictMulti(space, w_self): - return W_DictMultiIterValuesObject(space, w_self.itervalues()) - -def dict_viewitems__DictMulti(space, w_self): - return W_DictViewItemsObject(space, w_self) - -def dict_viewkeys__DictMulti(space, w_self): - return W_DictViewKeysObject(space, w_self) - -def dict_viewvalues__DictMulti(space, w_self): - return W_DictViewValuesObject(space, w_self) - -def dict_clear__DictMulti(space, w_self): - w_self.clear() - -def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default - -def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - return w_dict.setdefault(w_key, w_default) - -def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w): - len_defaults = len(defaults_w) - if len_defaults > 1: - raise operationerrfmt(space.w_TypeError, - "pop expected at most 2 arguments, got %d", - 1 + len_defaults) - w_item = w_dict.getitem(w_key) - if w_item is None: - if len_defaults > 0: - return defaults_w[0] - else: - space.raise_key_error(w_key) - else: - w_dict.delitem(w_key) - return w_item - -def dict_popitem__DictMulti(space, w_dict): - try: - w_key, w_value = w_dict.popitem() - except KeyError: - raise OperationError(space.w_KeyError, - space.wrap("popitem(): dictionary is empty")) - return space.newtuple([w_key, w_value]) - # ____________________________________________________________ # Iteration - -class W_BaseDictMultiIterObject(W_Object): - from pypy.objspace.std.dicttype import dictiter_typedef as typedef - +class W_BaseDictMultiIterObject(W_Root): _immutable_fields_ = ["iteratorimplementation"] ignore_for_isinstance_cache = True @@ -981,139 +1139,199 @@ w_self.space = space w_self.iteratorimplementation = iteratorimplementation + def descr_iter(self, space): + return self + + def descr_length_hint(self, space): + return space.wrap(self.iteratorimplementation.length()) + + def descr_reduce(self, space): + """ + This is a slightly special case of pickling. + Since iteration over a dict is a bit hairy, + we do the following: + - create a clone of the dict iterator + - run it to the original position + - collect all remaining elements into a list + At unpickling time, we just use that list + and create an iterator on it. + This is of course not the standard way. + + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('dictiter_surrogate_new') + w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) + + raise OperationError( + space.w_TypeError, + space.wrap("can't pickle dictionary-keyiterator objects")) + # XXXXXX get that working again + + # we cannot call __init__ since we don't have the original dict + if isinstance(self, W_DictIter_Keys): + w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) + elif isinstance(self, W_DictIter_Values): + w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) + elif isinstance(self, W_DictIter_Items): + w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + else: + msg = "unsupported dictiter type '%s' during pickling" % (self,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_clone.space = space + w_clone.content = self.content + w_clone.len = self.len + w_clone.pos = 0 + w_clone.setup_iterator() + # spool until we have the same pos + while w_clone.pos < self.pos: + w_obj = w_clone.next_entry() + w_clone.pos += 1 + stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] + w_res = space.newlist(stuff) + tup = [ + w_res + ] + w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + return w_ret + + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key = iteratorimplementation.next_key() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterValuesObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_value = iteratorimplementation.next_value() + if w_value is not None: + return w_value + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterItemsObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key, w_value = iteratorimplementation.next_item() + if w_key is not None: + return space.newtuple([w_key, w_value]) + raise OperationError(space.w_StopIteration, space.w_None) -registerimplementation(W_DictMultiIterKeysObject) -registerimplementation(W_DictMultiIterValuesObject) -registerimplementation(W_DictMultiIterItemsObject) +W_DictMultiIterItemsObject.typedef = StdTypeDef( + "dict_iteritems", + __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterKeysObject(space, w_dictiter): - return w_dictiter +W_DictMultiIterKeysObject.typedef = StdTypeDef( + "dict_iterkeys", + __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def next__DictMultiIterKeysObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key = iteratorimplementation.next_key() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) +W_DictMultiIterValuesObject.typedef = StdTypeDef( + "dict_itervalues", + __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterValuesObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterValuesObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_value = iteratorimplementation.next_value() - if w_value is not None: - return w_value - raise OperationError(space.w_StopIteration, space.w_None) - -def iter__DictMultiIterItemsObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterItemsObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key, w_value = iteratorimplementation.next_item() - if w_key is not None: - return space.newtuple([w_key, w_value]) - raise OperationError(space.w_StopIteration, space.w_None) # ____________________________________________________________ # Views -class W_DictViewObject(W_Object): +class W_DictViewObject(W_Root): def __init__(w_self, space, w_dict): w_self.w_dict = w_dict -class W_DictViewKeysObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_keys_typedef as typedef -registerimplementation(W_DictViewKeysObject) + def descr_repr(self, space): + w_seq = space.call_function(space.w_list, self) + w_repr = space.repr(w_seq) + return space.wrap("%s(%s)" % (space.type(self).getname(space), + space.str_w(w_repr))) + + def descr_eq(self, space, w_otherview): + if not space.eq_w(space.len(self), space.len(w_otherview)): + return space.w_False + + w_iter = space.iter(self) + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if not space.is_true(space.contains(w_otherview, w_item)): + return space.w_False + return space.w_True + + def descr_len(self, space): + return space.len(self.w_dict) + + def descr_and(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "intersection_update", w_otherview) + return w_set + + def descr_or(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "update", w_otherview) + return w_set + + def descr_xor(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "symmetric_difference_update", w_otherview) + return w_set class W_DictViewItemsObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_items_typedef as typedef -registerimplementation(W_DictViewItemsObject) + def descr_iter(self, space): + return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) + +class W_DictViewKeysObject(W_DictViewObject): + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) class W_DictViewValuesObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_values_typedef as typedef -registerimplementation(W_DictViewValuesObject) + def descr_iter(self, space): + return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) -def len__DictViewKeys(space, w_dictview): - return space.len(w_dictview.w_dict) -len__DictViewItems = len__DictViewValues = len__DictViewKeys +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewItemsObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), + __or__ = gateway.interp2app(W_DictViewItemsObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewItemsObject.descr_xor) + ) -def iter__DictViewKeys(space, w_dictview): - return dict_iterkeys__DictMulti(space, w_dictview.w_dict) -def iter__DictViewItems(space, w_dictview): - return dict_iteritems__DictMulti(space, w_dictview.w_dict) -def iter__DictViewValues(space, w_dictview): - return dict_itervalues__DictMulti(space, w_dictview.w_dict) +W_DictViewKeysObject.typedef = StdTypeDef( + "dict_keys", + __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewKeysObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), + __or__ = gateway.interp2app(W_DictViewKeysObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewKeysObject.descr_xor) + ) -def all_contained_in(space, w_dictview, w_otherview): - w_iter = space.iter(w_dictview) - - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - - return space.w_True - -def eq__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - if space.eq_w(space.len(w_dictview), space.len(w_otherview)): - return all_contained_in(space, w_dictview, w_otherview) - return space.w_False -eq__DictViewKeys_settypedef = eq__DictViewKeys_DictViewKeys -eq__DictViewKeys_frozensettypedef = eq__DictViewKeys_DictViewKeys - -eq__DictViewKeys_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_settypedef = eq__DictViewItems_DictViewItems -eq__DictViewItems_frozensettypedef = eq__DictViewItems_DictViewItems - -def repr__DictViewKeys(space, w_dictview): - w_seq = space.call_function(space.w_list, w_dictview) - w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), - space.str_w(w_repr))) -repr__DictViewItems = repr__DictViewKeys -repr__DictViewValues = repr__DictViewKeys - -def and__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set -and__DictViewKeys_settypedef = and__DictViewKeys_DictViewKeys -and__DictViewItems_DictViewItems = and__DictViewKeys_DictViewKeys -and__DictViewItems_settypedef = and__DictViewKeys_DictViewKeys - -def or__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "update", w_otherview) - return w_set -or__DictViewKeys_settypedef = or__DictViewKeys_DictViewKeys -or__DictViewItems_DictViewItems = or__DictViewKeys_DictViewKeys -or__DictViewItems_settypedef = or__DictViewKeys_DictViewKeys - -def xor__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set -xor__DictViewKeys_settypedef = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_DictViewItems = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_settypedef = xor__DictViewKeys_DictViewKeys - -# ____________________________________________________________ - -from pypy.objspace.std import dicttype -register_all(vars(), dicttype) +W_DictViewValuesObject.typedef = StdTypeDef( + "dict_values", + __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewValuesObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), + __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) + ) diff --git a/pypy/objspace/std/dicttype.py b/pypy/objspace/std/dicttype.py deleted file mode 100644 --- a/pypy/objspace/std/dicttype.py +++ /dev/null @@ -1,221 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter.mixedmodule import MixedModule -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.register_all import register_all - -dict_copy = SMM('copy', 1, - doc='D.copy() -> a shallow copy of D') -dict_items = SMM('items', 1, - doc="D.items() -> list of D's (key, value) pairs, as" - ' 2-tuples') -dict_keys = SMM('keys', 1, - doc="D.keys() -> list of D's keys") -dict_values = SMM('values', 1, - doc="D.values() -> list of D's values") -dict_has_key = SMM('has_key', 2, - doc='D.has_key(k) -> True if D has a key k, else False') -dict_clear = SMM('clear', 1, - doc='D.clear() -> None. Remove all items from D.') -dict_get = SMM('get', 3, defaults=(None,), - doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' - ' to None.') -dict_pop = SMM('pop', 2, varargs_w=True, - doc='D.pop(k[,d]) -> v, remove specified key and return' - ' the corresponding value\nIf key is not found, d is' - ' returned if given, otherwise KeyError is raised') -dict_popitem = SMM('popitem', 1, - doc='D.popitem() -> (k, v), remove and return some (key,' - ' value) pair as a\n2-tuple; but raise KeyError if D' - ' is empty') -dict_setdefault = SMM('setdefault', 3, defaults=(None,), - doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' - ' if k not in D') -dict_update = SMM('update', 1, general__args__=True, - doc='D.update(E, **F) -> None. Update D from E and F:' - ' for k in E: D[k] = E[k]\n(if E has keys else: for' - ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' - ' F[k]') -dict_iteritems = SMM('iteritems', 1, - doc='D.iteritems() -> an iterator over the (key, value)' - ' items of D') -dict_iterkeys = SMM('iterkeys', 1, - doc='D.iterkeys() -> an iterator over the keys of D') -dict_itervalues = SMM('itervalues', 1, - doc='D.itervalues() -> an iterator over the values of D') -dict_viewkeys = SMM('viewkeys', 1, - doc="D.viewkeys() -> a set-like object providing a view on D's keys") -dict_viewitems = SMM('viewitems', 1, - doc="D.viewitems() -> a set-like object providing a view on D's items") -dict_viewvalues = SMM('viewvalues', 1, - doc="D.viewvalues() -> an object providing a view on D's values") -dict_reversed = SMM('__reversed__', 1) - -def dict_reversed__ANY(space, w_dict): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - -register_all(vars(), globals()) - -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - - -app = gateway.applevel(''' - def dictrepr(currently_in_repr, d): - if len(d) == 0: - return "{}" - dict_id = id(d) - if dict_id in currently_in_repr: - return '{...}' - currently_in_repr[dict_id] = 1 - try: - items = [] - # XXX for now, we cannot use iteritems() at app-level because - # we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in dict.items(d): - items.append(repr(k) + ": " + repr(v)) - return "{" + ', '.join(items) + "}" - finally: - try: - del currently_in_repr[dict_id] - except: - pass -''', filename=__file__) - -dictrepr = app.interphook("dictrepr") - - -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - -dict_typedef = StdTypeDef("dict", - __doc__ = '''dict() -> new empty dictionary. -dict(mapping) -> new dictionary initialized from a mapping object\'s - (key, value) pairs. -dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v -dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), - ) -dict_typedef.registermethods(globals()) - -# ____________________________________________________________ - -def descr_dictiter__length_hint__(space, w_self): - from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject - assert isinstance(w_self, W_BaseDictMultiIterObject) - return space.wrap(w_self.iteratorimplementation.length()) - - -def descr_dictiter__reduce__(w_self, space): - """ - This is a slightly special case of pickling. - Since iteration over a dict is a bit hairy, - we do the following: - - create a clone of the dict iterator - - run it to the original position - - collect all remaining elements into a list - At unpickling time, we just use that list - and create an iterator on it. - This is of course not the standard way. - - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) - - raise OperationError( - space.w_TypeError, - space.wrap("can't pickle dictionary-keyiterator objects")) - # XXXXXX get that working again - - # we cannot call __init__ since we don't have the original dict - if isinstance(w_self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(w_self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(w_self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) - else: - msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_clone.space = space - w_clone.content = w_self.content - w_clone.len = w_self.len - w_clone.pos = 0 - w_clone.setup_iterator() - # spool until we have the same pos - while w_clone.pos < w_self.pos: - w_obj = w_clone.next_entry() - w_clone.pos += 1 - stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] - w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) - return w_ret - -# ____________________________________________________________ - - -dictiter_typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), - __reduce__ = gateway.interp2app(descr_dictiter__reduce__), - ) - -# ____________________________________________________________ -# Dict views - -dict_keys_typedef = StdTypeDef( - "dict_keys", - ) - -dict_items_typedef = StdTypeDef( - "dict_items", - ) - -dict_values_typedef = StdTypeDef( - "dict_values", - ) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -12,6 +12,7 @@ from pypy.objspace.std.register_all import register_all from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint, intmask from pypy.objspace.std import model +from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.interpreter.special import Ellipsis from pypy.interpreter.pycode import PyCode from pypy.interpreter import gateway, unicodehelper @@ -24,7 +25,6 @@ from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.longobject import W_LongObject, newlong @@ -309,15 +309,18 @@ return space.newlist(items_w) register(TYPE_LIST, unmarshal_List) -def marshal_w__DictMulti(space, w_dict, m): +def marshal_w_dict(space, w_dict, m): + if not isinstance(w_dict, W_DictMultiObject): + raise_exception(space, "unmarshallable object") m.start(TYPE_DICT) for w_tuple in w_dict.items(): w_key, w_value = space.fixedview(w_tuple, 2) m.put_w_obj(w_key) m.put_w_obj(w_value) m.atom(TYPE_NULL) +handled_by_any.append(('dict', marshal_w_dict)) -def unmarshal_DictMulti(space, u, tc): +def unmarshal_dict(space, u, tc): # since primitive lists are not optimized and we don't know # the dict size in advance, use the dict's setitem instead # of building a list of tuples. @@ -329,7 +332,7 @@ w_value = u.get_w_obj() space.setitem(w_dic, w_key, w_value) return w_dic -register(TYPE_DICT, unmarshal_DictMulti) +register(TYPE_DICT, unmarshal_dict) def unmarshal_NULL(self, u, tc): return None diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -40,7 +40,6 @@ from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef - from pypy.objspace.std.dicttype import dict_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -81,6 +80,7 @@ # not-multimethod based types + self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -92,10 +92,6 @@ floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], listobject.W_ListObject: [], - dictmultiobject.W_DictMultiObject: [], - dictmultiobject.W_DictMultiIterKeysObject: [], - dictmultiobject.W_DictMultiIterValuesObject: [], - dictmultiobject.W_DictMultiIterItemsObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -108,9 +104,6 @@ iterobject.W_FastTupleIterObject: [], iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], - dictmultiobject.W_DictViewKeysObject: [], - dictmultiobject.W_DictViewItemsObject: [], - dictmultiobject.W_DictViewValuesObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], } @@ -333,9 +326,6 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(self, space): - raise UnwrapError('cannot unwrap %r' % self) - class UnwrapError(Exception): pass diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -253,10 +253,9 @@ def unwrap(self, w_obj): """NOT_RPYTHON""" - if isinstance(w_obj, model.W_Object): + # _____ this code is here to support testing only _____ + if isinstance(w_obj, W_Root): return w_obj.unwrap(self) - if isinstance(w_obj, W_Root): - return w_obj raise model.UnwrapError("cannot unwrap: %r" % w_obj) def newint(self, intval): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -2,8 +2,7 @@ import py from pypy.objspace.std.dictmultiobject import (W_DictMultiObject, - setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, StringDictStrategy, - ObjectDictStrategy) + StringDictStrategy, ObjectDictStrategy) class TestW_DictObject(object): @@ -409,6 +408,24 @@ assert {'a': 1 } < { 'b': 1} assert {'a': 1, 'x': 2 } < { 'b': 1, 'x': 2} + def test_other_rich_cmp(self): + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} + + assert d1 <= d2 + assert d1 <= d3 + assert not d1 <= d4 + + assert not d1 > d2 + assert not d1 > d3 + assert d1 > d4 + + assert d1 >= d2 + assert not d1 >= d3 + assert d1 >= d4 + def test_str_repr(self): assert '{}' == str({}) assert '{1: 2}' == str({1: 2}) @@ -604,6 +621,9 @@ assert d.values() == [] assert d.keys() == [] + def test_cmp_with_noncmp(self): + assert not {} > object() + class AppTest_DictMultiObject(AppTest_DictObject): def test_emptydict_unhashable(self): @@ -971,10 +991,10 @@ pydict = {} for i in range(N): x = randint(-N, N) - setitem__DictMulti_ANY_ANY(self.space, d, x, i) + d.descr_setitem(self.space, x, i) pydict[x] = i for key, value in pydict.iteritems(): - assert value == getitem__DictMulti_ANY(self.space, d, key) + assert value == d.descr_getitem(self.space, key) class BaseTestRDictImplementation: diff --git a/rpython/memory/gctransform/asmgcroot.py b/rpython/memory/gctransform/asmgcroot.py --- a/rpython/memory/gctransform/asmgcroot.py +++ b/rpython/memory/gctransform/asmgcroot.py @@ -331,6 +331,11 @@ [annmodel.SomeInteger(), annmodel.SomeAddress()], annmodel.s_None) + # + # check that the order of the need_*() is correct for us: if we + # need both threads and stacklets, need_thread_support() must be + # called first, to initialize self.belongs_to_current_thread. + assert not hasattr(self, 'gc_detach_callback_pieces_ptr') def walk_stack_roots(self, collect_stack_root): gcdata = self.gcdata diff --git a/rpython/memory/gctransform/framework.py b/rpython/memory/gctransform/framework.py --- a/rpython/memory/gctransform/framework.py +++ b/rpython/memory/gctransform/framework.py @@ -236,9 +236,10 @@ # thread support if translator.config.translation.continuation: root_walker.stacklet_support = True - root_walker.need_stacklet_support(self, getfn) if translator.config.translation.thread: root_walker.need_thread_support(self, getfn) + if root_walker.stacklet_support: + root_walker.need_stacklet_support(self, getfn) self.layoutbuilder.encode_type_shapes_now() diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -57,7 +57,8 @@ # This thing is imported by any target which has any API, so it'll get # registered -RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void) +RPython_StartupCode = rffi.llexternal('RPython_StartupCode', [], lltype.Void, + _nowrapper=True) @entrypoint('main', [], c_name='rpython_startup_code') def rpython_startup_code(): diff --git a/rpython/rtyper/rpbc.py b/rpython/rtyper/rpbc.py --- a/rpython/rtyper/rpbc.py +++ b/rpython/rtyper/rpbc.py @@ -529,7 +529,7 @@ im_selves = [] for desc in s_pbc.descriptions: - assert desc.funcdesc is self.funcdesc + assert desc.funcdesc is self.funcdesc, "You can't mix a set of methods on a frozen PBC in RPython that are different underlaying functions" im_selves.append(desc.frozendesc) self.s_im_self = annmodel.SomePBC(im_selves) From noreply at buildbot.pypy.org Fri May 17 16:24:49 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 16:24:49 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove list from multi-method table. Message-ID: <20130517142449.075D41C32E8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64260:7fa96304949d Date: 2013-05-17 15:30 +0200 http://bitbucket.org/pypy/pypy/changeset/7fa96304949d/ Log: Remove list from multi-method table. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,6 +1,3 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.generator import GeneratorIterator from pypy.objspace.std.inttype import wrapint @@ -9,6 +6,7 @@ from pypy.interpreter.gateway import WrappedDefault, unwrap_spec, applevel,\ interp2app from pypy.interpreter import baseobjspace +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.signature import Signature from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, resizelist_hint) @@ -22,7 +20,7 @@ UNROLL_CUTOFF = 5 -class W_AbstractListObject(W_Object): +class W_AbstractListObject(W_Root): __slots__ = () def make_range_list(space, start, step, length): @@ -678,8 +676,6 @@ return space.w_None -registerimplementation(W_ListObject) - class ListStrategy(object): sizehint = -1 @@ -1676,12 +1672,9 @@ # ____________________________________________________________ -# ____________________________________________________________ - def get_list_index(space, w_index): return space.getindex_w(w_index, space.w_IndexError, "list index") -register_all(vars(), globals()) W_ListObject.typedef = StdTypeDef("list", __doc__ = """list() -> new list @@ -1726,6 +1719,3 @@ insert = interp2app(W_ListObject.descr_insert), remove = interp2app(W_ListObject.descr_remove), ) -W_ListObject.typedef.registermethods(globals()) - -list_typedef = W_ListObject.typedef diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -39,7 +39,6 @@ from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef - from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -80,6 +79,7 @@ # not-multimethod based types + self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -91,7 +91,6 @@ intobject.W_IntObject: [], floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], - listobject.W_ListObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -109,11 +108,6 @@ } self.imported_but_not_registered = { - dictmultiobject.W_DictMultiObject: True, # XXXXXX - dictmultiobject.W_DictMultiIterKeysObject: True, - dictmultiobject.W_DictMultiIterValuesObject: True, - dictmultiobject.W_DictMultiIterItemsObject: True, - listobject.W_ListObject: True, stringobject.W_StringObject: True, tupleobject.W_TupleObject: True, } From noreply at buildbot.pypy.org Fri May 17 16:24:50 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 16:24:50 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Make descr_new a static method of W_ListObject. Message-ID: <20130517142450.474C71C32E8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64261:c04f0bd7bbd5 Date: 2013-05-17 15:36 +0200 http://bitbucket.org/pypy/pypy/changeset/c04f0bd7bbd5/ Log: Make descr_new a static method of W_ListObject. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -332,6 +332,12 @@ # exposed to app-level + @staticmethod + def descr_new(space, w_listtype, __args__): + w_obj = space.allocate_instance(W_ListObject, w_listtype) + w_obj.clear(space) + return w_obj + def descr_init(self, space, __args__): # this is on the silly side w_iterable, = __args__.parse_obj( @@ -1665,13 +1671,6 @@ # ____________________________________________________________ -def descr_new(space, w_listtype, __args__): - w_obj = space.allocate_instance(W_ListObject, w_listtype) - w_obj.clear(space) - return w_obj - -# ____________________________________________________________ - def get_list_index(space, w_index): return space.getindex_w(w_index, space.w_IndexError, "list index") @@ -1679,7 +1678,7 @@ W_ListObject.typedef = StdTypeDef("list", __doc__ = """list() -> new list list(sequence) -> new list initialized from sequence's items""", - __new__ = interp2app(descr_new), + __new__ = interp2app(W_ListObject.descr_new), __init__ = interp2app(W_ListObject.descr_init), __repr__ = interp2app(W_ListObject.descr_repr), __hash__ = None, From noreply at buildbot.pypy.org Fri May 17 16:24:51 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 16:24:51 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: IN-PROGRESS: Translation fixes. Message-ID: <20130517142451.677F41C32E8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64262:cfa9aa3a362f Date: 2013-05-17 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/cfa9aa3a362f/ Log: IN-PROGRESS: Translation fixes. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -124,7 +124,7 @@ from pypy.objspace.std.floatobject import W_FloatObject return type(w_object) is W_FloatObject -def list_unroll_condition(space, w_list1, w_list2): +def list_unroll_condition(w_list1, space, w_list2): return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) @@ -376,28 +376,35 @@ def descr_ne(self, space, w_other): return space.not_(self.descr_eq(space, w_other)) - @staticmethod def _make_list_comparison(name): import operator op = getattr(operator, name) @jit.look_inside_iff(list_unroll_condition) - def compare_unwrappeditems(space, w_list1, w_list2): + def compare_unwrappeditems(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented + # needs to be safe against eq_w() mutating the w_lists behind our back # Search for the first index where items are different i = 0 # XXX in theory, this can be implemented more efficiently as well. # let's not care for now - while i < w_list1.length() and i < w_list2.length(): - w_item1 = w_list1.getitem(i) + while i < self.length() and i < w_list2.length(): + w_item1 = self.getitem(i) w_item2 = w_list2.getitem(i) if not space.eq_w(w_item1, w_item2): return getattr(space, name)(w_item1, w_item2) i += 1 # No more items to compare -- compare sizes - return space.newbool(op(w_list1.length(), w_list2.length())) + return space.newbool(op(self.length(), w_list2.length())) return func_with_new_name(compare_unwrappeditems, name + '__List_List') + descr_lt = _make_list_comparison('lt') + descr_le = _make_list_comparison('le') + descr_gt = _make_list_comparison('gt') + descr_ge = _make_list_comparison('ge') + def descr_len(self, space): result = self.length() return wrapint(space, result) @@ -451,7 +458,7 @@ times = space.getindex_w(w_times, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - raise FailedToImplement + return space.w_NotImplemented raise self.inplace_mul(times) return self @@ -1685,10 +1692,10 @@ __eq__ = interp2app(W_ListObject.descr_eq), __ne__ = interp2app(W_ListObject.descr_ne), - __lt__ = interp2app(W_ListObject._make_list_comparison('lt')), - __le__ = interp2app(W_ListObject._make_list_comparison('le')), - __gt__ = interp2app(W_ListObject._make_list_comparison('gt')), - __ge__ = interp2app(W_ListObject._make_list_comparison('ge')), + __lt__ = interp2app(W_ListObject.descr_lt), + __le__ = interp2app(W_ListObject.descr_le), + __gt__ = interp2app(W_ListObject.descr_gt), + __ge__ = interp2app(W_ListObject.descr_ge), __len__ = interp2app(W_ListObject.descr_len), __iter__ = interp2app(W_ListObject.descr_iter), From noreply at buildbot.pypy.org Fri May 17 16:24:52 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 16:24:52 +0200 (CEST) Subject: [pypy-commit] pypy remove-dict-smm: Close to-be-merged branch. Message-ID: <20130517142452.987471C32E8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-dict-smm Changeset: r64263:aef4a8f5b877 Date: 2013-05-17 16:21 +0200 http://bitbucket.org/pypy/pypy/changeset/aef4a8f5b877/ Log: Close to-be-merged branch. From noreply at buildbot.pypy.org Fri May 17 16:24:53 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 16:24:53 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge remove-dict-smm Message-ID: <20130517142453.C37CD1C32E8@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64264:3f055112fae9 Date: 2013-05-17 16:22 +0200 http://bitbucket.org/pypy/pypy/changeset/3f055112fae9/ Log: hg merge remove-dict-smm 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 @@ -19,3 +19,6 @@ .. branch: numpy-subarrays Implement subarrays for numpy + +.. branch: remove-dict-smm +Remove multi-methods on dict diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,19 +1,19 @@ -import py, sys -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.setobject import set_typedef as settypedef -from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef +from rpython.rlib import rerased, jit +from rpython.rlib.debug import mark_dict_non_null from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint -from rpython.rlib.debug import mark_dict_non_null from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib import rerased, jit UNROLL_CUTOFF = 5 + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -40,9 +40,20 @@ w_dct.length() <= UNROLL_CUTOFF) -class W_DictMultiObject(W_Object): - from pypy.objspace.std.dicttype import dict_typedef as typedef +def negate(f): + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator +class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, strdict=False, kwargs=False): @@ -108,6 +119,230 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + @staticmethod + def descr_new(space, w_dicttype, __args__): + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + + @staticmethod + def descr_fromkeys(space, w_type, w_keys, w_fill=None): + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + + def descr_init(self, space, __args__): + init_or_update(space, self, __args__, 'dict') + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if space.is_w(self, w_other): + return space.w_True + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + + if self.length() != w_other.length(): + return space.w_False + iteratorimplementation = self.iteritems() + while 1: + w_key, w_val = iteratorimplementation.next_item() + if w_key is None: + break + w_rightval = w_other.getitem(w_key) + if w_rightval is None: + return space.w_False + if not space.eq_w(w_val, w_rightval): + return space.w_False + return space.w_True + + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return self._compare_lt(space, w_other) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return w_other._compare_lt(space, self) + + def _compare_lt(self, space, w_other): + # Different sizes, no problem + if self.length() < w_other.length(): + return space.w_True + if self.length() > w_other.length(): + return space.w_False + + # Same size + w_leftdiff, w_leftval = characterize(space, self, w_other) + if w_leftdiff is None: + return space.w_False + w_rightdiff, w_rightval = characterize(space, w_other, self) + if w_rightdiff is None: + # w_leftdiff is not None, w_rightdiff is None + return space.w_True + w_res = space.lt(w_leftdiff, w_rightdiff) + if (not space.is_true(w_res) and + space.eq_w(w_leftdiff, w_rightdiff) and + w_rightval is not None): + w_res = space.lt(w_leftval, w_rightval) + return w_res + + descr_ne = negate(descr_eq) + descr_le = negate(descr_gt) + descr_ge = negate(descr_lt) + + def descr_len(self, space): + return space.wrap(self.length()) + + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_contains(self, space, w_key): + return space.newbool(self.getitem(w_key) is not None) + + def descr_getitem(self, space, w_key): + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + + w_missing_item = self.missing_method(space, w_key) + if w_missing_item is not None: + return w_missing_item + + space.raise_key_error(w_key) + + def descr_setitem(self, space, w_newkey, w_newvalue): + self.setitem(w_newkey, w_newvalue) + + def descr_delitem(self, space, w_key): + try: + self.delitem(w_key) + except KeyError: + space.raise_key_error(w_key) + + def descr_reversed(self, space): + raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + + def descr_copy(self, space): + """D.copy() -> a shallow copy of D""" + w_new = W_DictMultiObject.allocate_and_init_instance(space) + update1_dict_dict(space, w_new, self) + return w_new + + def descr_items(self, space): + """D.items() -> list of D's (key, value) pairs, as 2-tuples""" + return space.newlist(self.items()) + + def descr_keys(self, space): + """D.keys() -> list of D's keys""" + return self.w_keys() + + def descr_values(self, space): + """D.values() -> list of D's values""" + return space.newlist(self.values()) + + def descr_iteritems(self, space): + """D.iteritems() -> an iterator over the (key, value) items of D""" + return W_DictMultiIterItemsObject(space, self.iteritems()) + + def descr_iterkeys(self, space): + """D.iterkeys() -> an iterator over the keys of D""" + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_itervalues(self, space): + """D.itervalues() -> an iterator over the values of D""" + return W_DictMultiIterValuesObject(space, self.itervalues()) + + def descr_viewitems(self, space): + """D.viewitems() -> a set-like object providing a view on D's items""" + return W_DictViewItemsObject(space, self) + + def descr_viewkeys(self, space): + """D.viewkeys() -> a set-like object providing a view on D's keys""" + return W_DictViewKeysObject(space, self) + + def descr_viewvalues(self, space): + """D.viewvalues() -> an object providing a view on D's values""" + return W_DictViewValuesObject(space, self) + + def descr_has_key(self, space, w_key): + """D.has_key(k) -> True if D has a key k, else False""" + return space.newbool(self.getitem(w_key) is not None) + + def descr_clear(self, space): + """D.clear() -> None. Remove all items from D.""" + self.clear() + + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_get(self, space, w_key, w_default): + """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + else: + return w_default + + @gateway.unwrap_spec(defaults_w='args_w') + def descr_pop(self, space, w_key, defaults_w): + """D.pop(k[,d]) -> v, remove specified key and return the + corresponding value\nIf key is not found, d is returned if given, + otherwise KeyError is raised + """ + len_defaults = len(defaults_w) + if len_defaults > 1: + raise operationerrfmt(space.w_TypeError, + "pop expected at most 2 arguments, got %d", + 1 + len_defaults) + w_item = self.getitem(w_key) + if w_item is None: + if len_defaults > 0: + return defaults_w[0] + else: + space.raise_key_error(w_key) + else: + self.delitem(w_key) + return w_item + + def descr_popitem(self, space): + """D.popitem() -> (k, v), remove and return some (key, value) pair as + a\n2-tuple; but raise KeyError if D is empty""" + try: + w_key, w_value = self.popitem() + except KeyError: + raise OperationError(space.w_KeyError, + space.wrap("popitem(): dictionary is empty")) + return space.newtuple([w_key, w_value]) + + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_setdefault(self, space, w_key, w_default): + """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" + return self.setdefault(w_key, w_default) + + def descr_update(self, space, __args__): + """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] + = E[k]\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in + F: D[k] = F[k]""" + init_or_update(space, self, __args__, 'dict.update') + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -128,8 +363,87 @@ _add_indirections() + +app = gateway.applevel(''' + def dictrepr(currently_in_repr, d): + if len(d) == 0: + return "{}" + dict_id = id(d) + if dict_id in currently_in_repr: + return '{...}' + currently_in_repr[dict_id] = 1 + try: + items = [] + # XXX for now, we cannot use iteritems() at app-level because + # we want a reasonable result instead of a RuntimeError + # even if the dict is mutated by the repr() in the loop. + for k, v in dict.items(d): + items.append(repr(k) + ": " + repr(v)) + return "{" + ', '.join(items) + "}" + finally: + try: + del currently_in_repr[dict_id] + except: + pass +''', filename=__file__) + +dictrepr = app.interphook("dictrepr") + + +W_DictMultiObject.typedef = StdTypeDef("dict", + __doc__ = '''dict() -> new empty dictionary. +dict(mapping) -> new dictionary initialized from a mapping object\'s + (key, value) pairs. +dict(seq) -> new dictionary initialized as if via: + d = {} + for k, v in seq: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)''', + __new__ = gateway.interp2app(W_DictMultiObject.descr_new), + fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), + __hash__ = None, + __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), + __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + + __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), + __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), + __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), + __le__ = gateway.interp2app(W_DictMultiObject.descr_le), + __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), + __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), + + __len__ = gateway.interp2app(W_DictMultiObject.descr_len), + __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), + __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + + __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), + copy = gateway.interp2app(W_DictMultiObject.descr_copy), + items = gateway.interp2app(W_DictMultiObject.descr_items), + keys = gateway.interp2app(W_DictMultiObject.descr_keys), + values = gateway.interp2app(W_DictMultiObject.descr_values), + iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), + has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), + clear = gateway.interp2app(W_DictMultiObject.descr_clear), + get = gateway.interp2app(W_DictMultiObject.descr_get), + pop = gateway.interp2app(W_DictMultiObject.descr_pop), + popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), + setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), + update = gateway.interp2app(W_DictMultiObject.descr_update), + ) + + class DictStrategy(object): - def __init__(self, space): self.space = space @@ -171,7 +485,6 @@ # it ends up taking n**2 time, because the next() calls below # will take longer and longer. But all interesting strategies # provide a better one. - space = self.space iterator = self.iteritems(w_dict) w_key, w_value = iterator.next_item() self.delitem(w_dict, w_key) @@ -195,8 +508,8 @@ def view_as_kwargs(self, w_dict): return (None, None) + class EmptyDictStrategy(DictStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -301,6 +614,7 @@ def getiteritems(self, w_dict): return iter([(None, None)]) + # Iterator Implementation base classes def _new_next(TP): @@ -308,7 +622,7 @@ EMPTY = None else: EMPTY = None, None - + def next(self): if self.dictimplementation is None: return EMPTY @@ -372,7 +686,7 @@ wrapvalue = lambda space, key : key else: wrapvalue = dictimpl.wrapvalue.im_func - + class IterClassKeys(BaseKeyIterator): def __init__(self, space, strategy, impl): self.iterator = strategy.getiterkeys(impl) @@ -424,11 +738,6 @@ create_iterator_classes(EmptyDictStrategy) -registerimplementation(W_DictMultiObject) - -# DictImplementation lattice -# XXX fix me - # concrete subclasses of the above @@ -543,7 +852,6 @@ class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -576,8 +884,8 @@ create_iterator_classes(ObjectDictStrategy) + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -642,7 +950,6 @@ class UnicodeDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("unicode") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -744,9 +1051,6 @@ create_iterator_classes(IntDictStrategy) -init_signature = Signature(['seq_or_map'], None, 'kwargs') -init_defaults = [None] - def update1(space, w_dict, w_data): if space.findattr(w_data, space.wrap("keys")) is None: @@ -788,6 +1092,9 @@ w_dict.setitem(w_key, w_value) +init_signature = Signature(['seq_or_map'], None, 'kwargs') +init_defaults = [None] + def init_or_update(space, w_dict, __args__, funcname): w_src, w_kwds = __args__.parse_obj( None, funcname, @@ -798,61 +1105,6 @@ if space.is_true(w_kwds): update1(space, w_dict, w_kwds) -def init__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict') - -def dict_update__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict.update') - -def getitem__DictMulti_ANY(space, w_dict, w_key): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - - w_missing_item = w_dict.missing_method(space, w_key) - if w_missing_item is not None: - return w_missing_item - - space.raise_key_error(w_key) - -def setitem__DictMulti_ANY_ANY(space, w_dict, w_newkey, w_newvalue): - w_dict.setitem(w_newkey, w_newvalue) - -def delitem__DictMulti_ANY(space, w_dict, w_key): - try: - w_dict.delitem(w_key) - except KeyError: - space.raise_key_error(w_key) - -def len__DictMulti(space, w_dict): - return space.wrap(w_dict.length()) - -def contains__DictMulti_ANY(space, w_dict, w_key): - return space.newbool(w_dict.getitem(w_key) is not None) - -dict_has_key__DictMulti_ANY = contains__DictMulti_ANY - -def iter__DictMulti(space, w_dict): - return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) - -def eq__DictMulti_DictMulti(space, w_left, w_right): - if space.is_w(w_left, w_right): - return space.w_True - - if w_left.length() != w_right.length(): - return space.w_False - iteratorimplementation = w_left.iteritems() - while 1: - w_key, w_val = iteratorimplementation.next_item() - if w_key is None: - break - w_rightval = w_right.getitem(w_key) - if w_rightval is None: - return space.w_False - if not space.eq_w(w_val, w_rightval): - return space.w_False - return space.w_True - def characterize(space, w_a, w_b): """ (similar to CPython) returns the smallest key in acontent for which b's value is different or absent and this value """ @@ -874,105 +1126,11 @@ w_smallest_diff_a_key = w_key return w_smallest_diff_a_key, w_its_value -def lt__DictMulti_DictMulti(space, w_left, w_right): - # Different sizes, no problem - if w_left.length() < w_right.length(): - return space.w_True - if w_left.length() > w_right.length(): - return space.w_False - - # Same size - w_leftdiff, w_leftval = characterize(space, w_left, w_right) - if w_leftdiff is None: - return space.w_False - w_rightdiff, w_rightval = characterize(space, w_right, w_left) - if w_rightdiff is None: - # w_leftdiff is not None, w_rightdiff is None - return space.w_True - w_res = space.lt(w_leftdiff, w_rightdiff) - if (not space.is_true(w_res) and - space.eq_w(w_leftdiff, w_rightdiff) and - w_rightval is not None): - w_res = space.lt(w_leftval, w_rightval) - return w_res - -def dict_copy__DictMulti(space, w_self): - w_new = W_DictMultiObject.allocate_and_init_instance(space) - update1_dict_dict(space, w_new, w_self) - return w_new - -def dict_items__DictMulti(space, w_self): - return space.newlist(w_self.items()) - -def dict_keys__DictMulti(space, w_self): - return w_self.w_keys() - -def dict_values__DictMulti(space, w_self): - return space.newlist(w_self.values()) - -def dict_iteritems__DictMulti(space, w_self): - return W_DictMultiIterItemsObject(space, w_self.iteritems()) - -def dict_iterkeys__DictMulti(space, w_self): - return W_DictMultiIterKeysObject(space, w_self.iterkeys()) - -def dict_itervalues__DictMulti(space, w_self): - return W_DictMultiIterValuesObject(space, w_self.itervalues()) - -def dict_viewitems__DictMulti(space, w_self): - return W_DictViewItemsObject(space, w_self) - -def dict_viewkeys__DictMulti(space, w_self): - return W_DictViewKeysObject(space, w_self) - -def dict_viewvalues__DictMulti(space, w_self): - return W_DictViewValuesObject(space, w_self) - -def dict_clear__DictMulti(space, w_self): - w_self.clear() - -def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default - -def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - return w_dict.setdefault(w_key, w_default) - -def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w): - len_defaults = len(defaults_w) - if len_defaults > 1: - raise operationerrfmt(space.w_TypeError, - "pop expected at most 2 arguments, got %d", - 1 + len_defaults) - w_item = w_dict.getitem(w_key) - if w_item is None: - if len_defaults > 0: - return defaults_w[0] - else: - space.raise_key_error(w_key) - else: - w_dict.delitem(w_key) - return w_item - -def dict_popitem__DictMulti(space, w_dict): - try: - w_key, w_value = w_dict.popitem() - except KeyError: - raise OperationError(space.w_KeyError, - space.wrap("popitem(): dictionary is empty")) - return space.newtuple([w_key, w_value]) - # ____________________________________________________________ # Iteration - -class W_BaseDictMultiIterObject(W_Object): - from pypy.objspace.std.dicttype import dictiter_typedef as typedef - +class W_BaseDictMultiIterObject(W_Root): _immutable_fields_ = ["iteratorimplementation"] ignore_for_isinstance_cache = True @@ -981,139 +1139,199 @@ w_self.space = space w_self.iteratorimplementation = iteratorimplementation + def descr_iter(self, space): + return self + + def descr_length_hint(self, space): + return space.wrap(self.iteratorimplementation.length()) + + def descr_reduce(self, space): + """ + This is a slightly special case of pickling. + Since iteration over a dict is a bit hairy, + we do the following: + - create a clone of the dict iterator + - run it to the original position + - collect all remaining elements into a list + At unpickling time, we just use that list + and create an iterator on it. + This is of course not the standard way. + + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('dictiter_surrogate_new') + w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) + + raise OperationError( + space.w_TypeError, + space.wrap("can't pickle dictionary-keyiterator objects")) + # XXXXXX get that working again + + # we cannot call __init__ since we don't have the original dict + if isinstance(self, W_DictIter_Keys): + w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) + elif isinstance(self, W_DictIter_Values): + w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) + elif isinstance(self, W_DictIter_Items): + w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + else: + msg = "unsupported dictiter type '%s' during pickling" % (self,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_clone.space = space + w_clone.content = self.content + w_clone.len = self.len + w_clone.pos = 0 + w_clone.setup_iterator() + # spool until we have the same pos + while w_clone.pos < self.pos: + w_obj = w_clone.next_entry() + w_clone.pos += 1 + stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] + w_res = space.newlist(stuff) + tup = [ + w_res + ] + w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + return w_ret + + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key = iteratorimplementation.next_key() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterValuesObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_value = iteratorimplementation.next_value() + if w_value is not None: + return w_value + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterItemsObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key, w_value = iteratorimplementation.next_item() + if w_key is not None: + return space.newtuple([w_key, w_value]) + raise OperationError(space.w_StopIteration, space.w_None) -registerimplementation(W_DictMultiIterKeysObject) -registerimplementation(W_DictMultiIterValuesObject) -registerimplementation(W_DictMultiIterItemsObject) +W_DictMultiIterItemsObject.typedef = StdTypeDef( + "dict_iteritems", + __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterKeysObject(space, w_dictiter): - return w_dictiter +W_DictMultiIterKeysObject.typedef = StdTypeDef( + "dict_iterkeys", + __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def next__DictMultiIterKeysObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key = iteratorimplementation.next_key() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) +W_DictMultiIterValuesObject.typedef = StdTypeDef( + "dict_itervalues", + __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterValuesObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterValuesObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_value = iteratorimplementation.next_value() - if w_value is not None: - return w_value - raise OperationError(space.w_StopIteration, space.w_None) - -def iter__DictMultiIterItemsObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterItemsObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key, w_value = iteratorimplementation.next_item() - if w_key is not None: - return space.newtuple([w_key, w_value]) - raise OperationError(space.w_StopIteration, space.w_None) # ____________________________________________________________ # Views -class W_DictViewObject(W_Object): +class W_DictViewObject(W_Root): def __init__(w_self, space, w_dict): w_self.w_dict = w_dict -class W_DictViewKeysObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_keys_typedef as typedef -registerimplementation(W_DictViewKeysObject) + def descr_repr(self, space): + w_seq = space.call_function(space.w_list, self) + w_repr = space.repr(w_seq) + return space.wrap("%s(%s)" % (space.type(self).getname(space), + space.str_w(w_repr))) + + def descr_eq(self, space, w_otherview): + if not space.eq_w(space.len(self), space.len(w_otherview)): + return space.w_False + + w_iter = space.iter(self) + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if not space.is_true(space.contains(w_otherview, w_item)): + return space.w_False + return space.w_True + + def descr_len(self, space): + return space.len(self.w_dict) + + def descr_and(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "intersection_update", w_otherview) + return w_set + + def descr_or(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "update", w_otherview) + return w_set + + def descr_xor(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "symmetric_difference_update", w_otherview) + return w_set class W_DictViewItemsObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_items_typedef as typedef -registerimplementation(W_DictViewItemsObject) + def descr_iter(self, space): + return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) + +class W_DictViewKeysObject(W_DictViewObject): + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) class W_DictViewValuesObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_values_typedef as typedef -registerimplementation(W_DictViewValuesObject) + def descr_iter(self, space): + return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) -def len__DictViewKeys(space, w_dictview): - return space.len(w_dictview.w_dict) -len__DictViewItems = len__DictViewValues = len__DictViewKeys +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewItemsObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), + __or__ = gateway.interp2app(W_DictViewItemsObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewItemsObject.descr_xor) + ) -def iter__DictViewKeys(space, w_dictview): - return dict_iterkeys__DictMulti(space, w_dictview.w_dict) -def iter__DictViewItems(space, w_dictview): - return dict_iteritems__DictMulti(space, w_dictview.w_dict) -def iter__DictViewValues(space, w_dictview): - return dict_itervalues__DictMulti(space, w_dictview.w_dict) +W_DictViewKeysObject.typedef = StdTypeDef( + "dict_keys", + __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewKeysObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), + __or__ = gateway.interp2app(W_DictViewKeysObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewKeysObject.descr_xor) + ) -def all_contained_in(space, w_dictview, w_otherview): - w_iter = space.iter(w_dictview) - - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - - return space.w_True - -def eq__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - if space.eq_w(space.len(w_dictview), space.len(w_otherview)): - return all_contained_in(space, w_dictview, w_otherview) - return space.w_False -eq__DictViewKeys_settypedef = eq__DictViewKeys_DictViewKeys -eq__DictViewKeys_frozensettypedef = eq__DictViewKeys_DictViewKeys - -eq__DictViewKeys_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_settypedef = eq__DictViewItems_DictViewItems -eq__DictViewItems_frozensettypedef = eq__DictViewItems_DictViewItems - -def repr__DictViewKeys(space, w_dictview): - w_seq = space.call_function(space.w_list, w_dictview) - w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), - space.str_w(w_repr))) -repr__DictViewItems = repr__DictViewKeys -repr__DictViewValues = repr__DictViewKeys - -def and__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set -and__DictViewKeys_settypedef = and__DictViewKeys_DictViewKeys -and__DictViewItems_DictViewItems = and__DictViewKeys_DictViewKeys -and__DictViewItems_settypedef = and__DictViewKeys_DictViewKeys - -def or__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "update", w_otherview) - return w_set -or__DictViewKeys_settypedef = or__DictViewKeys_DictViewKeys -or__DictViewItems_DictViewItems = or__DictViewKeys_DictViewKeys -or__DictViewItems_settypedef = or__DictViewKeys_DictViewKeys - -def xor__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set -xor__DictViewKeys_settypedef = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_DictViewItems = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_settypedef = xor__DictViewKeys_DictViewKeys - -# ____________________________________________________________ - -from pypy.objspace.std import dicttype -register_all(vars(), dicttype) +W_DictViewValuesObject.typedef = StdTypeDef( + "dict_values", + __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewValuesObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), + __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) + ) diff --git a/pypy/objspace/std/dicttype.py b/pypy/objspace/std/dicttype.py deleted file mode 100644 --- a/pypy/objspace/std/dicttype.py +++ /dev/null @@ -1,221 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter.mixedmodule import MixedModule -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.register_all import register_all - -dict_copy = SMM('copy', 1, - doc='D.copy() -> a shallow copy of D') -dict_items = SMM('items', 1, - doc="D.items() -> list of D's (key, value) pairs, as" - ' 2-tuples') -dict_keys = SMM('keys', 1, - doc="D.keys() -> list of D's keys") -dict_values = SMM('values', 1, - doc="D.values() -> list of D's values") -dict_has_key = SMM('has_key', 2, - doc='D.has_key(k) -> True if D has a key k, else False') -dict_clear = SMM('clear', 1, - doc='D.clear() -> None. Remove all items from D.') -dict_get = SMM('get', 3, defaults=(None,), - doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' - ' to None.') -dict_pop = SMM('pop', 2, varargs_w=True, - doc='D.pop(k[,d]) -> v, remove specified key and return' - ' the corresponding value\nIf key is not found, d is' - ' returned if given, otherwise KeyError is raised') -dict_popitem = SMM('popitem', 1, - doc='D.popitem() -> (k, v), remove and return some (key,' - ' value) pair as a\n2-tuple; but raise KeyError if D' - ' is empty') -dict_setdefault = SMM('setdefault', 3, defaults=(None,), - doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' - ' if k not in D') -dict_update = SMM('update', 1, general__args__=True, - doc='D.update(E, **F) -> None. Update D from E and F:' - ' for k in E: D[k] = E[k]\n(if E has keys else: for' - ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' - ' F[k]') -dict_iteritems = SMM('iteritems', 1, - doc='D.iteritems() -> an iterator over the (key, value)' - ' items of D') -dict_iterkeys = SMM('iterkeys', 1, - doc='D.iterkeys() -> an iterator over the keys of D') -dict_itervalues = SMM('itervalues', 1, - doc='D.itervalues() -> an iterator over the values of D') -dict_viewkeys = SMM('viewkeys', 1, - doc="D.viewkeys() -> a set-like object providing a view on D's keys") -dict_viewitems = SMM('viewitems', 1, - doc="D.viewitems() -> a set-like object providing a view on D's items") -dict_viewvalues = SMM('viewvalues', 1, - doc="D.viewvalues() -> an object providing a view on D's values") -dict_reversed = SMM('__reversed__', 1) - -def dict_reversed__ANY(space, w_dict): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - -register_all(vars(), globals()) - -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - - -app = gateway.applevel(''' - def dictrepr(currently_in_repr, d): - if len(d) == 0: - return "{}" - dict_id = id(d) - if dict_id in currently_in_repr: - return '{...}' - currently_in_repr[dict_id] = 1 - try: - items = [] - # XXX for now, we cannot use iteritems() at app-level because - # we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in dict.items(d): - items.append(repr(k) + ": " + repr(v)) - return "{" + ', '.join(items) + "}" - finally: - try: - del currently_in_repr[dict_id] - except: - pass -''', filename=__file__) - -dictrepr = app.interphook("dictrepr") - - -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - -dict_typedef = StdTypeDef("dict", - __doc__ = '''dict() -> new empty dictionary. -dict(mapping) -> new dictionary initialized from a mapping object\'s - (key, value) pairs. -dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v -dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), - ) -dict_typedef.registermethods(globals()) - -# ____________________________________________________________ - -def descr_dictiter__length_hint__(space, w_self): - from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject - assert isinstance(w_self, W_BaseDictMultiIterObject) - return space.wrap(w_self.iteratorimplementation.length()) - - -def descr_dictiter__reduce__(w_self, space): - """ - This is a slightly special case of pickling. - Since iteration over a dict is a bit hairy, - we do the following: - - create a clone of the dict iterator - - run it to the original position - - collect all remaining elements into a list - At unpickling time, we just use that list - and create an iterator on it. - This is of course not the standard way. - - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) - - raise OperationError( - space.w_TypeError, - space.wrap("can't pickle dictionary-keyiterator objects")) - # XXXXXX get that working again - - # we cannot call __init__ since we don't have the original dict - if isinstance(w_self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(w_self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(w_self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) - else: - msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_clone.space = space - w_clone.content = w_self.content - w_clone.len = w_self.len - w_clone.pos = 0 - w_clone.setup_iterator() - # spool until we have the same pos - while w_clone.pos < w_self.pos: - w_obj = w_clone.next_entry() - w_clone.pos += 1 - stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] - w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) - return w_ret - -# ____________________________________________________________ - - -dictiter_typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), - __reduce__ = gateway.interp2app(descr_dictiter__reduce__), - ) - -# ____________________________________________________________ -# Dict views - -dict_keys_typedef = StdTypeDef( - "dict_keys", - ) - -dict_items_typedef = StdTypeDef( - "dict_items", - ) - -dict_values_typedef = StdTypeDef( - "dict_values", - ) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -12,6 +12,7 @@ from pypy.objspace.std.register_all import register_all from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint, intmask from pypy.objspace.std import model +from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.interpreter.special import Ellipsis from pypy.interpreter.pycode import PyCode from pypy.interpreter import gateway, unicodehelper @@ -24,7 +25,6 @@ from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.longobject import W_LongObject, newlong @@ -309,15 +309,18 @@ return space.newlist(items_w) register(TYPE_LIST, unmarshal_List) -def marshal_w__DictMulti(space, w_dict, m): +def marshal_w_dict(space, w_dict, m): + if not isinstance(w_dict, W_DictMultiObject): + raise_exception(space, "unmarshallable object") m.start(TYPE_DICT) for w_tuple in w_dict.items(): w_key, w_value = space.fixedview(w_tuple, 2) m.put_w_obj(w_key) m.put_w_obj(w_value) m.atom(TYPE_NULL) +handled_by_any.append(('dict', marshal_w_dict)) -def unmarshal_DictMulti(space, u, tc): +def unmarshal_dict(space, u, tc): # since primitive lists are not optimized and we don't know # the dict size in advance, use the dict's setitem instead # of building a list of tuples. @@ -329,7 +332,7 @@ w_value = u.get_w_obj() space.setitem(w_dic, w_key, w_value) return w_dic -register(TYPE_DICT, unmarshal_DictMulti) +register(TYPE_DICT, unmarshal_dict) def unmarshal_NULL(self, u, tc): return None diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -40,7 +40,6 @@ from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef - from pypy.objspace.std.dicttype import dict_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -81,6 +80,7 @@ # not-multimethod based types + self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -92,10 +92,6 @@ floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], listobject.W_ListObject: [], - dictmultiobject.W_DictMultiObject: [], - dictmultiobject.W_DictMultiIterKeysObject: [], - dictmultiobject.W_DictMultiIterValuesObject: [], - dictmultiobject.W_DictMultiIterItemsObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -108,9 +104,6 @@ iterobject.W_FastTupleIterObject: [], iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], - dictmultiobject.W_DictViewKeysObject: [], - dictmultiobject.W_DictViewItemsObject: [], - dictmultiobject.W_DictViewValuesObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], } @@ -333,9 +326,6 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(self, space): - raise UnwrapError('cannot unwrap %r' % self) - class UnwrapError(Exception): pass diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -253,10 +253,9 @@ def unwrap(self, w_obj): """NOT_RPYTHON""" - if isinstance(w_obj, model.W_Object): + # _____ this code is here to support testing only _____ + if isinstance(w_obj, W_Root): return w_obj.unwrap(self) - if isinstance(w_obj, W_Root): - return w_obj raise model.UnwrapError("cannot unwrap: %r" % w_obj) def newint(self, intval): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -2,8 +2,7 @@ import py from pypy.objspace.std.dictmultiobject import (W_DictMultiObject, - setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, StringDictStrategy, - ObjectDictStrategy) + StringDictStrategy, ObjectDictStrategy) class TestW_DictObject(object): @@ -409,6 +408,24 @@ assert {'a': 1 } < { 'b': 1} assert {'a': 1, 'x': 2 } < { 'b': 1, 'x': 2} + def test_other_rich_cmp(self): + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} + + assert d1 <= d2 + assert d1 <= d3 + assert not d1 <= d4 + + assert not d1 > d2 + assert not d1 > d3 + assert d1 > d4 + + assert d1 >= d2 + assert not d1 >= d3 + assert d1 >= d4 + def test_str_repr(self): assert '{}' == str({}) assert '{1: 2}' == str({1: 2}) @@ -604,6 +621,9 @@ assert d.values() == [] assert d.keys() == [] + def test_cmp_with_noncmp(self): + assert not {} > object() + class AppTest_DictMultiObject(AppTest_DictObject): def test_emptydict_unhashable(self): @@ -971,10 +991,10 @@ pydict = {} for i in range(N): x = randint(-N, N) - setitem__DictMulti_ANY_ANY(self.space, d, x, i) + d.descr_setitem(self.space, x, i) pydict[x] = i for key, value in pydict.iteritems(): - assert value == getitem__DictMulti_ANY(self.space, d, key) + assert value == d.descr_getitem(self.space, key) class BaseTestRDictImplementation: From noreply at buildbot.pypy.org Fri May 17 16:51:15 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 17 May 2013 16:51:15 +0200 (CEST) Subject: [pypy-commit] buildbot default: add ubuntu/raring cross-translation builder Message-ID: <20130517145115.1616A1C01D1@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r821:0eed6be4f9e9 Date: 2013-05-17 16:50 +0200 http://bitbucket.org/pypy/buildbot/changeset/0eed6be4f9e9/ Log: add ubuntu/raring cross-translation builder diff --git a/bot2/pypybuildbot/arm_master.py b/bot2/pypybuildbot/arm_master.py --- a/bot2/pypybuildbot/arm_master.py +++ b/bot2/pypybuildbot/arm_master.py @@ -51,6 +51,14 @@ prefix=['schroot', '-c', 'raspbian'], trigger='JITLINUXARMHF_RASPBIAN_scheduler') +pypyJITCrossTranslationFactoryRaringHF = pypybuilds.NightlyBuild( + translationArgs=(crosstranslationargs + + jit_translation_args + + crosstranslationjitargs), + platform='linux-armhf-raring', + interpreter='pypy', + prefix=['schroot', '-c', 'raring']) + pypyARMJITTranslatedTestFactory = pypybuilds.TranslatedTests( translationArgs=(crosstranslationargs + jit_translation_args @@ -100,12 +108,14 @@ BUILDJITLINUXARM = "build-pypy-c-jit-linux-armel" BUILDLINUXARMHF_RASPBIAN = "build-pypy-c-linux-armhf-raspbian" BUILDJITLINUXARMHF_RASPBIAN = "build-pypy-c-jit-linux-armhf-raspbian" +BUILDJITLINUXARMHF_RARING = "build-pypy-c-jit-linux-armhf-raring" schedulers = [ Nightly("nighly-arm-0-00", [ BUILDJITLINUXARM, # on hhu-cross-armel, uses 1 core BUILDJITLINUXARMHF_RASPBIAN, # on hhu-cross-raspbianhf, uses 1 core + BUILDJITLINUXARMHF_RARING, # on hhu-cross-raring-armhf, uses 1 core BUILDLINUXARM, # on hhu-cross-armel, uses 1 core BUILDLINUXARMHF_RASPBIAN, # on hhu-cross-raspbianhf, uses 1 core @@ -236,4 +246,11 @@ "category": 'linux-armhf', "locks": [ARMCrossLock.access('counting')], }, + {"name": BUILDJITLINUXARMHF_RARING, + "slavenames": ['hhu-cross-raring'], + "builddir": BUILDJITLINUXARMHF_RARING, + "factory": pypyJITCrossTranslationFactoryRaringHF, + "category": 'linux-armhf', + "locks": [ARMCrossLock.access('counting')], + }, ] From noreply at buildbot.pypy.org Fri May 17 17:02:49 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 17 May 2013 17:02:49 +0200 (CEST) Subject: [pypy-commit] pypy numpy-subarrays: Add a test for multidimensional subarrays Message-ID: <20130517150249.A60611C32EA@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-subarrays Changeset: r64265:b2014e32f383 Date: 2013-05-17 17:02 +0200 http://bitbucket.org/pypy/pypy/changeset/b2014e32f383/ Log: Add a test for multidimensional subarrays diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2715,7 +2715,11 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 - assert len(list(a[0])) == 2 + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + assert (a[0]["x"][0] == [1, 2, 3]).all() d = dtype((float, (10, 10))) a = zeros((3,3), dtype=d) @@ -2725,6 +2729,14 @@ assert (a[0, 0, 0] == 500).all() assert a[0, 0, 0].shape == (10,) + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): if option.runappdirect and '__pypy__' not in sys.builtin_module_names: From noreply at buildbot.pypy.org Fri May 17 17:03:47 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 17:03:47 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Make list marshallable again. Message-ID: <20130517150347.9FF5A1C32EA@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64266:9772bc95964e Date: 2013-05-17 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/9772bc95964e/ Log: Make list marshallable again. diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -297,17 +297,17 @@ return space.newtuple(items_w) register(TYPE_TUPLE, unmarshal_Tuple) -def marshal_w__List(space, w_list, m): +def marshal_list(space, w_list, m): + if not isinstance(w_list, W_ListObject): + raise_exception(space, "unmarshallable object") items = w_list.getitems()[:] m.put_tuple_w(TYPE_LIST, items) +handled_by_any.append(('list', marshal_list)) -def unmarshal_List(space, u, tc): +def unmarshal_list(space, u, tc): items_w = u.get_list_w() return space.newlist(items_w) - -def finish_List(space, items_w, typecode): - return space.newlist(items_w) -register(TYPE_LIST, unmarshal_List) +register(TYPE_LIST, unmarshal_list) def marshal_w_dict(space, w_dict, m): if not isinstance(w_dict, W_DictMultiObject): From noreply at buildbot.pypy.org Fri May 17 17:03:48 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Fri, 17 May 2013 17:03:48 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Fix translation. Message-ID: <20130517150348.DB2EA1C32EA@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64267:282807104b80 Date: 2013-05-17 16:59 +0200 http://bitbucket.org/pypy/pypy/changeset/282807104b80/ Log: Fix translation. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -355,11 +355,13 @@ w_currently_in_repr = ec._py_repr = space.newdict() return listrepr(space, w_currently_in_repr, self) - @jit.look_inside_iff(list_unroll_condition) def descr_eq(self, space, w_other): if not isinstance(w_other, W_ListObject): return space.w_NotImplemented + return self._descr_eq(space, w_other) + @jit.look_inside_iff(list_unroll_condition) + def _descr_eq(self, space, w_other): # needs to be safe against eq_w() mutating the w_lists behind our back if self.length() != w_other.length(): return space.w_False @@ -380,11 +382,13 @@ import operator op = getattr(operator, name) - @jit.look_inside_iff(list_unroll_condition) def compare_unwrappeditems(self, space, w_list2): if not isinstance(w_list2, W_ListObject): return space.w_NotImplemented + return _compare_unwrappeditems(self, space, w_list2) + @jit.look_inside_iff(list_unroll_condition) + def _compare_unwrappeditems(self, space, w_list2): # needs to be safe against eq_w() mutating the w_lists behind our back # Search for the first index where items are different i = 0 @@ -398,6 +402,7 @@ i += 1 # No more items to compare -- compare sizes return space.newbool(op(self.length(), w_list2.length())) + return func_with_new_name(compare_unwrappeditems, name + '__List_List') descr_lt = _make_list_comparison('lt') From noreply at buildbot.pypy.org Fri May 17 18:32:37 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 17 May 2013 18:32:37 +0200 (CEST) Subject: [pypy-commit] buildbot default: do not trigger the app-level tests for the no-jit armel build Message-ID: <20130517163237.EED851C32E8@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r822:b52c1ec7179b Date: 2013-05-17 18:32 +0200 http://bitbucket.org/pypy/buildbot/changeset/b52c1ec7179b/ Log: do not trigger the app-level tests for the no-jit armel build diff --git a/bot2/pypybuildbot/arm_master.py b/bot2/pypybuildbot/arm_master.py --- a/bot2/pypybuildbot/arm_master.py +++ b/bot2/pypybuildbot/arm_master.py @@ -23,8 +23,7 @@ translationArgs=crosstranslationargs + ['-O2'], platform='linux-armel', interpreter='pypy', - prefix=['schroot', '-c', 'armel'], - trigger='APPLVLLINUXARM_scheduler') + prefix=['schroot', '-c', 'armel']) pypyJITCrossTranslationFactoryARM = pypybuilds.NightlyBuild( translationArgs=(crosstranslationargs From noreply at buildbot.pypy.org Fri May 17 18:58:46 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 17 May 2013 18:58:46 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed a probably problem in ContextPart>>#context(On:do:|Ensure:) Message-ID: <20130517165846.283961C2FE2@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r395:1d0a554ca9de Date: 2013-05-17 18:57 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/1d0a554ca9de/ Log: fixed a probably problem in ContextPart>>#context(On:do:|Ensure:) diff too long, truncating to 2000 out of 79849 lines diff --git a/images/Squeak4.5-12568.changes b/images/Squeak4.5-12568.changes --- a/images/Squeak4.5-12568.changes +++ b/images/Squeak4.5-12568.changes @@ -36,4 +36,4 @@ Workspace allInstances do: [:w | w topView delete]. ReleaseBuilderFor4dot4 prepareNewBuild. Smalltalk snapshot: true andQuit: true. -! ----End fileIn of a stream----! ----SNAPSHOT----{31 March 2013 . 3:27:34 pm} Squeak4.5-12327.image priorSource: 7430688! !Installer methodsFor: 'squeakmap' stamp: 'fbs 1/28/2013 19:25' prior: 57597950! packageAndVersionFrom: pkg | p | p := ReadStream on: pkg . ^{(p upTo: $(). p upTo: $)} collect: [:s | s withBlanksTrimmed].! ! "Installer-Core"! !Categorizer methodsFor: 'fileIn/Out' stamp: 'cwp 6/20/2012 16:58'! scanFrom: aStream environment: anEnvironment ^ self scanFrom: aStream! ! !ClassCategoryReader methodsFor: 'fileIn/Out' stamp: 'cwp 6/20/2012 17:21'! scanFrom: aStream environment: anEnvironment "File in methods from the stream, aStream." | methodText | [methodText := aStream nextChunkText. methodText size > 0] whileTrue: [class compile: methodText environment: anEnvironment classified: category withStamp: changeStamp notifying: nil]! ! !ClassCommentReader methodsFor: 'as yet unclassified' stamp: 'cwp 6/20/2012 17:22'! scanFrom: aStream environment: anEnvironment ^ self scanFrom: aStream! ! !Metaclass methodsFor: 'compiling' stamp: 'cwp 6/20/2012 17:29'! bindingOf: varName environment: anEnvironment ^ thisClass classBindingOf: varName environment: anEnvironment! ! !LargePositiveInteger methodsFor: 'arithmetic' stamp: 'nice 12/30/2012 20:03' prior: 22505876! \\ aNumber "Primitive. Take the receiver modulo the argument. The result is the remainder rounded towards negative infinity, of the receiver divided by the argument. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." aNumber isInteger ifTrue: [| neg qr q r | neg := self negative == aNumber negative == false. qr := (self digitDiv: (aNumber class == SmallInteger ifTrue: [aNumber abs] ifFalse: [aNumber]) neg: neg). q := qr first normalize. r := qr last normalize. ^(q negative ifTrue: [r isZero not] ifFalse: [q isZero and: [neg]]) ifTrue: [r + aNumber] ifFalse: [r]]. ^super \\ aNumber ! ! !LargePositiveInteger methodsFor: 'converting' stamp: 'nice 1/27/2012 22:41' prior: 37616324! asFloat "Answer a Float that best approximates the value of the receiver. This algorithm is optimized to process only the significant digits of a LargeInteger. And it does honour IEEE 754 round to nearest even mode in case of excess precision (see details below)." "How numbers are rounded in IEEE 754 default rounding mode: A shift is applied so that the highest 53 bits are placed before the floating point to form a mantissa. The trailing bits form the fraction part placed after the floating point. This fractional number must be rounded to the nearest integer. If fraction part is 2r0.1, exactly between two consecutive integers, there is a tie. The nearest even integer is chosen in this case. Examples (First 52bits of mantissa are omitted for brevity): 2r0.00001 is rounded downward to 2r0 2r1.00001 is rounded downward to 2r1 2r0.1 is a tie and rounded to 2r0 (nearest even) 2r1.1 is a tie and rounded to 2r10 (nearest even) 2r0.10001 is rounded upward to 2r1 2r1.10001 is rounded upward to 2r10 Thus, if the next bit after floating point is 0, the mantissa is left unchanged. If next bit after floating point is 1, an odd mantissa is always rounded upper. An even mantissa is rounded upper only if the fraction part is not a tie." "Algorihm details: The floating point hardware can perform the rounding correctly with several excess bits as long as there is a single inexact operation. This can be obtained by splitting the mantissa plus excess bits in two part with less bits than Float precision. Note 1: the inexact flag in floating point hardware must not be trusted because in some cases the operations would be exact but would not take into account some bits that were truncated before the Floating point operations. Note 2: the floating point hardware is presumed configured in default rounding mode." | mantissa shift excess result n | "Check how many bits excess the maximum precision of a Float mantissa." excess := self highBitOfMagnitude - Float precision. excess > 7 ifTrue: ["Remove the excess bits but seven." mantissa := self bitShiftMagnitude: 7 - excess. shift := excess - 7. "An even mantissa with a single excess bit immediately following would be truncated. But this would not be correct if above shift has truncated some extra bits. Check this case, and round excess bits upper manually." ((mantissa digitAt: 1) = 2r01000000 and: [self anyBitOfMagnitudeFrom: 1 to: shift]) ifTrue: [mantissa := mantissa + 1]] ifFalse: [mantissa := self. shift := 0]. "There will be a single inexact round off at last iteration" result := (mantissa digitAt: (n := mantissa digitLength)) asFloat. [(n := n - 1) > 0] whileTrue: [ result := 256.0 * result + (mantissa digitAt: n) asFloat]. ^result timesTwoPower: shift.! ! !LargePositiveInteger methodsFor: 'private' stamp: 'nice 12/30/2012 14:25'! primitiveQuo: anInteger "Primitive. Divide the receiver by the argument and return the result. Round the result down towards zero to make it a whole integer. Fail if the argument is 0. Fail if either the argument or the result is not a SmallInteger or a LargePositiveInteger less than 2-to-the-30th (1073741824). Optional. See Object documentation whatIsAPrimitive." ^nil! ! !LargePositiveInteger methodsFor: 'arithmetic' stamp: 'nice 12/30/2012 14:34'! rem: aNumber "Remainder defined in terms of quo:. See super rem:. This is defined only to speed up case of very large integers." (self primitiveQuo: aNumber) ifNotNil: [:quo | ^self - (quo * aNumber)]. aNumber isInteger ifTrue: [| ng rem | ng := self negative == aNumber negative == false. rem := (self digitDiv: (aNumber class == SmallInteger ifTrue: [aNumber abs] ifFalse: [aNumber]) neg: ng) at: 2. ^ rem normalize]. ^super rem: aNumber! ! !LargeNegativeInteger methodsFor: 'converting' stamp: 'nice 1/1/2013 15:42' prior: 37616204! asFloat ^super asFloat negated! ! !UndefinedObject methodsFor: 'class hierarchy' stamp: 'cwp 6/22/2012 15:39'! literalScannedAs: scannedLiteral environment: anEnvironment notifying: requestor ^ scannedLiteral! ! !Behavior methodsFor: 'testing method dictionary' stamp: 'cwp 6/20/2012 17:32'! bindingOf: varName environment: anEnvironment ^superclass bindingOf: varName environment: anEnvironment! ! !Behavior methodsFor: 'testing method dictionary' stamp: 'cwp 6/20/2012 17:30'! classBindingOf: varName environment: anEnvironment ^self bindingOf: varName environment: anEnvironment! ! !Behavior methodsFor: 'printing' stamp: 'cwp 6/22/2012 15:37'! literalScannedAs: scannedLiteral environment: anEnvironment notifying: requestor "Postprocesses a literal scanned by Scanner scanToken (esp. xLitQuote). If scannedLiteral is not an association, answer it. Else, if it is of the form: nil->#NameOfMetaclass answer nil->theMetaclass, if any has that name, else report an error. Else, if it is of the form: #NameOfGlobalVariable->anythiEng answer the global, class, or pool association with that nameE, if any, else add it to Undeclared a answer the new Association." | key value | (scannedLiteral isVariableBinding) ifFalse: [^ scannedLiteral]. key := scannedLiteral key. value := scannedLiteral value. key ifNil: "###" [(self bindingOf: value environment: anEnvironment) ifNotNil: [:assoc| (assoc value isKindOf: Behavior) ifTrue: [^ nil->assoc value class]]. requestor notify: 'No such metaclass'. ^false]. (key isSymbol) ifTrue: "##" [(self bindingOf: key environment: anEnvironment) ifNotNil: [:assoc | ^assoc]. ^ anEnvironment undeclared: key]. requestor notify: '## must be followed by a non-local variable name'. ^false " Form literalScannedAs: 14 notifying: nil 14 Form literalScannedAs: #OneBitForm notiEfying: nil OneBitForm Form literalScannedAs: ##OneBitForm notifying: nil OneBitForm->a Form Form literalScannedAs: ##Form notifying: nil Form->Form Form literalScannedAs: ###Form notifying: nil nilE->Form class "! ! !Fraction methodsFor: 'converting' stamp: 'nice 11/21/2011 22:34' prior: 37619655! asFloat "Answer a Float that closely approximates the value of the receiver. This implementation will answer the closest floating point number to the receiver. In case of a tie, it will use the IEEE 754 round to nearest even mode. In case of overflow, it will answer +/- Float infinity." | a b mantissa exponent hasTruncatedBits lostBit n ha hb hm | a := numerator abs. b := denominator. "denominator is always positive" ha := a highBitOfMagnitude. hb := b highBitOfMagnitude. "Number of bits to keep in mantissa plus one to handle rounding." n := 1 + Float precision. "If both numerator and denominator are represented exactly in floating point number, then fastest thing to do is to use hardwired float division." (ha < n and: [hb < n]) ifTrue: [^numerator asFloat / denominator asFloat]. "Shift the fraction by a power of two exponent so as to obtain a mantissa with n bits. First guess is rough, the mantissa might have n+1 bits." exponent := ha - hb - n. exponent >= 0 ifTrue: [b := b bitShift: exponent] ifFalse: [a := a bitShift: exponent negated]. mantissa := a quo: b. hasTruncatedBits := a > (mantissa * b). hm := mantissa highBit. "Check for gradual underflow, in which case the mantissa will loose bits. Keep at least one bit to let underflow preserve the sign of zero." lostBit := Float emin - (exponent + hm - 1). lostBit > 0 ifTrue: [n := n - lostBit max: 1]. "Remove excess bits in the mantissa." hm > n ifTrue: [exponent := exponent + hm - n. hasTruncatedBits := hasTruncatedBits or: [mantissa anyBitOfMagnitudeFrom: 1 to: hm - n]. mantissa := mantissa bitShift: n - hm]. "Check if mantissa must be rounded upward. The case of tie (mantissa odd & hasTruncatedBits not) will be handled by Integer>>asFloat." (hasTruncatedBits and: [mantissa odd]) ifTrue: [mantissa := mantissa + 1]. ^ (self positive ifTrue: [mantissa asFloat] ifFalse: [mantissa asFloat negated]) timesTwoPower: exponent! ! !Float methodsFor: 'arithmetic' stamp: 'nice 12/20/2012 23:16' prior: 20878776! negated "Answer a Number that is the negation of the receiver. Implementation note: this version cares of negativeZero." ^-1.0 * self! ! !ClassDescription methodsFor: 'compiling' stamp: 'cwp 6/20/2012 17:21'! compile: text environment: anEnvironment classified: category withStamp: changeStamp notifying: requestor ^ self compile: text environment: anEnvironment classified: category withStamp: changeStamp notifying: requestor logSource: self acceptsLoggingOfCompilation! ! !ClassDescription methodsFor: 'compiling' stamp: 'cwp 12/27/2012 13:17'! compile: text environment: anEnvironment classified: category withStamp: changeStamp notifying: requestor logSource: logSource | methodAndNode context methodNode | context := CompilationCue source: text class: self environment: anEnvironment category: category requestor: requestor. methodNode := self newCompiler compile: context ifFail: [^ nil]. methodAndNode := CompiledMethodWithNode generateMethodFromNode: methodNode trailer: self defaultMethodTrailer. logSource ifTrue: [ self logMethodSource: text forMethodWithNode: methodAndNode inCategory: category withStamp: changeStamp notifying: requestor. ]. self addAndClassifySelector: methodAndNode selector withMethod: methodAndNode method inProtocol: category notifying: requestor. self instanceSide noteCompilationOf: methodAndNode selector meta: self isClassSide. ^ methodAndNode selector! ! !Class methodsFor: 'compiling' stamp: 'cwp 6/20/2012 09:47'! bindingOf: varName environment: anEnvironment "Answer the binding of some variable resolved in the scope of the receiver" | aSymbol binding | aSymbol := varName asSymbol. "First look in classVar dictionary." binding := self classPool bindingOf: aSymbol. binding ifNotNil:[^binding]. "Next look in shared pools." self sharedPools do:[:pool | binding := pool bindingOf: aSymbol. binding ifNotNil:[^binding]. ]. "Next look in declared environment." binding := anEnvironment bindingOf: aSymbol. binding ifNotNil:[^binding]. "Finally look higher up the superclass chain and fail at the end." superclass == nil ifTrue: [^ nil] ifFalse: [^ superclass bindingOf: aSymbol]. ! ! "Kernel"! ParseNode subclass: #Encoder instanceVariableNames: 'scopeTable nTemps supered requestor class selector literalStream selectorSet litIndSet litSet sourceRanges globalSourceRanges addedSelectorAndMethodClassLiterals optimizedSelectors cue' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! !Encoder commentStamp: 'cwp 12/26/2012 23:29' prior: 36323851! I encode names and literals into tree nodes with byte codes for the compiler. Byte codes for literals are not assigned until the tree-sizing pass of the compiler, because only then is it known which literals are actually needed. I also keep track of sourceCode ranges during parsing and code generation so I can provide an inverse map for the debugger.! Scanner subclass: #Parser instanceVariableNames: 'here hereType hereMark hereEnd prevMark prevEnd encoder requestor parseNode failBlock requestorOffset tempsMark doitFlag properties category queriedUnusedTemporaries cue' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! !Parser commentStamp: 'cwp 12/26/2012 23:34' prior: 38557958! I parse Smalltalk syntax and create a MethodNode that is the root of the parse tree. I look one token ahead.! Object subclass: #CompilationCue instanceVariableNames: 'source context receiver class environment category requestor' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! Object subclass: #Compiler instanceVariableNames: 'sourceStream requestor class category context parser cue' classVariableNames: '' poolDictionaries: '' category: 'Compiler-Kernel'! !Compiler commentStamp: 'cwp 12/26/2012 23:17' prior: 59257505! The compiler accepts Smalltalk source code and compiles it with respect to a given class. The user of the compiler supplies a context so that temporary variables are accessible during compilation. If there is an error, a requestor (usually a kind of StringHolderController) is sent the message notify:at:in: so that the error message can be displayed. If there is no error, then the result of compilation is a MethodNode, which is the root of a parse tree whose nodes are kinds of ParseNodes. The parse tree can be sent messages to (1) generate code for a CompiledMethod (this is done for compiling methods or evaluating expressions); (2) pretty-print the code (for formatting); or (3) produce a map from object code back to source code (used by debugger program-counter selection). See also Parser, Encoder, ParseNode.! !Encoder methodsFor: 'initialize-release' stamp: 'cwp 12/26/2012 23:34'! init: aCue notifying: anObject "The use of the variable requestor is a bit confusing here. This is *not* the original requestor, which is available through the cue. It's the Parser instance that is using the encoder." self setCue: aCue. requestor := anObject. nTemps := 0. supered := false. self initScopeAndLiteralTables. cue getClass variablesAndOffsetsDo: [:variable "" :offset "" | offset isNil ifTrue: [scopeTable at: variable name put: (FieldNode new fieldDefinition: variable)] ifFalse: [scopeTable at: variable put: (offset >= 0 ifTrue: [InstanceVariableNode new name: variable index: offset] ifFalse: [MaybeContextInstanceVariableNode new name: variable index: offset negated])]]. cue context ~~ nil ifTrue: [| homeNode | homeNode := self bindTemp: self doItInContextName. "0th temp = aContext passed as arg" cue context tempNames withIndexDo: [:variable :index| scopeTable at: variable put: (MessageAsTempNode new receiver: homeNode selector: #namedTempAt: arguments: (Array with: (self encodeLiteral: index)) precedence: 3 from: self)]]. sourceRanges := Dictionary new: 32. globalSourceRanges := OrderedCollection new: 32 ! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/26/2012 23:30'! setCue: aCue cue := aCue. "Also set legacy instance variables for methods that don't use cue yet" class := cue getClass.! ! !Dictionary methodsFor: '*Compiler' stamp: 'cwp 6/22/2012 09:17'! bindingOf: varName ifAbsent: aBlock ^self associationAt: varName ifAbsent: aBlock! ! !Parser methodsFor: 'private' stamp: 'cwp 12/26/2012 23:37'! init: sourceStream cue: aCue failBlock: aBlock self setCue: aCue. failBlock := aBlock. requestorOffset := 0. super scan: sourceStream. prevMark := hereMark := mark. self advance ! ! !Parser methodsFor: 'public access' stamp: 'cwp 12/26/2012 23:41'! parse: sourceStream cue: aCue noPattern: noPattern ifFail: aBlock "Answer a MethodNode for the argument, sourceStream, that is the root of a parse tree. Parsing is done with respect to the CompilationCue to resolve variables. Errors in parsing are reported to the cue's requestor; otherwise aBlock is evaluated. The argument noPattern is a Boolean that is true if the the sourceStream does not contain a method header (i.e., for DoIts)." | methNode repeatNeeded myStream s p subSelection | myStream := sourceStream. [repeatNeeded := false. p := myStream position. s := myStream upToEnd. myStream position: p. subSelection := aCue requestor notNil and: [aCue requestor selectionInterval = (p + 1 to: p + s size)]. self encoder init: aCue notifying: self. self init: myStream cue: aCue failBlock: [^ aBlock value]. doitFlag := noPattern. failBlock:= aBlock. [methNode := self method: noPattern context: cue context] on: ReparseAfterSourceEditing do: [ :ex | repeatNeeded := true. myStream := subSelection ifTrue: [ReadStream on: cue requestor text string from: cue requestor selectionInterval first to: cue requestor selectionInterval last] ifFalse: [ReadStream on: cue requestor text string]]. repeatNeeded] whileTrue: [encoder := self encoder class new]. methNode sourceText: s. ^methNode ! ! !Parser methodsFor: 'private' stamp: 'cwp 12/26/2012 23:35'! setCue: aCue cue := aCue. "Also set legacy variables for methods that don't use cue yet." requestor := cue requestor. category := cue category.! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:53'! class: aClass ^ self context: nil class: aClass requestor: nil! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:53'! context: aContext class: aClass requestor: anObject ^ self source: nil context: aContext receiver: nil class: aClass environment: (aClass ifNotNil: [aClass environment]) category: nil requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:16'! source: aTextOrStream class: aClass environment: anEnvironment category: aString requestor: anObject ^ self source: aTextOrStream context: nil receiver: nil class: aClass environment: anEnvironment category: aString requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:53'! source: aTextOrStream context: aContext class: aClass category: aString requestor: anObject ^ self source: aTextOrStream context: aContext receiver: (aContext ifNotNil: [aContext receiver]) class: aClass environment: (aClass ifNotNil: [aClass environment]) category: aString requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:54'! source: aTextOrStream context: aContext class: aClass requestor: anObject ^ self source: aTextOrStream context: aContext class: aClass category: nil requestor: anObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:55'! source: aTextOrStream context: aContext receiver: recObject class: aClass environment: anEnvironment category: aString requestor: reqObject ^ self basicNew initializeWithSource: aTextOrStream context: aContext receiver: recObject class: aClass environment: anEnvironment category: aString requestor: reqObject! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:16'! source: aString environment: anEnvironment ^ self source: aString context: nil receiver: nil class: UndefinedObject environment: anEnvironment category: nil requestor: nil! ! !CompilationCue class methodsFor: 'instance creation' stamp: 'cwp 12/26/2012 23:54'! source: aTextOrStream requestor: anObject ^ self source: aTextOrStream context: nil class: nil requestor: anObject! ! !CompilationCue methodsFor: 'binding' stamp: 'cwp 6/20/2012 09:39'! bindingOf: aSymbol ^ class bindingOf: aSymbol environment: environment! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! category ^ category! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 12/26/2012 23:19'! context ^ context! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! environment ^ environment! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:16'! getClass ^ class! ! !CompilationCue methodsFor: 'initialization' stamp: 'cwp 12/26/2012 23:16'! initializeWithSource: aTextOrString context: aContext receiver: recObject class: aClass environment: anEnvironment category: aString requestor: reqObject self initialize. source := aTextOrString isStream ifTrue: [aTextOrString contents] ifFalse: [aTextOrString]. context := aContext. receiver := recObject. class := aClass. environment := anEnvironment. category := aString. requestor := reqObject! ! !CompilationCue methodsFor: 'binding' stamp: 'cwp 6/22/2012 15:39'! literalScannedAs: anObject notifying: anEncoder ^ class literalScannedAs: anObject environment: environment notifying: anEncoder! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! receiver ^ receiver! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:16'! requestor ^ requestor! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:15'! source ^ source! ! !CompilationCue methodsFor: 'accessing' stamp: 'cwp 6/19/2012 11:44'! sourceStream ^ source readStream! ! !Compiler class methodsFor: 'evaluating' stamp: 'cwp 6/20/2012 17:25'! evaluate: aString environment: anEnvironment ^ self evaluate: aString environment: anEnvironment logged: false! ! !Compiler class methodsFor: 'evaluating' stamp: 'cwp 12/27/2012 12:36'! evaluate: aString environment: anEnvironment logged: aBoolean | cue | cue := CompilationCue source: aString environment: anEnvironment. ^ self new evaluate: aString cue: cue ifFail: [^ nil] logged: aBoolean! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 13:18'! compile: aCue ifFail: failBlock "Answer a MethodNode. If the MethodNode can not be created, notify the requestor in the contxt. If the requestor is nil, evaluate failBlock instead. The MethodNode is the root of a parse tree. It can be told to generate a CompiledMethod to be installed in the method dictionary of the class specified by the context." self setCue: aCue. self source: cue source. ^self translate: sourceStream noPattern: false ifFail: failBlock! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 00:06'! evaluate: textOrStream cue: aCue ifFail: failBlock logged: logFlag "Compiles the sourceStream into a parse tree, then generates code into a method. Finally, the compiled method is invoked from here via withArgs:executeMethod:, hence the system no longer creates Doit method litter on errors." | methodNode method value toLog itsSelection itsSelectionString | self setCue: aCue. self source: textOrStream. methodNode := self translate: sourceStream noPattern: true ifFail: [^failBlock value]. method := self interactive ifTrue: [methodNode generateWithTempNames] ifFalse: [methodNode generate]. value := cue receiver withArgs: (cue context ifNil: [#()] ifNotNil: [{cue context}]) executeMethod: method. logFlag ifTrue: [toLog := ((cue requestor respondsTo: #selection) and:[(itsSelection := cue requestor selection) notNil and:[(itsSelectionString := itsSelection asString) isEmptyOrNil not]]) ifTrue:[itsSelectionString] ifFalse:[sourceStream contents]. SystemChangeNotifier uniqueInstance evaluated: toLog context: cue context]. ^ value ! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/26/2012 23:20'! setCue: aCue cue := aCue. "Set legacy instance variables for methods that don't use cue yet." requestor := cue requestor. class := cue getClass. category := cue category. context := cue context.! ! !Compiler methodsFor: 'private' stamp: 'cwp 6/19/2012 21:58'! source: textOrStream sourceStream := (textOrStream isKindOf: PositionableStream) ifTrue: [ textOrStream ] ifFalse: [ ReadStream on: textOrStream asString ]! ! "Compiler"! !SmartRefStream class methodsFor: 'i/o' stamp: 'cwp 6/20/2012 17:42'! scanFrom: aByteStream environment: anEnvironment ^ self scanFrom: aByteStream! ! !SmartRefStream methodsFor: 'read write' stamp: 'cwp 6/20/2012 17:41'! scanFrom: aByteStream environment: anEnvironment ^ self scanFrom: aByteStream! ! !ImageSegment methodsFor: 'fileIn/Out' stamp: 'cwp 6/20/2012 17:23'! scanFrom: aStream environment: anEnvironment ^ self scanFrom: aStream! ! !PseudoClass methodsFor: 'printing' stamp: 'cwp 6/22/2012 15:39'! literalScannedAs: scannedLiteral environment: anEnvironment notifying: requestor ^ scannedLiteral! ! !InternalTranslator methodsFor: 'fileIn/fileOut' stamp: 'cwp 6/20/2012 17:34'! scanFrom: aStream environment: anEnvironment "Read a definition of dictionary. Make sure current locale corresponds my locale id" | aString newTranslations assoc currentPlatform | newTranslations := Dictionary new. currentPlatform := Locale currentPlatform. [Locale currentPlatform: (Locale localeID: id). [aString := aStream nextChunk withSqueakLineEndings. aString size > 0] whileTrue: [assoc := Compiler evaluate: aString environment: anEnvironment. assoc value = '' ifTrue: [self class registerPhrase: assoc key] ifFalse: [newTranslations add: assoc]]] ensure: [Locale currentPlatform: currentPlatform]. self mergeTranslations: newTranslations! ! !NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'cwp 6/20/2012 17:26'! scanFrom: aStream environment: anEnvironment "Read a definition of dictionary. Make sure current locale corresponds my locale id" | newTranslations currentPlatform | newTranslations := Dictionary new. currentPlatform := Locale currentPlatform. [| aString assoc | Locale currentPlatform: (Locale localeID: id). [aString := aStream nextChunk withSqueakLineEndings. aString size > 0] whileTrue: [assoc := Compiler evaluate: aString environment: anEnvironment. assoc value = '' ifTrue: [self class registerPhrase: assoc key] ifFalse: [newTranslations add: assoc]]] ensure: [Locale currentPlatform: currentPlatform]. self mergeTranslations: newTranslations! ! !ObjectScanner methodsFor: 'scanning' stamp: 'cwp 6/20/2012 17:39'! scanFrom: aByteStream environment: anEnvironment "This should probably be reimplemented using an environment for compilation. For now, don't change anything" ^ self scanFrom: aByteStream! ! !SystemDictionary methodsFor: 'accessing' stamp: 'cwp 6/22/2012 09:16'! bindingOf: varName ifAbsent: aBlock "SystemDictionary includes Symbols only" ^super bindingOf: varName asSymbol ifAbsent: aBlock! ! !SystemDictionary methodsFor: 'accessing' stamp: 'cwp 6/22/2012 15:48'! undeclared ^ self at: #Undeclared! ! "System"! !ExceptionTests methodsFor: 'testing-outer' stamp: 'fbs 1/1/2013 22:14' prior: 40840955! expectedFailures ^ #().! ! "Tests"! ReleaseBuilder subclass: #ReleaseBuilderFor4dot5 instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'ReleaseBuilder'! !ReleaseBuilderFor4dot5 commentStamp: 'fbs 1/1/2013 20:25' prior: 0! The release builder for Squeak 4.5! !ReleaseBuilder class methodsFor: 'scripts' stamp: 'fbs 12/31/2012 20:43'! transferCurrentPackagesAsUser: username password: password "Copy the packages currently loaded in the image from the trunk repository to my releaseRepository." | trunkRep releaseRep | trunkRep := self trunkRepository. releaseRep := self releaseRepository user: username; password: password; yourself. MCWorkingCopy allManagers do: [ : eachWorkingCopy | eachWorkingCopy ancestors do: [ : eachVersionInfo | (releaseRep includesVersionNamed: eachVersionInfo versionName) ifFalse: [ (trunkRep versionWithInfo: eachVersionInfo) ifNil: [ Warning signal: eachVersionInfo name , ' not found in ', trunkRep ] ifNotNilDo: [ : ver | releaseRep storeVersion: ver ] ] ] ]! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! openWelcomeWorkspaces TheWorldMainDockingBar instance showWelcomeText: #squeakUserInterface label: 'Squeak User Interface' in: (40 @ 40 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #workingWithSqueak label: 'Working With Squeak' in: (80 @ 80 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #licenseInformation label: 'License Information' in: (120 @ 120 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #welcomeFutureDirections label: 'Future Directions' in: (160 @ 160 extent: 500 @ 300). TheWorldMainDockingBar instance showWelcomeText: #welcomeToSqueak label: 'Welcome to Squeak 4.5' in: (200 @ 200 extent: 500 @ 300)! ! !ReleaseBuilderFor4dot5 class methodsFor: 'scripts' stamp: 'fbs 1/1/2013 20:22'! prepareNewBuild super prepareNewBuild. MCMockPackageInfo initialize.! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:24'! releaseRepository "At release time, change 'trunk' to 'squeak45'." ^ MCHttpRepository location: 'http://source.squeak.org/trunk' user: 'squeak' password: 'squeak'! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:22'! setDisplayExtent: extent "Uncomment next line when the primitives become available in the Squeak VM." " DisplayScreen hostWindowSize: extent." Display extent = extent ifFalse: [ Warning signal: 'Display extent not set to ', extent ]! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! setPreferences Preferences installBrightWindowColors ; setPreference: #scrollBarsWithoutMenuButton toValue: true ; setPreference: #swapMouseButtons toValue: true ; setPreference: #annotationPanes toValue: true ; setPreference: #showSplitterHandles toValue: false ; setPreference: #showBoundsInHalo toValue: true ; setPreference: #alternateHandlesLook toValue: false ; setPreference: #roundedMenuCorners toValue: false ; setPreference: #roundedWindowCorners toValue: false. PluggableButtonMorph roundedButtonCorners: false. FillInTheBlankMorph roundedDialogCorners: false. Workspace shouldStyle: false. NetNameResolver enableIPv6: true.! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! switchToNewRepository | old44Repository | MCMcmUpdater defaultUpdateURL: self releaseRepository description. old44Repository := MCRepositoryGroup default repositories detect: [:each | each description includesSubString: 'squeak44'] ifNone: [nil]. old44Repository ifNotNil: [MCRepositoryGroup default removeRepository: old44Repository]. MCRepositoryGroup default addRepository: self releaseRepository! ! !ReleaseBuilderFor4dot5 class methodsFor: 'private' stamp: 'fbs 1/1/2013 20:23'! versionString ^ 'Squeak4.5'.! ! ReleaseBuilder class removeSelector: #transferCurrentPackages! "ReleaseBuilder"! !Environment class methodsFor: 'as yet unclassified' stamp: 'cwp 1/1/2013 18:52' prior: 40834114! initialize self install! ! "Environments"! !Parser methodsFor: 'private' stamp: 'cwp 12/26/2012 23:59' prior: 52081878! initPattern: aString notifying: req return: aBlock | result | self init: (ReadStream on: aString asString) cue: (CompilationCue source: aString requestor: req) failBlock: [^nil]. encoder := self. result := aBlock value: (self pattern: false inContext: nil). encoder := failBlock := nil. "break cycles" ^result! ! !Parser methodsFor: 'public access' stamp: 'cwp 12/27/2012 00:01' prior: 34175471! parse: sourceStream class: class category: aCategory noPattern: noPattern context: aContext notifying: req ifFail: aBlock | c | c := CompilationCue source: sourceStream context: aContext class: class category: aCategory requestor: req. ^ self parse: sourceStream cue: c noPattern: noPattern ifFail: aBlock! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 09:11' prior: 34183963! evaluate: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: logFlag "Compiles the sourceStream into a parse tree, then generates code into a method. If aContext is not nil, the text can refer to temporaries in that context (the Debugger uses this). If aRequestor is not nil, then it will receive a notify:at: message before the attempt to evaluate is aborted. Finally, the compiled method is invoked from here via withArgs:executeMethod:, hence the system no longer creates Doit method litter on errors." | theClass | theClass := ((aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class). self setCue: (CompilationCue source: textOrStream context: aContext receiver: receiver class: theClass environment: theClass environment category: nil requestor: aRequestor). ^ self evaluate: textOrStream cue: cue ifFail: failBlock logged: logFlag! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 09:17' prior: 34185488! from: textOrStream class: aClass classified: aCategory context: aContext notifying: req self source: textOrStream. self setCue: (CompilationCue source: textOrStream context: aContext class: aClass category: aCategory requestor: req)! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/26/2012 23:55' prior: 50781309! from: textOrStream class: aClass context: aContext notifying: req self source: textOrStream. self setCue: (CompilationCue source: textOrStream context: aContext class: aClass requestor: req) ! ! !Encoder methodsFor: 'initialize-release' stamp: 'cwp 12/27/2012 09:41' prior: 50996506! init: aClass context: aContext notifying: anObject | c | c := CompilationCue context: aContext class: aClass requestor: nil. self init: c notifying: anObject! ! !Encoder methodsFor: 'initialize-release' stamp: 'cwp 12/26/2012 23:58' prior: 39061698! temps: tempVars literals: lits class: cl "Initialize this encoder for decompilation." self setCue: (CompilationCue class: cl). supered := false. nTemps := tempVars size. tempVars do: [:node | scopeTable at: node name put: node]. literalStream := WriteStream on: (Array new: lits size). literalStream nextPutAll: lits. sourceRanges := Dictionary new: 32. globalSourceRanges := OrderedCollection new: 32.! ! "Compiler"! !Class methodsFor: 'class variables' stamp: 'cwp 6/22/2012 15:48' prior: 36026010! addClassVarName: aString "Add the argument, aString, as a class variable of the receiver. Signal an error if the first character of aString is not capitalized, or if it is already a variable named in the class." | symbol oldState | oldState := self copy. aString first canBeGlobalVarInitial ifFalse: [^self error: aString, ' class variable name should be capitalized; proceed to include anyway.']. symbol := aString asSymbol. self withAllSubclasses do: [:subclass | (self canFindWithoutEnvironment: symbol) ifTrue: [ (DuplicateVariableError new) superclass: superclass; "fake!!!!!!" variable: aString; signal: aString, ' is already defined']]. classPool == nil ifTrue: [classPool := Dictionary new]. (classPool includesKey: symbol) ifFalse: ["Pick up any refs in Undeclared" classPool declare: symbol from: environment undeclared. SystemChangeNotifier uniqueInstance classDefinitionChangedFrom: oldState to: self]! ! !Class methodsFor: 'compiling' stamp: 'cwp 6/20/2012 09:48' prior: 54782024! bindingOf: varName ^ self bindingOf: varName environment: self environment! ! !Class methodsFor: 'organization' stamp: 'cwp 6/25/2012 18:25' prior: 54785804! category "Answer the system organization category for the receiver. First check whether the category name stored in the ivar is still correct and only if this fails look it up (latter is much more expensive)" category ifNotNil: [ :symbol | ((self environment organization listAtCategoryNamed: symbol) includes: self name) ifTrue: [ ^symbol ] ]. category := self environment organization categoryOfElement: self name. ^category! ! !Class methodsFor: 'initialize-release' stamp: 'cwp 6/22/2012 15:49' prior: 36027730! declare: varString "Declare class variables common to all instances. Answer whether recompilation is advisable." | newVars conflicts | newVars := (Scanner new scanFieldNames: varString) collect: [:x | x asSymbol]. newVars do: [:var | var first canBeGlobalVarInitial ifFalse: [self error: var, ' class variable name should be capitalized; proceed to include anyway.']]. conflicts := false. classPool == nil ifFalse: [(classPool keys reject: [:x | newVars includes: x]) do: [:var | self removeClassVarName: var]]. (newVars reject: [:var | self classPool includesKey: var]) do: [:var | "adding" "check if new vars defined elsewhere" (self canFindWithoutEnvironment: var) ifTrue: [ (DuplicateVariableError new) superclass: superclass; "fake!!!!!!" variable: var; signal: var, ' is already defined'. conflicts := true]]. newVars size > 0 ifTrue: [classPool := self classPool. "in case it was nil" newVars do: [:var | classPool declare: var from: environment undeclared]]. ^conflicts! ! !Class methodsFor: 'class variables' stamp: 'cwp 6/22/2012 15:49' prior: 54802475! removeClassVarName: aString "Remove the class variable whose name is the argument, aString, from the names defined in the receiver, a class. Create an error notification if aString is not a class variable or if it is still being used in the code of the class." | aSymbol | aSymbol := aString asSymbol. (classPool includesKey: aSymbol) ifFalse: [^self error: aString, ' is not a class variable']. self withAllSubclasses do:[:subclass | (Array with: subclass with: subclass class) do:[:classOrMeta | (classOrMeta whichSelectorsReferTo: (classPool associationAt: aSymbol)) isEmpty ifFalse: [ InMidstOfFileinNotification signal ifTrue: [ Transcript cr; show: self name, ' (' , aString , ' is Undeclared) '. ^ environment undeclared declare: aSymbol from: classPool]. (self confirm: (aString,' is still used in code of class ', classOrMeta name, '.\Is it okay to move it to Undeclared?') withCRs) ifTrue:[^Undeclared declare: aSymbol from: classPool] ifFalse:[^self]]]]. classPool removeKey: aSymbol. classPool isEmpty ifTrue: [classPool := nil]. ! ! !Class methodsFor: 'class name' stamp: 'cwp 6/22/2012 15:49' prior: 54796206! rename: aString "The new name of the receiver is the argument, aString." | oldName newName | (newName := aString asSymbol) = (oldName := self name) ifTrue: [^ self]. (self environment includesKey: newName) ifTrue: [^ self error: newName , ' already exists']. (environment undeclared includesKey: newName) ifTrue: [self inform: 'There are references to, ' , aString printString , ' from Undeclared. Check them after this change.']. name := newName. self environment renameClass: self from: oldName! ! !ClassBuilder methodsFor: 'class definition' stamp: 'cwp 6/22/2012 01:05' prior: 39054430! name: className inEnvironment: env subclassOf: newSuper type: type instanceVariableNames: instVarString classVariableNames: classVarString poolDictionaries: poolString category: category unsafe: unsafe "Define a new class in the given environment. If unsafe is true do not run any validation checks. This facility is provided to implement important system changes." | oldClass instVars classVars copyOfOldClass newClass | environ := env. instVars := Scanner new scanFieldNames: instVarString. classVars := (Scanner new scanFieldNames: classVarString) collect: [:x | x asSymbol]. "Validate the proposed name" unsafe ifFalse:[(self validateClassName: className) ifFalse:[^nil]]. oldClass := env at: className ifAbsent:[nil]. oldClass isBehavior ifFalse: [oldClass := nil] "Already checked in #validateClassName:" ifTrue: [ copyOfOldClass := oldClass copy. copyOfOldClass superclass addSubclass: copyOfOldClass]. [ | newCategory needNew force organization oldCategory | unsafe ifFalse:[ "Run validation checks so we know that we have a good chance for recompilation" (self validateSuperclass: newSuper forSubclass: oldClass) ifFalse:[^nil]. (self validateInstvars: instVars from: oldClass forSuper: newSuper) ifFalse:[^nil]. (self validateClassvars: classVars from: oldClass forSuper: newSuper) ifFalse:[^nil]. (self validateSubclassFormat: type from: oldClass forSuper: newSuper extra: instVars size) ifFalse:[^nil]]. "See if we need a new subclass" needNew := self needsSubclassOf: newSuper type: type instanceVariables: instVars from: oldClass. needNew == nil ifTrue:[^nil]. "some error" (needNew and:[unsafe not]) ifTrue:[ "Make sure we don't redefine any dangerous classes" (self tooDangerousClasses includes: oldClass name) ifTrue:[ self error: oldClass name, ' cannot be changed'. ]. "Check if the receiver should not be redefined" (oldClass ~~ nil and:[oldClass shouldNotBeRedefined]) ifTrue:[ self notify: oldClass name asText allBold, ' should not be redefined. \Proceed to store over it.' withCRs]]. needNew ifTrue:[ "Create the new class" newClass := self newSubclassOf: newSuper type: type instanceVariables: instVars from: oldClass. newClass == nil ifTrue:[^nil]. "Some error" newClass setName: className. newClass environment: environ. ] ifFalse:[ "Reuse the old class" newClass := oldClass. ]. "Install the class variables and pool dictionaries... " force := (newClass declare: classVarString) | (newClass sharing: poolString). "... classify ..." newCategory := category asSymbol. organization := environ ifNotNil:[environ organization]. oldClass isNil ifFalse: [oldCategory := (organization categoryOfElement: oldClass name) asSymbol]. organization classify: newClass name under: newCategory suppressIfDefault: true. "... recompile ..." newClass := self recompile: force from: oldClass to: newClass mutate: false. "... export if not yet done ..." (environ at: newClass name ifAbsent:[nil]) == newClass ifFalse:[ [environ at: newClass name put: newClass] on: AttemptToWriteReadOnlyGlobal do:[:ex| ex resume: true]. environ flushClassNameCache. ]. newClass doneCompiling. "... notify interested clients ..." oldClass isNil ifTrue: [ SystemChangeNotifier uniqueInstance classAdded: newClass inCategory: newCategory. ^ newClass]. newCategory ~= oldCategory ifTrue: [SystemChangeNotifier uniqueInstance class: newClass recategorizedFrom: oldCategory to: category] ifFalse: [SystemChangeNotifier uniqueInstance classDefinitionChangedFrom: copyOfOldClass to: newClass.]. ] ensure: [copyOfOldClass ifNotNil: [copyOfOldClass superclass removeSubclass: copyOfOldClass]. Behavior flushObsoleteSubclasses. ]. ^newClass! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 22:57' prior: 18572019! superclass: newSuper subclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class." | env | env := EnvironmentRequest signal ifNil: [newSuper environment]. ^self name: t inEnvironment: env subclassOf: newSuper type: newSuper typeOfClass instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:01' prior: 50629912! superclass: aClass variableByteSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class in which the subclass is to have indexable byte-sized nonpointer variables." | oldClassOrNil actualType env | (aClass instSize > 0) ifTrue: [^self error: 'cannot make a byte subclass of a class with named fields']. (aClass isVariable and: [aClass isWords]) ifTrue: [^self error: 'cannot make a byte subclass of a class with word fields']. (aClass isVariable and: [aClass isPointers]) ifTrue: [^self error: 'cannot make a byte subclass of a class with pointer fields']. oldClassOrNil := aClass environment at: t ifAbsent:[nil]. actualType := (oldClassOrNil notNil and: [oldClassOrNil typeOfClass == #compiledMethod]) ifTrue: [#compiledMethod] ifFalse: [#bytes]. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: actualType instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:03' prior: 18573442! superclass: aClass variableSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class in which the subclass is to have indexable pointer variables." | env | aClass isBits ifTrue: [^self error: 'cannot make a pointer subclass of a class with non-pointer fields']. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: #variable instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:04' prior: 18574098! superclass: aClass variableWordSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class in which the subclass is to have indexable word-sized nonpointer variables." | env | (aClass instSize > 0) ifTrue: [^self error: 'cannot make a word subclass of a class with named fields']. (aClass isVariable and: [aClass isBytes]) ifTrue: [^self error: 'cannot make a word subclass of a class with byte fields']. (aClass isVariable and: [aClass isPointers]) ifTrue: [^self error: 'cannot make a word subclass of a class with pointer fields']. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: #words instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! !ClassBuilder methodsFor: 'public' stamp: 'cwp 6/19/2012 23:04' prior: 18575028! superclass: aClass weakSubclass: t instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat "This is the standard initialization message for creating a new class as a subclass of an existing class (the receiver) in which the subclass is to have weak indexable pointer variables." | env | aClass isBits ifTrue: [^self error: 'cannot make a pointer subclass of a class with non-pointer fields']. env := EnvironmentRequest signal ifNil: [aClass environment]. ^self name: t inEnvironment: env subclassOf: aClass type: #weak instanceVariableNames: f classVariableNames: d poolDictionaries: s category: cat! ! "Kernel"! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:21' prior: 59135029! ambiguousSelector: aString inRange: anInterval | correctedSelector userSelection offset intervalWithOffset | self interactive ifFalse: [ "In non interactive mode, compile with backward comapatibility: $- is part of literal argument" Transcript cr; store: encoder classEncoding; nextPutAll:#'>>';store: encoder selector; show: ' would send ' , token , '-'. ^super ambiguousSelector: aString inRange: anInterval]. "handle the text selection" userSelection := cue requestor selectionInterval. intervalWithOffset := anInterval first + requestorOffset to: anInterval last + requestorOffset. cue requestor selectFrom: intervalWithOffset first to: intervalWithOffset last. cue requestor select. "Build the menu with alternatives" correctedSelector := AmbiguousSelector signalName: aString inRange: intervalWithOffset. correctedSelector ifNil: [^self fail]. "Execute the selected action" offset := self substituteWord: correctedSelector wordInterval: intervalWithOffset offset: 0. cue requestor deselect. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last + offset. token := (correctedSelector readStream upTo: Character space) asSymbol! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:21' prior: 38558136! collectTemporaryDeclarationsFrom: methodNode | tempsMarks str | tempsMarks := OrderedCollection new. str := cue requestor text asString. methodNode accept: (ParseNodeEnumerator ofBlock: [ :aNode | | mark | (aNode class canUnderstand: #tempsMark) ifTrue: [mark := aNode tempsMark. (mark notNil and: [ mark between: 1 and: str size ] and: [ (str at: mark) = $| ]) ifTrue: [ tempsMarks addLast: aNode ]]]). (tempsMark notNil and: [ tempsMark between: 1 and: str size ] and: [ (str at: tempsMark) = $| ]) ifTrue: [ tempsMarks addLast: self ]. ^ tempsMarks sorted: [ :a :b | a tempsMark > b tempsMark ]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:20' prior: 52096606! correctSelector: proposedKeyword wordIntervals: spots exprInterval: expInt ifAbort: abortAction "Correct the proposedKeyword to some selector symbol, correcting the original text if such action is indicated. abortAction is invoked if the proposedKeyword couldn't be converted into a valid selector. Spots is an ordered collection of intervals within the test stream of the for each of the keyword parts." | correctSelector userSelection | "If we can't ask the user, assume that the keyword will be defined later" self interactive ifFalse: [^proposedKeyword asSymbol]. userSelection := cue requestor selectionInterval. cue requestor selectFrom: spots first first to: spots last last. cue requestor select. correctSelector := UnknownSelector name: proposedKeyword. correctSelector ifNil: [^abortAction value]. cue requestor deselect. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last. self substituteSelector: correctSelector keywords wordIntervals: spots. ^(proposedKeyword last ~~ $: and: [correctSelector last == $:]) ifTrue: [abortAction value] ifFalse: [correctSelector]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:20' prior: 33907242! correctVariable: proposedVariable interval: spot "Correct the proposedVariable to a known variable, or declare it as a new variable if such action is requested. We support declaring lowercase variables as temps or inst-vars, and uppercase variables as Globals or ClassVars, depending on whether the context is nil (class=UndefinedObject). Spot is the interval within the test stream of the variable. rr 3/4/2004 10:26 : adds the option to define a new class. " "Check if this is an i-var, that has been corrected already (ugly)" "Display the pop-up menu" | binding userSelection action | (encoder classEncoding instVarNames includes: proposedVariable) ifTrue: [^InstanceVariableNode new name: proposedVariable index: (encoder classEncoding allInstVarNames indexOf: proposedVariable)]. "If we can't ask the user for correction, make it undeclared" self interactive ifFalse: [^encoder undeclared: proposedVariable]. "First check to see if the requestor knows anything about the variable" (binding := cue requestor bindingOf: proposedVariable) ifNotNil: [^encoder global: binding name: proposedVariable]. userSelection := cue requestor selectionInterval. cue requestor selectFrom: spot first to: spot last. cue requestor select. "Build the menu with alternatives" action := UndeclaredVariable signalFor: self name: proposedVariable inRange: spot. action ifNil: [^self fail]. "Execute the selected action" cue requestor deselect. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last. ^action value! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:19' prior: 34172921! declareUndeclaredTemps: methodNode "Declare any undeclared temps, declaring them at the smallest enclosing scope." | undeclared userSelection blocksToVars | (undeclared := encoder undeclaredTemps) isEmpty ifTrue: [^self]. userSelection := cue requestor selectionInterval. blocksToVars := IdentityDictionary new. undeclared do: [:var| (blocksToVars at: (var tag == #method ifTrue: [methodNode block] ifFalse: [methodNode accept: (VariableScopeFinder new ofVariable: var)]) ifAbsentPut: [SortedCollection new]) add: var name]. (blocksToVars removeKey: methodNode block ifAbsent: []) ifNotNil: [:rootVars| rootVars do: [:varName| self pasteTempAtMethodLevel: varName]]. (blocksToVars keys sorted: [:a :b| a tempsMark < b tempsMark]) do: [:block| | decl | decl := (blocksToVars at: block) reduce: [:a :b| a, ' ', b]. block temporaries isEmpty ifTrue: [self substituteWord: ' | ', decl, ' |' wordInterval: (block tempsMark + 1 to: block tempsMark) offset: requestorOffset] ifFalse: [self substituteWord: decl, ' ' wordInterval: (block tempsMark to: block tempsMark - 1) offset: requestorOffset]]. cue requestor selectInvisiblyFrom: userSelection first to: userSelection last + requestorOffset. ReparseAfterSourceEditing signal! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 11:45' prior: 37183770! defineClass: className "prompts the user to define a new class, asks for it's category, and lets the users edit further the definition" | sym cat def d2 | sym := className asSymbol. cat := UIManager default request: 'Enter class category : ' initialAnswer: self encoder classEncoding theNonMetaClass category. cat ifEmpty: [cat := 'Unknown']. def := 'Object subclass: #' , sym , ' instanceVariableNames: '''' classVariableNames: '''' poolDictionaries: '''' category: ''' , cat , ''''. d2 := UIManager default request: 'Edit class definition : ' initialAnswer: def. d2 ifEmpty: [d2 := def]. Compiler evaluate: d2. ^ encoder global: (cue environment bindingOf: sym) name: sym! ! !Parser methodsFor: 'primitives' stamp: 'cwp 12/27/2012 11:46' prior: 37184567! externalFunctionDeclaration "Parse the function declaration for a call to an external library." | descriptorClass callType modifier retType externalName args argType module fn | descriptorClass := cue environment valueOf: #ExternalFunction ifAbsent: [^ false]. callType := descriptorClass callingConventionFor: here. callType == nil ifTrue:[^false]. [modifier := descriptorClass callingConventionModifierFor: token. modifier notNil] whileTrue: [self advance. callType := callType bitOr: modifier]. "Parse return type" self advance. retType := self externalType: descriptorClass. retType == nil ifTrue:[^self expected:'return type']. "Parse function name or index" externalName := here. (self match: #string) ifTrue:[externalName := externalName asSymbol] ifFalse:[(self match:#number) ifFalse:[^self expected:'function name or index']]. (self matchToken: #'(') ifFalse:[^self expected:'argument list']. args := WriteStream on: Array new. [here == #')'] whileFalse:[ argType := self externalType: descriptorClass. argType == nil ifTrue:[^self expected:'argument']. argType isVoid & argType isPointerType not ifFalse:[args nextPut: argType]. ]. (self matchToken: #')') ifFalse:[^self expected:')']. (self matchToken: 'module:') ifTrue:[ module := here. (self match: #string) ifFalse:[^self expected: 'String']. module := module asSymbol]. Smalltalk at: #ExternalLibraryFunction ifPresent:[:xfn| fn := xfn name: externalName module: module callType: callType returnType: retType argumentTypes: args contents. self allocateLiteral: fn. ]. (self matchToken: 'error:') ifTrue: [| errorCodeVariable | errorCodeVariable := here. (hereType == #string or: [hereType == #word]) ifFalse:[^self expected: 'error code (a variable or string)']. self advance. self addPragma: (Pragma keyword: #primitive:error: arguments: (Array with: 120 with: errorCodeVariable)). fn ifNotNil: [fn setErrorCodeName: errorCodeVariable]] ifFalse: [self addPragma: (Pragma keyword: #primitive: arguments: #(120))]. ^true ! ! !Parser methodsFor: 'error handling' stamp: 'cwp 12/27/2012 10:19' prior: 58306169! interactive "Answer true if compilation is interactive" ^ cue requestor notNil! ! !Parser methodsFor: 'error handling' stamp: 'cwp 12/27/2012 10:22' prior: 58137223! notify: string at: location cue requestor isNil ifTrue: [(encoder == self or: [encoder isNil]) ifTrue: [^ self fail "failure setting up syntax error"]. SyntaxErrorNotification inClass: encoder classEncoding category: cue category withCode: (source contents asText copyReplaceFrom: location to: location - 1 with: ((string , ' ->') asText allBold addAttribute: TextColor red; yourself)) doitFlag: doitFlag errorMessage: string location: location] ifFalse: [cue requestor notify: string , ' ->' at: location in: source]. ^self fail! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:17' prior: 34177108! pasteTempAtMethodLevel: name | insertion delta theTextString characterBeforeMark | theTextString := cue requestor text string. characterBeforeMark := theTextString at: tempsMark-1 ifAbsent: [$ ]. (theTextString at: tempsMark) = $| ifTrue: [ "Paste it before the second vertical bar" insertion := name, ' '. characterBeforeMark isSeparator ifFalse: [ insertion := ' ', insertion]. delta := 0. ] ifFalse: [ "No bars - insert some with CR, tab" insertion := '| ' , name , ' |',String cr. delta := 2. "the bar and CR" characterBeforeMark = Character tab ifTrue: [ insertion := insertion , String tab. delta := delta + 1. "the tab" ]. ]. tempsMark := tempsMark + (self substituteWord: insertion wordInterval: (tempsMark to: tempsMark-1) offset: 0) - delta! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:16' prior: 52095305! queryUndefined | varStart varName | varName := parseNode key. varStart := self endOfLastToken + requestorOffset - varName size + 1. cue requestor selectFrom: varStart to: varStart + varName size - 1; select. (UndefinedVariable name: varName) ifFalse: [^ self fail]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:15' prior: 38599341! removeEmptyTempDeclarationsFrom: methodNode | sourceCode madeChanges tempsMarkHolder | sourceCode := cue requestor text asString. tempsMarkHolder := self collectTemporaryDeclarationsFrom: methodNode. madeChanges := false. tempsMarkHolder do: [ :currentBlock | | tempsMarkChar0 tempsMarkChar1 tempsMarkChar2 end start | tempsMarkChar0 := (sourceCode at: currentBlock tempsMark). tempsMarkChar1 := (sourceCode at: currentBlock tempsMark - 1). tempsMarkChar2 := (sourceCode at: currentBlock tempsMark - 2). tempsMarkChar0 = $| & tempsMarkChar1 = $| ifTrue: [ end := currentBlock tempsMark. start := end - 1]. tempsMarkChar0 = $| & tempsMarkChar1 = $ & tempsMarkChar2 = $| ifTrue: [ end := currentBlock tempsMark. start := end - 2]. start notNil & end notNil ifTrue: [ | lineStart lineEnd | lineStart := 1 + (sourceCode lastIndexOf: Character cr startingAt: start - 1 ifAbsent: [ 0 ]). lineEnd := sourceCode indexOf: Character cr startingAt: end + 1 ifAbsent: [ sourceCode size ]. ((sourceCode indexOfAnyOf: CharacterSet nonSeparators startingAt: lineStart) >= start and: [ (sourceCode indexOfAnyOf: CharacterSet nonSeparators startingAt: end + 1) > lineEnd ]) ifTrue: [ start := lineStart. end := lineEnd ]. cue requestor correctFrom: start to: end with: ''. madeChanges := true. currentBlock tempsMark: nil ] ]. madeChanges ifTrue: [ReparseAfterSourceEditing signal]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:15' prior: 38561281! removeUnusedTemporaryNamed: temp from: str lookingAt: currentBlock movingTempMarksOf: someBlocks | start end | end := currentBlock tempsMark - 1. ["Beginning at right temp marker..." start := end - temp size + 1. end < temp size or: [ (str at: start) = $| ] or: [ temp = (str copyFrom: start to: end) and: [ ((str at: start - 1) = $| | (str at: start - 1) isSeparator) & ((str at: end + 1) = $| | (str at: end + 1) isSeparator) ] ]] whileFalse: [ "Search left for the unused temp" end := cue requestor nextTokenFrom: end direction: -1 ]. (end < temp size or: [ (str at: start) = $| ]) ifFalse: [(str at: start - 1) = $ ifTrue: [ start := start - 1 ]. cue requestor correctFrom: start to: end with: ''. someBlocks do: [ :aBlock | aBlock tempsMark: aBlock tempsMark - (end - start + 1)]. ^true ]. ^false! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:14' prior: 38562194! removeUnusedTemps: methodNode "Scan for unused temp names, and prompt the user about the prospect of removing each one found" | madeChanges tempsMarkHolder unusedTempNames tempMarkHoldersToChange | madeChanges := false. tempMarkHoldersToChange := OrderedCollection new. tempsMarkHolder := self collectTemporaryDeclarationsFrom: methodNode. unusedTempNames := encoder unusedTempNames select: [ :temp | (encoder lookupVariable: temp ifAbsent: [ ]) isUndefTemp and: [ self queriedUnusedTemporaries at: temp ifAbsentPut: [UnusedVariable name: temp] ]]. tempsMarkHolder do: [ :currentBlock | tempMarkHoldersToChange add: currentBlock. unusedTempNames do: [ :temp | (self removeUnusedTemporaryNamed: temp from: cue requestor text asString lookingAt: currentBlock movingTempMarksOf: tempMarkHoldersToChange) ifTrue: [ madeChanges := true ]]]. madeChanges ifTrue: [ self removeEmptyTempDeclarationsFrom: methodNode. ReparseAfterSourceEditing signal ]! ! !Parser methodsFor: 'error correction' stamp: 'cwp 12/27/2012 10:14' prior: 34179326! substituteWord: correctWord wordInterval: spot offset: o "Substitute the correctSelector into the (presumed interactive) receiver. Update requestorOffset based on the delta size and answer the updated offset." cue requestor correctFrom: spot first + o to: spot last + o with: correctWord. requestorOffset := requestorOffset + correctWord size - spot size. ^o + correctWord size - spot size! ! !Parser methodsFor: 'expression types' stamp: 'cwp 12/27/2012 10:14' prior: 34179807! temporaries " [ '|' (variable)* '|' ]" | vars theActualText | (self match: #verticalBar) ifFalse: ["no temps" doitFlag ifTrue: [tempsMark := self interactive ifTrue: [cue requestor selectionInterval first] ifFalse: [1]. ^ #()]. tempsMark := hereMark "formerly --> prevMark + prevToken". tempsMark > 0 ifTrue: [theActualText := source contents. [tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]] whileTrue: [tempsMark := tempsMark + 1]]. ^ #()]. vars := OrderedCollection new. [hereType == #word] whileTrue: [vars addLast: (encoder bindTemp: self advance)]. (self match: #verticalBar) ifTrue: [tempsMark := prevMark. ^ vars]. ^ self expected: 'Vertical bar' ! ! !Parser methodsFor: 'expression types' stamp: 'cwp 12/27/2012 10:14' prior: 34180638! temporariesIn: methodSelector " [ '|' (variable)* '|' ]" | vars theActualText | (self match: #verticalBar) ifFalse: ["no temps" doitFlag ifTrue: [tempsMark := self interactive ifTrue: [cue requestor selectionInterval first] ifFalse: [1]. ^ #()]. tempsMark := hereMark "formerly --> prevMark + prevToken". tempsMark > 0 ifTrue: [theActualText := source contents. [tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]] whileTrue: [tempsMark := tempsMark + 1]]. ^ #()]. vars := OrderedCollection new. [hereType == #word] whileTrue: [vars addLast: (encoder bindTemp: self advance in: methodSelector)]. (self match: #verticalBar) ifTrue: [tempsMark := prevMark. ^ vars]. ^ self expected: 'Vertical bar'! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 10:11' prior: 53971863! compiledMethodFor: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: logFlag "Compiles the sourceStream into a parse tree, then generates code into a method, and answers it. If receiver is not nil, then the text can refer to instance variables of that receiver (the Inspector uses this). If aContext is not nil, the text can refer to temporaries in that context (the Debugger uses this). If aRequestor is not nil, then it will receive a notify:at: message before the attempt to evaluate is aborted." | methodNode method theClass | theClass := (aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class. self from: textOrStream class: theClass context: aContext notifying: aRequestor. methodNode := self translate: sourceStream noPattern: true ifFail: [^failBlock value]. method := self interactive ifTrue: [ methodNode generateWithTempNames ] ifFalse: [methodNode generate]. logFlag ifTrue: [SystemChangeNotifier uniqueInstance evaluated: sourceStream contents context: aContext]. ^method! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/27/2012 11:33' prior: 34363593! format: aStream noPattern: noPattern ifFail: failBlock ^(self parser parse: aStream cue: cue noPattern: noPattern ifFail: [^failBlock value]) preen! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/27/2012 10:08' prior: 58306325! interactive "Answer true if compilation is interactive" ^ cue requestor notNil! ! !Compiler methodsFor: 'error handling' stamp: 'cwp 12/27/2012 10:10' prior: 50779387! notify: aString at: location "Refer to the comment in Object|notify:." ^ cue requestor == nil ifTrue: [SyntaxErrorNotification inClass: cue getClass category: cue category withCode: (sourceStream contents copyReplaceFrom: location to: location - 1 with: aString) doitFlag: false errorMessage: aString location: location] ifFalse: [cue requestor notify: aString at: location in: sourceStream]! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 11:34' prior: 50777201! parse: textOrStream in: aClass notifying: req "Compile the argument, textOrStream, with respect to the class, aClass, and answer the MethodNode that is the root of the resulting parse tree. Notify the argument, req, if an error occurs. The failBlock is defaulted to an empty block." self from: textOrStream class: aClass context: nil notifying: req. ^self parser parse: sourceStream cue: cue noPattern: false ifFail: []! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 10:09' prior: 36332471! parser parser ifNil: [parser := (cue getClass ifNil: [self class]) newParser]. ^parser! ! !Compiler methodsFor: 'private' stamp: 'cwp 12/27/2012 11:37' prior: 50780779! translate: aStream noPattern: noPattern ifFail: failBlock ^self parser parse: aStream cue: cue noPattern: noPattern ifFail: [^failBlock value]! ! !Compiler methodsFor: 'public access' stamp: 'cwp 12/27/2012 11:37' prior: 19124095! translate: aStream noPattern: noPattern ifFail: failBlock parser: parser | tree | tree := parser parse: aStream cue: cue noPattern: noPattern ifFail: [^ failBlock value]. ^ tree! ! !Encoder methodsFor: 'results' stamp: 'cwp 12/27/2012 10:26' prior: 50999892! associationForClass | assoc | assoc := self environment associationAt: cue getClass name ifAbsent: [nil]. ^assoc value == cue getClass ifTrue: [assoc] ifFalse: [Association new value: cue getClass]! ! !Encoder methodsFor: 'temps' stamp: 'cwp 12/27/2012 10:25' prior: 20148386! bindTemp: name in: methodSelector "Declare a temporary; error not if a field or class variable." scopeTable at: name ifPresent:[:node| "When non-interactive raise the error only if its a duplicate" (node isTemp or:[requestor interactive]) ifTrue:[^self notify:'Name is already defined'] ifFalse:[Transcript show: '(', name, ' is shadowed in "' , cue getClass printString , '>>' , methodSelector printString , '")']]. ^self reallyBind: name! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:25' prior: 20149084! classEncoding "This is a hack so that the parser may findout what class it was parsing for when it wants to create a syntax error view." ^ cue getClass! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:39' prior: 20138819! encodeLiteral: object ^self name: object key: (cue literalScannedAs: object notifying: self) class: LiteralNode type: LdLitType set: litSet! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:40' prior: 20139010! encodeSelector: aSelector ^self name: aSelector key: aSelector class: SelectorNode type: SendType set: selectorSet! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:40' prior: 58545123! environment "Answer the environment of the current compilation context, be it in a class or global (e.g. a workspace)" ^cue environment! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 11:41' prior: 50994497! lookupInPools: varName ifFound: assocBlock ^Symbol hasInterned: varName ifTrue: [:sym| (cue bindingOf: sym) ifNil: [^false] ifNotNil: [:assoc| assocBlock value: assoc]]! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:24' prior: 51004306! possibleNamesFor: proposedName | results | results := cue getClass possibleVariablesFor: proposedName continuedFrom: nil. ^ proposedName correctAgainst: nil continuedFrom: results. ! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:24' prior: 50995012! possibleVariablesFor: proposedVariable | results | results := proposedVariable correctAgainstDictionary: scopeTable continuedFrom: nil. proposedVariable first canBeGlobalVarInitial ifTrue: [ results := cue getClass possibleVariablesFor: proposedVariable continuedFrom: results ]. ^ proposedVariable correctAgainst: nil continuedFrom: results. ! ! !Encoder methodsFor: 'encoding' stamp: 'cwp 12/27/2012 11:42' prior: 51002830! undeclared: name | sym | requestor interactive ifTrue: [requestor requestor == #error: ifTrue: [requestor error: 'Undeclared']. ^self notify: 'Undeclared']. "Allow knowlegeable clients to squash the undeclared warning if they want (e.g. Diffing pretty printers that are simply formatting text). As this breaks compilation it should only be used by clients that want to discard the result of the compilation. To squash the warning use e.g. [Compiler format: code in: class notifying: nil decorated: false] on: UndeclaredVariableWarning do: [:ex| ex resume: false]" sym := name asSymbol. ^(UndeclaredVariableWarning new name: name selector: selector class: cue getClass) signal ifTrue: [| undeclared | undeclared := cue environment undeclared. undeclared at: sym put: nil. self global: (undeclared associationAt: sym) name: sym] ifFalse: [self global: (Association key: sym) name: sym]! ! !Encoder methodsFor: 'private' stamp: 'cwp 12/27/2012 10:23' prior: 51006007! warnAboutShadowed: name requestor addWarning: name,' is shadowed'. selector ifNotNil: [Transcript cr; show: cue getClass name,'>>', selector, '(', name,' is shadowed)']! ! "Compiler"! !SmalltalkImage methodsFor: 'housekeeping' stamp: 'cwp 6/22/2012 15:56' prior: 58497062! cleanOutUndeclared globals undeclared removeUnreferencedKeys! ! !SmalltalkImage methodsFor: 'special objects' stamp: 'cwp 6/22/2012 09:01' prior: 40515090! recreateSpecialObjectsArray "Smalltalk recreateSpecialObjectsArray" "To external package developers: **** DO NOT OVERRIDE THIS METHOD. ***** If you are writing a plugin and need additional special object(s) for your own use, use addGCRoot() function and use own, separate special objects registry " "The Special Objects Array is an array of objects used by the Squeak virtual machine. Its contents are critical and accesses to it by the VM are unchecked, so don't even think of playing here unless you know what you are doing." | newArray | newArray := Array new: 56. "Nil false and true get used throughout the interpreter" newArray at: 1 put: nil. newArray at: 2 put: false. newArray at: 3 put: true. "This association holds the active process (a ProcessScheduler)" newArray at: 4 put: (self bindingOf: #Processor). "Numerous classes below used for type checking and instantiation" newArray at: 5 put: Bitmap. newArray at: 6 put: SmallInteger. newArray at: 7 put: ByteString. newArray at: 8 put: Array. newArray at: 9 put: Smalltalk. newArray at: 10 put: Float. newArray at: 11 put: MethodContext. newArray at: 12 put: BlockContext. newArray at: 13 put: Point. newArray at: 14 put: LargePositiveInteger. newArray at: 15 put: Display. newArray at: 16 put: Message. newArray at: 17 put: CompiledMethod. newArray at: 18 put: (self specialObjectsArray at: 18). "(low space Semaphore)" newArray at: 19 put: Semaphore. newArray at: 20 put: Character. newArray at: 21 put: #doesNotUnderstand:. newArray at: 22 put: #cannotReturn:. newArray at: 23 put: nil. "This is the process signalling low space." "An array of the 32 selectors that are compiled as special bytecodes, paired alternately with the number of arguments each takes." newArray at: 24 put: #( #+ 1 #- 1 #< 1 #> 1 #<= 1 #>= 1 #= 1 #~= 1 #* 1 #/ 1 #\\ 1 #@ 1 #bitShift: 1 #// 1 #bitAnd: 1 #bitOr: 1 #at: 1 #at:put: 2 #size 0 #next 0 #nextPut: 1 #atEnd 0 #== 1 #class 0 #blockCopy: 1 #value 0 #value: 1 #do: 1 #new 0 #new: 1 #x 0 #y 0 ). "An array of the 255 Characters in ascii order. Cog inlines table into machine code at: prim so do not regenerate it." newArray at: 25 put: (self specialObjectsArray at: 25). newArray at: 26 put: #mustBeBoolean. newArray at: 27 put: ByteArray. newArray at: 28 put: Process. "An array of up to 31 classes whose instances will have compact headers" newArray at: 29 put: self compactClassesArray. newArray at: 30 put: (self specialObjectsArray at: 30). "(delay Semaphore)" newArray at: 31 put: (self specialObjectsArray at: 31). "(user interrupt Semaphore)" "Entries 32 - 34 unreferenced. Previously these contained prototype instances to be copied for fast initialization" newArray at: 32 put: nil. "was (Float new: 2)" newArray at: 33 put: nil. "was (LargePositiveInteger new: 4)" newArray at: 34 put: nil. "was Point new" newArray at: 35 put: #cannotInterpret:. "Note: This must be fixed once we start using context prototypes (yeah, right)" "(MethodContext new: CompiledMethod fullFrameSize)." newArray at: 36 put: (self specialObjectsArray at: 36). "Is the prototype MethodContext (unused by the VM)" newArray at: 37 put: BlockClosure. "(BlockContext new: CompiledMethod fullFrameSize)." newArray at: 38 put: (self specialObjectsArray at: 38). "Is the prototype BlockContext (unused by the VM)" "array of objects referred to by external code" newArray at: 39 put: (self specialObjectsArray at: 39). "preserve external semaphores" newArray at: 40 put: nil. "Reserved for Mutex in Cog VMs" newArray at: 41 put: nil. "Reserved for a LinkedList instance for overlapped calls in CogMT" "finalization Semaphore" newArray at: 42 put: ((self specialObjectsArray at: 42) ifNil: [Semaphore new]). newArray at: 43 put: LargeNegativeInteger. "External objects for callout. Note: Written so that one can actually completely remove the FFI." newArray at: 44 put: (self at: #ExternalAddress ifAbsent: []). newArray at: 45 put: (self at: #ExternalStructure ifAbsent: []). newArray at: 46 put: (self at: #ExternalData ifAbsent: []). newArray at: 47 put: (self at: #ExternalFunction ifAbsent: []). newArray at: 48 put: (self at: #ExternalLibrary ifAbsent: []). newArray at: 49 put: #aboutToReturn:through:. newArray at: 50 put: #run:with:in:. "51 reserved for immutability message" "newArray at: 51 put: #attemptToAssign:withIndex:." newArray at: 52 put: #(nil "nil => generic error" #'bad receiver' #'bad argument' #'bad index' #'bad number of arguments' #'inappropriate operation' #'unsupported operation' #'no modification' #'insufficient object memory' #'insufficient C memory' #'not found' #'bad method' #'internal error in named primitive machinery' #'object may move'). "53 to 55 are for Alien" newArray at: 53 put: (self at: #Alien ifAbsent: []). newArray at: 54 put: #invokeCallback:stack:registers:jmpbuf:. newArray at: 55 put: (self at: #UnsafeAlien ifAbsent: []). "Weak reference finalization" newArray at: 56 put: (self at: #WeakFinalizationList ifAbsent: []). "Now replace the interpreter's reference in one atomic operation" self specialObjectsArray becomeForward: newArray ! ! !SmalltalkImage methodsFor: 'shrinking' stamp: 'cwp 6/22/2012 15:57' prior: 37288071! unloadAllKnownPackages "Unload all packages we know how to unload and reload" "Prepare unloading" Smalltalk zapMVCprojects. Flaps disableGlobalFlaps: false. StandardScriptingSystem removeUnreferencedPlayers. Project removeAllButCurrent. #('Morphic-UserObjects' 'EToy-UserObjects' 'Morphic-Imported' ) do: [:each | SystemOrganization removeSystemCategory: each]. Smalltalk at: #ServiceRegistry ifPresent:[:aClass| SystemChangeNotifier uniqueInstance noMoreNotificationsFor: aClass. ]. World removeAllMorphs. "Go unloading" #( 'ReleaseBuilder' 'ScriptLoader' '311Deprecated' '39Deprecated' 'Universes' 'SMLoader' 'SMBase' 'Installer-Core' 'VersionNumberTests' 'VersionNumber' 'Services-Base' 'PreferenceBrowser' 'Nebraska' 'ToolBuilder-MVC' 'ST80' 'CollectionsTests' 'GraphicsTests' 'KernelTests' 'MorphicTests' 'MultilingualTests' 'NetworkTests' 'ToolsTests' 'TraitsTests' 'SystemChangeNotification-Tests' 'FlexibleVocabularies' 'EToys' 'Protocols' 'XML-Parser' 'Tests' 'SUnitGUI' 'Help-Squeak' 'HelpSystem' 'SystemReporter' ) do: [:pkgName| (MCPackage named: pkgName) unload. MCMcmUpdater disableUpdatesOfPackage: pkgName. ]. "Traits use custom unload" Smalltalk at: #Trait ifPresent:[:aClass| aClass unloadTraits]. "Post-unload cleanup" MCWorkingCopy flushObsoletePackageInfos. SystemOrganization removeSystemCategory: 'UserObjects'. Presenter defaultPresenterClass: nil. World dumpPresenter. ScheduledControllers := nil. Preferences removePreference: #allowEtoyUserCustomEvents. SystemOrganization removeEmptyCategories. ChangeSet removeChangeSetsNamedSuchThat:[:cs | (cs == ChangeSet current) not]. globals undeclared removeUnreferencedKeys. StandardScriptingSystem initialize. MCFileBasedRepository flushAllCaches. MCDefinition clearInstances. Behavior flushObsoleteSubclasses. ChangeSet current clear. ChangeSet current name: 'Unnamed1'. Smalltalk flushClassNameCache. Smalltalk at: #Browser ifPresent:[:br| br initialize]. DebuggerMethodMap voidMapCache. DataStream initialize. AppRegistry removeObsolete. FileServices removeObsolete. Preferences removeObsolete. TheWorldMenu removeObsolete. Smalltalk garbageCollect. Symbol compactSymbolTable. TheWorldMainDockingBar updateInstances. MorphicProject defaultFill: (Color gray: 0.9). World color: (Color gray: 0.9). ! ! !InternalTranslator methodsFor: 'fileIn/fileOut' stamp: 'cwp 6/20/2012 17:34' prior: 40472775! scanFrom: aStream ^ self scanFrom: aStream environment: Environment default! ! !NaturalLanguageTranslator methodsFor: 'fileIn/fileOut' stamp: 'cwp 6/20/2012 17:27' prior: 40496770! scanFrom: aStream ^ self scanFrom: aStream environment: Environment default! ! !SystemDictionary methodsFor: 'dictionary access' stamp: 'cwp 6/22/2012 15:58' prior: 30574136! at: aKey put: anObject "Override from Dictionary to check Undeclared and fix up references to undeclared variables." | index element | (self includesKey: aKey) ifFalse: [self declare: aKey from: (self at: #Undeclared). self flushClassNameCache]. super at: aKey put: anObject. ^ anObject! ! "System"! CodeHolder subclass: #Browser instanceVariableNames: 'environment systemOrganizer classOrganizer metaClassOrganizer editSelection metaClassIndicated selectedSystemCategory selectedClassName selectedMessageName selectedMessageCategoryName' classVariableNames: 'ListClassesHierarchically RecentClasses' poolDictionaries: '' category: 'Tools-Browser'! !Browser commentStamp: 'cwp 12/27/2012 11:09' prior: 36419432! I represent a query path into the class descriptions, the software of the system.! !Browser methodsFor: 'accessing' stamp: 'cwp 6/24/2012 23:20'! selectEnvironment: anEnvironment environment := anEnvironment. systemOrganizer := environment organization! ! !Browser methodsFor: 'system category list' stamp: 'cwp 6/24/2012 23:06' prior: 36467357! From noreply at buildbot.pypy.org Fri May 17 18:58:47 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 17 May 2013 18:58:47 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changed ContextShadow printing to print temp and args as well as stack Message-ID: <20130517165847.48C6C1C2FE2@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r396:bd9f294aae93 Date: 2013-05-17 18:57 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/bd9f294aae93/ Log: changed ContextShadow printing to print temp and args as well as stack diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -965,8 +965,8 @@ def __str__(self): retval = '\nMethodContext of:' retval += self.w_method().as_string(markBytecode=self.pc() + 1) - retval += "Stackptr: %d (this is an empty ascending stack)" % (self._stack_ptr - self.tempsize()) - retval += "\nStack : " + str(self.stack()) + retval += "Stackptr: %d (this is an empty ascending stack with args and temps (%d), then stack)" % (self._stack_ptr, self.tempsize()) + retval += "\nStack : " + str(self._temps_and_stack[:self._stack_ptr]) return retval def short_str(self, argcount): From noreply at buildbot.pypy.org Sat May 18 01:41:58 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 01:41:58 +0200 (CEST) Subject: [pypy-commit] pypy default: add missing __sub__ to viewitems/keys and kill the set like methods from Message-ID: <20130517234158.24A631C02E4@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64271:32dd588a5e23 Date: 2013-05-17 16:41 -0700 http://bitbucket.org/pypy/pypy/changeset/32dd588a5e23/ Log: add missing __sub__ to viewitems/keys and kill the set like methods from viewvalues which aren't supported diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1273,6 +1273,14 @@ def descr_len(self, space): return space.len(self.w_dict) +class SetLikeDictView(object): + _mixin_ = True + + def descr_sub(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "difference_update", w_otherview) + return w_set + def descr_and(self, space, w_otherview): w_set = space.call_function(space.w_set, self) space.call_method(w_set, "intersection_update", w_otherview) @@ -1288,11 +1296,11 @@ space.call_method(w_set, "symmetric_difference_update", w_otherview) return w_set -class W_DictViewItemsObject(W_DictViewObject): +class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) -class W_DictViewKeysObject(W_DictViewObject): +class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) @@ -1306,6 +1314,7 @@ __eq__ = interp2app(W_DictViewItemsObject.descr_eq), __len__ = interp2app(W_DictViewItemsObject.descr_len), __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), __and__ = interp2app(W_DictViewItemsObject.descr_and), __or__ = interp2app(W_DictViewItemsObject.descr_or), __xor__ = interp2app(W_DictViewItemsObject.descr_xor) @@ -1317,6 +1326,7 @@ __eq__ = interp2app(W_DictViewKeysObject.descr_eq), __len__ = interp2app(W_DictViewKeysObject.descr_len), __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), __and__ = interp2app(W_DictViewKeysObject.descr_and), __or__ = interp2app(W_DictViewKeysObject.descr_or), __xor__ = interp2app(W_DictViewKeysObject.descr_xor) @@ -1328,7 +1338,4 @@ __eq__ = interp2app(W_DictViewValuesObject.descr_eq), __len__ = interp2app(W_DictViewValuesObject.descr_len), __iter__ = interp2app(W_DictViewValuesObject.descr_iter), - __and__ = interp2app(W_DictViewValuesObject.descr_and), - __or__ = interp2app(W_DictViewValuesObject.descr_or), - __xor__ = interp2app(W_DictViewValuesObject.descr_xor) ) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -774,6 +774,13 @@ assert d1.viewkeys() ^ set(d2.viewkeys()) == set('ac') assert d1.viewkeys() ^ set(d3.viewkeys()) == set('abde') + assert d1.viewkeys() - d1.viewkeys() == set() + assert d1.viewkeys() - d2.viewkeys() == set('a') + assert d1.viewkeys() - d3.viewkeys() == set('ab') + assert d1.viewkeys() - set(d1.viewkeys()) == set() + assert d1.viewkeys() - set(d2.viewkeys()) == set('a') + assert d1.viewkeys() - set(d3.viewkeys()) == set('ab') + def test_items_set_operations(self): d1 = {'a': 1, 'b': 2} d2 = {'a': 2, 'b': 2} @@ -802,6 +809,10 @@ assert (d1.viewitems() ^ d3.viewitems() == set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) + assert d1.viewitems() - d1.viewitems() == set() + assert d1.viewitems() - d2.viewitems() == set([('a', 1)]) + assert d1.viewitems() - d3.viewitems() == set([('a', 1), ('b', 2)]) + class AppTestStrategies(object): def setup_class(cls): From noreply at buildbot.pypy.org Sat May 18 04:10:52 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 18 May 2013 04:10:52 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Fix test_liststrategies. Message-ID: <20130518021052.BB74B1C02E4@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64272:ff9008f4506d Date: 2013-05-17 20:49 +0200 http://bitbucket.org/pypy/pypy/changeset/ff9008f4506d/ Log: Fix test_liststrategies. diff --git a/pypy/objspace/std/test/test_liststrategies.py b/pypy/objspace/std/test/test_liststrategies.py --- a/pypy/objspace/std/test/test_liststrategies.py +++ b/pypy/objspace/std/test/test_liststrategies.py @@ -488,15 +488,13 @@ def test_weird_rangelist_bug(self): l = make_range_list(self.space, 1, 1, 3) - from pypy.objspace.std.listobject import getslice__List_ANY_ANY # should not raise - assert getslice__List_ANY_ANY(self.space, l, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy) + assert l.descr_getslice(self.space, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy) def test_add_to_rangelist(self): l1 = make_range_list(self.space, 1, 1, 3) l2 = W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5)]) - from pypy.objspace.std.listobject import add__List_List - l3 = add__List_List(self.space, l1, l2) + l3 = l1.descr_add(self.space, l2) assert self.space.eq_w(l3, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3), self.space.wrap(4), self.space.wrap(5)])) def test_unicode(self): From noreply at buildbot.pypy.org Sat May 18 04:10:54 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 18 May 2013 04:10:54 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Remove TestW_StdObjSpace.test_multimethods_defined_on(). Message-ID: <20130518021054.1FDB91C02E4@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64273:75fc01ea9e92 Date: 2013-05-17 20:52 +0200 http://bitbucket.org/pypy/pypy/changeset/75fc01ea9e92/ Log: Remove TestW_StdObjSpace.test_multimethods_defined_on(). diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py --- a/pypy/objspace/std/test/test_stdobjspace.py +++ b/pypy/objspace/std/test/test_stdobjspace.py @@ -23,19 +23,6 @@ raises(OperationError,self.space.uint_w,self.space.wrap(None)) raises(OperationError,self.space.uint_w,self.space.wrap("")) - def test_multimethods_defined_on(self): - from pypy.objspace.std.stdtypedef import multimethods_defined_on - from pypy.objspace.std.listobject import W_ListObject - res = multimethods_defined_on(W_ListObject) - res = [(m.name, local) for (m, local) in res] - assert ('add', False) in res - assert ('lt', False) in res - assert ('setitem', False) in res - assert ('mod', False) not in res - assert ('pop', True) not in res - assert ('reverse', True) not in res - assert ('popitem', True) not in res - def test_sliceindices(self): space = self.space w_obj = space.appexec([], """(): From noreply at buildbot.pypy.org Sat May 18 12:05:38 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 18 May 2013 12:05:38 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: list.__add__ works only with lists as right operator. Message-ID: <20130518100538.723CA1C10FA@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64274:d71699519e23 Date: 2013-05-18 11:25 +0200 http://bitbucket.org/pypy/pypy/changeset/d71699519e23/ Log: list.__add__ works only with lists as right operator. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -426,6 +426,8 @@ return space.w_False def descr_add(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented w_clone = self.clone() w_clone.extend(w_list2) return w_clone From noreply at buildbot.pypy.org Sat May 18 12:05:39 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 18 May 2013 12:05:39 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Move the negate helper into the new module pypy.objspace.std.util. Message-ID: <20130518100539.BD49D1C1241@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64275:d97aaa5083b8 Date: 2013-05-18 11:44 +0200 http://bitbucket.org/pypy/pypy/changeset/d97aaa5083b8/ Log: Move the negate helper into the new module pypy.objspace.std.util. diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -4,6 +4,7 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate from rpython.rlib import rerased, jit from rpython.rlib.debug import mark_dict_non_null @@ -40,19 +41,6 @@ w_dct.length() <= UNROLL_CUTOFF) -def negate(f): - def _negator(self, space, w_other): - # no need to use space.is_ / space.not_ - tmp = f(self, space, w_other) - if tmp is space.w_NotImplemented: - return space.w_NotImplemented - elif tmp is space.w_False: - return space.w_True - else: - return space.w_False - _negator.func_name = 'negate-%s' % f.func_name - return _negator - class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/util.py @@ -0,0 +1,18 @@ +def negate(f): + """Create a function which calls `f` and negates its result. When the + result is ``space.w_NotImplemented``, ``space.w_NotImplemented`` is + returned. This is useful for complementing e.g. the __ne__ descriptor if + your type already defines a __eq__ descriptor. + """ + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator + From noreply at buildbot.pypy.org Sat May 18 12:05:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sat, 18 May 2013 12:05:41 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Test and fix for comparisons of list and non-lists. Message-ID: <20130518100541.1A2171C1260@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64276:14e9e505be43 Date: 2013-05-18 12:03 +0200 http://bitbucket.org/pypy/pypy/changeset/14e9e505be43/ Log: Test and fix for comparisons of list and non-lists. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -3,6 +3,7 @@ from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std import slicetype +from pypy.objspace.std.util import negate from pypy.interpreter.gateway import WrappedDefault, unwrap_spec, applevel,\ interp2app from pypy.interpreter import baseobjspace @@ -375,8 +376,7 @@ i += 1 return space.w_True - def descr_ne(self, space, w_other): - return space.not_(self.descr_eq(space, w_other)) + descr_ne = negate(descr_eq) def _make_list_comparison(name): import operator diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -1308,6 +1308,12 @@ def test_use_method_for_wrong_object(self): raises(TypeError, list.append.im_func, 1, 2) + def test_ne_NotImplemented(self): + class NonList(object): + pass + non_list = NonList() + assert [] != non_list + class AppTestForRangeLists(AppTestW_ListObject): spaceconfig = {"objspace.std.withrangelist": True} From noreply at buildbot.pypy.org Sat May 18 13:19:17 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 18 May 2013 13:19:17 +0200 (CEST) Subject: [pypy-commit] pypy default: (unbit) a minimal thread API Message-ID: <20130518111917.C3CD81C01CD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64277:2b93500c58ca Date: 2013-05-18 13:17 +0200 http://bitbucket.org/pypy/pypy/changeset/2b93500c58ca/ Log: (unbit) a minimal thread API diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -10,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -120,6 +122,15 @@ source = rffi.charp2str(ll_source) return _pypy_execute_source(source) + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + rthread.gc_thread_start() + w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), space.builtin_modules['__builtin__']) @@ -137,6 +148,8 @@ return 0 return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, 'pypy_setup_home': pypy_setup_home} def call_finish(space): From noreply at buildbot.pypy.org Sat May 18 13:19:19 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sat, 18 May 2013 13:19:19 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130518111919.2657E1C01CD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64278:44b4f0cf0b7d Date: 2013-05-18 13:18 +0200 http://bitbucket.org/pypy/pypy/changeset/44b4f0cf0b7d/ Log: merge diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,13 +1,14 @@ -from pypy.interpreter import gateway from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import ( + WrappedDefault, applevel, interp2app, unwrap_spec) from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef -from rpython.rlib import rerased, jit +from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null -from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint +from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize from rpython.tool.sourcetools import func_with_new_name @@ -18,7 +19,7 @@ return space.is_w(space.type(w_key), space.w_str) def _never_equal_to_string(space, w_lookup_type): - """ Handles the case of a non string key lookup. + """Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. XXX The types should provide such a flag. """ @@ -32,7 +33,7 @@ @specialize.call_location() def w_dict_unrolling_heuristic(w_dct): - """ In which cases iterating over dict items can be unrolled. + """In which cases iterating over dict items can be unrolled. Note that w_dct is an instance of W_DictMultiObject, not necesarilly an actual dict """ @@ -56,8 +57,8 @@ class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, - instance=False, strdict=False, kwargs=False): - + instance=False, strdict=False, + kwargs=False): if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None @@ -67,11 +68,9 @@ elif space.config.objspace.std.withmapdict and instance: from pypy.objspace.std.mapdict import MapDictStrategy strategy = space.fromcache(MapDictStrategy) - elif instance or strdict or module: assert w_type is None strategy = space.fromcache(StringDictStrategy) - elif kwargs: assert w_type is None from pypy.objspace.std.kwargsdict import EmptyKwargsDictStrategy @@ -92,7 +91,7 @@ self.dstorage = storage def __repr__(w_self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): @@ -105,12 +104,10 @@ def missing_method(w_dict, space, w_key): if not space.is_w(space.type(w_dict), space.w_dict): - w_missing = space.lookup(w_dict, "__missing__") - if w_missing is None: - return None - return space.get_and_call_function(w_missing, w_dict, w_key) - else: - return None + w_missing = space.lookup(w_dict, '__missing__') + if w_missing is not None: + return space.get_and_call_function(w_missing, w_dict, w_key) + return None def initialize_content(w_self, list_pairs_w): for w_k, w_v in list_pairs_w: @@ -163,7 +160,7 @@ if self.length() != w_other.length(): return space.w_False iteratorimplementation = self.iteritems() - while 1: + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break @@ -240,7 +237,8 @@ space.raise_key_error(w_key) def descr_reversed(self, space): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + raise OperationError(space.w_TypeError, space.wrap( + 'argument to reversed() must be a sequence')) def descr_copy(self, space): """D.copy() -> a shallow copy of D""" @@ -292,16 +290,13 @@ """D.clear() -> None. Remove all items from D.""" self.clear() - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_get(self, space, w_key, w_default): """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" w_value = self.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default + return w_value if w_value is not None else w_default - @gateway.unwrap_spec(defaults_w='args_w') + @unwrap_spec(defaults_w='args_w') def descr_pop(self, space, w_key, defaults_w): """D.pop(k[,d]) -> v, remove specified key and return the corresponding value\nIf key is not found, d is returned if given, @@ -332,7 +327,7 @@ space.wrap("popitem(): dictionary is empty")) return space.newtuple([w_key, w_value]) - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_setdefault(self, space, w_key, w_default): """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" return self.setdefault(w_key, w_default) @@ -364,7 +359,7 @@ _add_indirections() -app = gateway.applevel(''' +app = applevel(''' def dictrepr(currently_in_repr, d): if len(d) == 0: return "{}" @@ -400,46 +395,46 @@ d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(W_DictMultiObject.descr_new), - fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, - as_classmethod=True), + __new__ = interp2app(W_DictMultiObject.descr_new), + fromkeys = interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), __hash__ = None, - __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), - __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + __repr__ = interp2app(W_DictMultiObject.descr_repr), + __init__ = interp2app(W_DictMultiObject.descr_init), - __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), - __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), - __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), - __le__ = gateway.interp2app(W_DictMultiObject.descr_le), - __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), - __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), + __eq__ = interp2app(W_DictMultiObject.descr_eq), + __ne__ = interp2app(W_DictMultiObject.descr_ne), + __lt__ = interp2app(W_DictMultiObject.descr_lt), + __le__ = interp2app(W_DictMultiObject.descr_le), + __gt__ = interp2app(W_DictMultiObject.descr_gt), + __ge__ = interp2app(W_DictMultiObject.descr_ge), - __len__ = gateway.interp2app(W_DictMultiObject.descr_len), - __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), - __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + __len__ = interp2app(W_DictMultiObject.descr_len), + __iter__ = interp2app(W_DictMultiObject.descr_iter), + __contains__ = interp2app(W_DictMultiObject.descr_contains), - __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), - __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), - __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + __getitem__ = interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = interp2app(W_DictMultiObject.descr_delitem), - __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), - copy = gateway.interp2app(W_DictMultiObject.descr_copy), - items = gateway.interp2app(W_DictMultiObject.descr_items), - keys = gateway.interp2app(W_DictMultiObject.descr_keys), - values = gateway.interp2app(W_DictMultiObject.descr_values), - iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), - iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), - itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), - viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), - viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), - viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), - has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), - clear = gateway.interp2app(W_DictMultiObject.descr_clear), - get = gateway.interp2app(W_DictMultiObject.descr_get), - pop = gateway.interp2app(W_DictMultiObject.descr_pop), - popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), - setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), - update = gateway.interp2app(W_DictMultiObject.descr_update), + __reversed__ = interp2app(W_DictMultiObject.descr_reversed), + copy = interp2app(W_DictMultiObject.descr_copy), + items = interp2app(W_DictMultiObject.descr_items), + keys = interp2app(W_DictMultiObject.descr_keys), + values = interp2app(W_DictMultiObject.descr_values), + iteritems = interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = interp2app(W_DictMultiObject.descr_viewvalues), + has_key = interp2app(W_DictMultiObject.descr_has_key), + clear = interp2app(W_DictMultiObject.descr_clear), + get = interp2app(W_DictMultiObject.descr_get), + pop = interp2app(W_DictMultiObject.descr_pop), + popitem = interp2app(W_DictMultiObject.descr_popitem), + setdefault = interp2app(W_DictMultiObject.descr_setdefault), + update = interp2app(W_DictMultiObject.descr_update), ) @@ -453,7 +448,7 @@ def w_keys(self, w_dict): iterator = self.iterkeys(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key = iterator.next_key() if w_key is not None: result.append(w_key) @@ -463,7 +458,7 @@ def values(self, w_dict): iterator = self.itervalues(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_value = iterator.next_value() if w_value is not None: result.append(w_value) @@ -473,7 +468,7 @@ def items(self, w_dict): iterator = self.iteritems(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is not None: result.append(self.space.newtuple([w_key, w_value])) @@ -515,7 +510,7 @@ unerase = staticmethod(unerase) def get_empty_storage(self): - return self.erase(None) + return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): withidentitydict = self.space.config.objspace.std.withidentitydict @@ -618,7 +613,7 @@ # Iterator Implementation base classes def _new_next(TP): - if TP == 'key' or TP == 'value': + if TP in ('key', 'value'): EMPTY = None else: EMPTY = None, None @@ -626,10 +621,12 @@ def next(self): if self.dictimplementation is None: return EMPTY + space = self.space if self.len != self.dictimplementation.length(): self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed size during iteration")) + msg = "dictionary changed size during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + # look for the next entry if self.pos < self.len: result = getattr(self, 'next_' + TP + '_entry')() @@ -647,8 +644,8 @@ w_value = self.dictimplementation.getitem(w_key) if w_value is None: self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed during iteration")) + msg = "dictionary changed during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) return (w_key, w_value) # no more entries self.dictimplementation = None @@ -781,7 +778,8 @@ def setdefault(self, w_dict, w_key, w_default): if self.is_correct_type(w_key): - return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), + w_default) else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) @@ -821,7 +819,7 @@ space = self.space dict_w = self.unerase(w_dict.dstorage) return [space.newtuple([self.wrap(key), w_value]) - for (key, w_value) in dict_w.iteritems()] + for (key, w_value) in dict_w.iteritems()] def popitem(self, w_dict): key, value = self.unerase(w_dict.dstorage).popitem() @@ -866,9 +864,9 @@ return True def get_empty_storage(self): - new_dict = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.erase(new_dict) + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) def _never_equal_to(self, w_lookup_type): return False @@ -1068,7 +1066,7 @@ w_dict_unrolling_heuristic(w_data)) def update1_dict_dict(space, w_dict, w_data): iterator = w_data.iteritems() - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is None: break @@ -1106,16 +1104,18 @@ update1(space, w_dict, w_kwds) def characterize(space, w_a, w_b): - """ (similar to CPython) - returns the smallest key in acontent for which b's value is different or absent and this value """ + """(similar to CPython) + returns the smallest key in acontent for which b's value is + different or absent and this value""" w_smallest_diff_a_key = None w_its_value = None iteratorimplementation = w_a.iteritems() - while 1: + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break - if w_smallest_diff_a_key is None or space.is_true(space.lt(w_key, w_smallest_diff_a_key)): + if w_smallest_diff_a_key is None or space.is_true(space.lt( + w_key, w_smallest_diff_a_key)): w_bvalue = w_b.getitem(w_key) if w_bvalue is None: w_its_value = w_val @@ -1191,10 +1191,7 @@ w_clone.pos += 1 stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + w_ret = space.newtuple([new_inst, space.newtuple([w_res])]) return w_ret @@ -1224,23 +1221,23 @@ W_DictMultiIterItemsObject.typedef = StdTypeDef( "dict_iteritems", - __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), + next = interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterKeysObject.typedef = StdTypeDef( "dict_iterkeys", - __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), + next = interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterValuesObject.typedef = StdTypeDef( "dict_itervalues", - __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), + next = interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) @@ -1276,6 +1273,14 @@ def descr_len(self, space): return space.len(self.w_dict) +class SetLikeDictView(object): + _mixin_ = True + + def descr_sub(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "difference_update", w_otherview) + return w_set + def descr_and(self, space, w_otherview): w_set = space.call_function(space.w_set, self) space.call_method(w_set, "intersection_update", w_otherview) @@ -1291,11 +1296,11 @@ space.call_method(w_set, "symmetric_difference_update", w_otherview) return w_set -class W_DictViewItemsObject(W_DictViewObject): +class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) -class W_DictViewKeysObject(W_DictViewObject): +class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) @@ -1305,33 +1310,32 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", - __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewItemsObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), - __or__ = gateway.interp2app(W_DictViewItemsObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewItemsObject.descr_xor) + __repr__ = interp2app(W_DictViewItemsObject.descr_repr), + __eq__ = interp2app(W_DictViewItemsObject.descr_eq), + __len__ = interp2app(W_DictViewItemsObject.descr_len), + __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), + __and__ = interp2app(W_DictViewItemsObject.descr_and), + __or__ = interp2app(W_DictViewItemsObject.descr_or), + __xor__ = interp2app(W_DictViewItemsObject.descr_xor) ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", - __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewKeysObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), - __or__ = gateway.interp2app(W_DictViewKeysObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewKeysObject.descr_xor) + __repr__ = interp2app(W_DictViewKeysObject.descr_repr), + __eq__ = interp2app(W_DictViewKeysObject.descr_eq), + __len__ = interp2app(W_DictViewKeysObject.descr_len), + __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), + __and__ = interp2app(W_DictViewKeysObject.descr_and), + __or__ = interp2app(W_DictViewKeysObject.descr_or), + __xor__ = interp2app(W_DictViewKeysObject.descr_xor) ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", - __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewValuesObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), - __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) + __repr__ = interp2app(W_DictViewValuesObject.descr_repr), + __eq__ = interp2app(W_DictViewValuesObject.descr_eq), + __len__ = interp2app(W_DictViewValuesObject.descr_len), + __iter__ = interp2app(W_DictViewValuesObject.descr_iter), ) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -774,6 +774,13 @@ assert d1.viewkeys() ^ set(d2.viewkeys()) == set('ac') assert d1.viewkeys() ^ set(d3.viewkeys()) == set('abde') + assert d1.viewkeys() - d1.viewkeys() == set() + assert d1.viewkeys() - d2.viewkeys() == set('a') + assert d1.viewkeys() - d3.viewkeys() == set('ab') + assert d1.viewkeys() - set(d1.viewkeys()) == set() + assert d1.viewkeys() - set(d2.viewkeys()) == set('a') + assert d1.viewkeys() - set(d3.viewkeys()) == set('ab') + def test_items_set_operations(self): d1 = {'a': 1, 'b': 2} d2 = {'a': 2, 'b': 2} @@ -802,6 +809,10 @@ assert (d1.viewitems() ^ d3.viewitems() == set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) + assert d1.viewitems() - d1.viewitems() == set() + assert d1.viewitems() - d2.viewitems() == set([('a', 1)]) + assert d1.viewitems() - d3.viewitems() == set([('a', 1), ('b', 2)]) + class AppTestStrategies(object): def setup_class(cls): From noreply at buildbot.pypy.org Sat May 18 13:28:21 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 18 May 2013 13:28:21 +0200 (CEST) Subject: [pypy-commit] pypy default: Performance: copy long_to_decimal_string() from CPython. Message-ID: <20130518112821.AF14C1C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64279:af160213d701 Date: 2013-05-18 11:17 +0200 http://bitbucket.org/pypy/pypy/changeset/af160213d701/ Log: Performance: copy long_to_decimal_string() from CPython. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -447,11 +447,11 @@ @jit.elidable def repr(self): - return _format(self, BASE10, '', 'L') + return _format_decimal(self, addL=True) @jit.elidable def str(self): - return _format(self, BASE10) + return _format_decimal(self) @jit.elidable def eq(self, other): @@ -2101,6 +2101,98 @@ return ''.join(s[p:]) +DECIMAL_SHIFT = 0 # computed as max(E such that 10**E fits in a digit) +while 10 ** (DECIMAL_SHIFT + 1) <= 2 ** SHIFT: + DECIMAL_SHIFT += 1 +DECIMAL_BASE = 10 ** DECIMAL_SHIFT + +def _format_decimal(a, addL=False): + """ Optimized version of _format(a, BASE10, '', addL*'L'). """ + if a.sign == 0: + if addL: + return "0L" + else: + return "0" + + size_a = a.numdigits() + negative = a.sign < 0 + + # quick and dirty upper bound for the number of digits + # required to express a in base DECIMAL_BASE: + # + # #digits = 1 + floor(log2(a) / log2(DECIMAL_BASE)) + # + # But log2(a) < size_a * PyLong_SHIFT, and + # log2(DECIMAL_BASE) = log2(10) * DECIMAL_SHIFT + # > 3 * DECIMAL_SHIFT + + size = 1 + size_a * SHIFT // (3 * DECIMAL_SHIFT) + pout = [NULLDIGIT] * size + + # convert array of base _PyLong_BASE digits in pin to an array of + # base _PyLong_DECIMAL_BASE digits in pout, following Knuth (TAOCP, + # Volume 2 (3rd edn), section 4.4, Method 1b). + size = 0 + for i in range(size_a-1, -1, -1): + hi = a.digit(i) + for j in range(size): + z = (_widen_digit(pout[j]) << SHIFT) | hi + hi = _store_digit(z // DECIMAL_BASE) + pout[j] = _store_digit(z - _widen_digit(hi) * DECIMAL_BASE) + assert hi >= 0 + while hi: + pout[size] = hi % DECIMAL_BASE + hi //= DECIMAL_BASE + size += 1 + sizem1 = size - 1 + assert sizem1 >= 0 + + # calculate exact length of output string, and allocate + strlen = (addL + negative + + 1 + (sizem1) * DECIMAL_SHIFT) + tenpow = 10 + rem = pout[sizem1] + while rem >= tenpow: + tenpow *= 10 + strlen += 1 + + l = ['\x00'] * strlen + + p = strlen + if addL: + p -= 1; assert p >= 0 + l[p] = 'L' + + # pout[0] through pout[size-2] contribute exactly + # DECIMAL_SHIFT digits each + for i in range(sizem1): + rem = pout[i] + assert rem >= 0 + for j in range(DECIMAL_SHIFT): + p -= 1; assert p >= 0 + l[p] = chr(ord('0') + rem % 10) + rem //= 10 + + # pout[size-1]: always produce at least one decimal digit + rem = pout[sizem1] + assert rem >= 0 + while True: + p -= 1; assert p >= 0 + l[p] = chr(ord('0') + rem % 10) + if rem < 10: + break + rem //= 10 + + # and sign + if negative: + p -= 1; assert p >= 0 + l[p] = '-' + + # check we've counted correctly + assert p == 0 + return ''.join(l) + + def _bitwise(a, op, b): # '&', '|', '^' """ Bitwise and/or/xor operations """ From noreply at buildbot.pypy.org Sat May 18 13:28:23 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 18 May 2013 13:28:23 +0200 (CEST) Subject: [pypy-commit] pypy default: Build the final digits in order rather than in opposite order, Message-ID: <20130518112823.39B4A1C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64280:5de7c3413954 Date: 2013-05-18 11:41 +0200 http://bitbucket.org/pypy/pypy/changeset/5de7c3413954/ Log: Build the final digits in order rather than in opposite order, with a regular builder. Use unrolling. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -5,6 +5,7 @@ from rpython.rlib.rstring import StringBuilder from rpython.rlib.debug import make_sure_not_resized, check_regular_int from rpython.rlib.objectmodel import we_are_translated, specialize +from rpython.rlib.unroll import unrolling_iterable from rpython.rlib import jit from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper import extregistry @@ -2106,8 +2107,30 @@ DECIMAL_SHIFT += 1 DECIMAL_BASE = 10 ** DECIMAL_SHIFT +# an RPython trick: this creates a nested sequence of calls that are +# all inlined into each other, making an unrolled loop. Moreover the +# calls are done in the "wrong" order to write it as a regular loop: +# the first digit that is append-ed to the builder is the most +# significant one (corresponding to the innermost call). + at specialize.memo() +def _minus_1(x): + return x - 1 + at specialize.arg(2) +def _add_decimal_digits(builder, value, ndigits): + assert value >= 0 + if ndigits > 1: + _add_decimal_digits(builder, value // 10, _minus_1(ndigits)) + builder.append(chr(ord('0') + value % 10)) + else: + assert value < 10 + builder.append(chr(ord('0') + value)) +_add_decimal_digits._always_inline_ = True + +count_decimal_shift_from_1 = unrolling_iterable(range(1, DECIMAL_SHIFT)) + + def _format_decimal(a, addL=False): - """ Optimized version of _format(a, BASE10, '', addL*'L'). """ + """ Optimized version of _format(a, BASE10, '', 'L' if addL else ''). """ if a.sign == 0: if addL: return "0L" @@ -2148,49 +2171,41 @@ assert sizem1 >= 0 # calculate exact length of output string, and allocate + rem = pout[sizem1] + tenpow = 10 + for i in count_decimal_shift_from_1: + if rem < tenpow: + decimal_digits_in_last_part = i + break + tenpow *= 10 + else: + decimal_digits_in_last_part = DECIMAL_SHIFT strlen = (addL + negative + - 1 + (sizem1) * DECIMAL_SHIFT) - tenpow = 10 - rem = pout[sizem1] - while rem >= tenpow: - tenpow *= 10 - strlen += 1 + decimal_digits_in_last_part + (sizem1) * DECIMAL_SHIFT) - l = ['\x00'] * strlen + builder = StringBuilder(strlen) - p = strlen - if addL: - p -= 1; assert p >= 0 - l[p] = 'L' + # start with the negative sign, if needed + if negative: + builder.append('-') + + # pout[size-1]: always produce at least one decimal digit + for i in count_decimal_shift_from_1: + if i == decimal_digits_in_last_part: + _add_decimal_digits(builder, pout[sizem1], i) + break + else: + _add_decimal_digits(builder, pout[sizem1], DECIMAL_SHIFT) # pout[0] through pout[size-2] contribute exactly # DECIMAL_SHIFT digits each - for i in range(sizem1): - rem = pout[i] - assert rem >= 0 - for j in range(DECIMAL_SHIFT): - p -= 1; assert p >= 0 - l[p] = chr(ord('0') + rem % 10) - rem //= 10 + for i in range(sizem1-1, -1, -1): + _add_decimal_digits(builder, pout[i], DECIMAL_SHIFT) - # pout[size-1]: always produce at least one decimal digit - rem = pout[sizem1] - assert rem >= 0 - while True: - p -= 1; assert p >= 0 - l[p] = chr(ord('0') + rem % 10) - if rem < 10: - break - rem //= 10 - - # and sign - if negative: - p -= 1; assert p >= 0 - l[p] = '-' - - # check we've counted correctly - assert p == 0 - return ''.join(l) + # done + if addL: + builder.append('L') + return builder.build() def _bitwise(a, op, b): # '&', '|', '^' From noreply at buildbot.pypy.org Sat May 18 13:28:24 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 18 May 2013 13:28:24 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix: I suspect the previous version to create a code of size N^2, Message-ID: <20130518112824.94A061C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64281:f12e27274ff3 Date: 2013-05-18 12:19 +0200 http://bitbucket.org/pypy/pypy/changeset/f12e27274ff3/ Log: Fix: I suspect the previous version to create a code of size N^2, with N==31 or 63 diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -5,7 +5,6 @@ from rpython.rlib.rstring import StringBuilder from rpython.rlib.debug import make_sure_not_resized, check_regular_int from rpython.rlib.objectmodel import we_are_translated, specialize -from rpython.rlib.unroll import unrolling_iterable from rpython.rlib import jit from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper import extregistry @@ -2109,25 +2108,22 @@ # an RPython trick: this creates a nested sequence of calls that are # all inlined into each other, making an unrolled loop. Moreover the -# calls are done in the "wrong" order to write it as a regular loop: +# calls are done in the "wrong" order to be written as a regular loop: # the first digit that is append-ed to the builder is the most # significant one (corresponding to the innermost call). - at specialize.memo() -def _minus_1(x): - return x - 1 - at specialize.arg(2) -def _add_decimal_digits(builder, value, ndigits): +_succ = specialize.memo()(lambda n: n + 1) + at specialize.arg(3) +def _add_decimal_digits(builder, value, ndigits, digit_index=1): assert value >= 0 - if ndigits > 1: - _add_decimal_digits(builder, value // 10, _minus_1(ndigits)) + if digit_index < ndigits: + assert digit_index < DECIMAL_SHIFT + _add_decimal_digits(builder, value // 10, ndigits, _succ(digit_index)) builder.append(chr(ord('0') + value % 10)) else: assert value < 10 builder.append(chr(ord('0') + value)) _add_decimal_digits._always_inline_ = True -count_decimal_shift_from_1 = unrolling_iterable(range(1, DECIMAL_SHIFT)) - def _format_decimal(a, addL=False): """ Optimized version of _format(a, BASE10, '', 'L' if addL else ''). """ @@ -2171,15 +2167,12 @@ assert sizem1 >= 0 # calculate exact length of output string, and allocate + decimal_digits_in_last_part = 1 rem = pout[sizem1] tenpow = 10 - for i in count_decimal_shift_from_1: - if rem < tenpow: - decimal_digits_in_last_part = i - break + while rem >= tenpow: tenpow *= 10 - else: - decimal_digits_in_last_part = DECIMAL_SHIFT + decimal_digits_in_last_part += 1 strlen = (addL + negative + decimal_digits_in_last_part + (sizem1) * DECIMAL_SHIFT) @@ -2189,18 +2182,13 @@ if negative: builder.append('-') - # pout[size-1]: always produce at least one decimal digit - for i in count_decimal_shift_from_1: - if i == decimal_digits_in_last_part: - _add_decimal_digits(builder, pout[sizem1], i) - break - else: - _add_decimal_digits(builder, pout[sizem1], DECIMAL_SHIFT) - - # pout[0] through pout[size-2] contribute exactly - # DECIMAL_SHIFT digits each - for i in range(sizem1-1, -1, -1): - _add_decimal_digits(builder, pout[i], DECIMAL_SHIFT) + # pout[size-1] produces 'decimal_digits_in_last_part' digits. + # Then the remaining pout[size-2] through pout[0] contribute exactly + # DECIMAL_SHIFT digits each. + decimal_digits = decimal_digits_in_last_part + for i in range(sizem1, -1, -1): + _add_decimal_digits(builder, pout[i], decimal_digits) + decimal_digits = DECIMAL_SHIFT # done if addL: From noreply at buildbot.pypy.org Sat May 18 13:28:26 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 18 May 2013 13:28:26 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130518112826.50B161C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64282:5e25ae4de748 Date: 2013-05-18 13:31 +0200 http://bitbucket.org/pypy/pypy/changeset/5e25ae4de748/ Log: merge heads diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python 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 @@ -19,3 +19,6 @@ .. branch: numpy-subarrays Implement subarrays for numpy + +.. branch: remove-dict-smm +Remove multi-methods on dict diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -10,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -120,6 +122,15 @@ source = rffi.charp2str(ll_source) return _pypy_execute_source(source) + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + rthread.gc_thread_start() + w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), space.builtin_modules['__builtin__']) @@ -137,6 +148,8 @@ return 0 return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, 'pypy_setup_home': pypy_setup_home} def call_finish(space): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): 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 @@ -920,7 +920,7 @@ import app_main app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + [self.goal_dir] + assert sys.path == old_sys_path app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,24 +1,25 @@ -import py, sys -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.setobject import set_typedef as settypedef -from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import ( + WrappedDefault, applevel, interp2app, unwrap_spec) +from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef -from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint +from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null +from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib import rerased, jit UNROLL_CUTOFF = 5 + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) def _never_equal_to_string(space, w_lookup_type): - """ Handles the case of a non string key lookup. + """Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. XXX The types should provide such a flag. """ @@ -32,7 +33,7 @@ @specialize.call_location() def w_dict_unrolling_heuristic(w_dct): - """ In which cases iterating over dict items can be unrolled. + """In which cases iterating over dict items can be unrolled. Note that w_dct is an instance of W_DictMultiObject, not necesarilly an actual dict """ @@ -40,13 +41,24 @@ w_dct.length() <= UNROLL_CUTOFF) -class W_DictMultiObject(W_Object): - from pypy.objspace.std.dicttype import dict_typedef as typedef +def negate(f): + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator +class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, - instance=False, strdict=False, kwargs=False): - + instance=False, strdict=False, + kwargs=False): if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None @@ -56,11 +68,9 @@ elif space.config.objspace.std.withmapdict and instance: from pypy.objspace.std.mapdict import MapDictStrategy strategy = space.fromcache(MapDictStrategy) - elif instance or strdict or module: assert w_type is None strategy = space.fromcache(StringDictStrategy) - elif kwargs: assert w_type is None from pypy.objspace.std.kwargsdict import EmptyKwargsDictStrategy @@ -81,7 +91,7 @@ self.dstorage = storage def __repr__(w_self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): @@ -94,12 +104,10 @@ def missing_method(w_dict, space, w_key): if not space.is_w(space.type(w_dict), space.w_dict): - w_missing = space.lookup(w_dict, "__missing__") - if w_missing is None: - return None - return space.get_and_call_function(w_missing, w_dict, w_key) - else: - return None + w_missing = space.lookup(w_dict, '__missing__') + if w_missing is not None: + return space.get_and_call_function(w_missing, w_dict, w_key) + return None def initialize_content(w_self, list_pairs_w): for w_k, w_v in list_pairs_w: @@ -108,6 +116,228 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + @staticmethod + def descr_new(space, w_dicttype, __args__): + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + + @staticmethod + def descr_fromkeys(space, w_type, w_keys, w_fill=None): + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + + def descr_init(self, space, __args__): + init_or_update(space, self, __args__, 'dict') + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if space.is_w(self, w_other): + return space.w_True + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + + if self.length() != w_other.length(): + return space.w_False + iteratorimplementation = self.iteritems() + while True: + w_key, w_val = iteratorimplementation.next_item() + if w_key is None: + break + w_rightval = w_other.getitem(w_key) + if w_rightval is None: + return space.w_False + if not space.eq_w(w_val, w_rightval): + return space.w_False + return space.w_True + + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return self._compare_lt(space, w_other) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return w_other._compare_lt(space, self) + + def _compare_lt(self, space, w_other): + # Different sizes, no problem + if self.length() < w_other.length(): + return space.w_True + if self.length() > w_other.length(): + return space.w_False + + # Same size + w_leftdiff, w_leftval = characterize(space, self, w_other) + if w_leftdiff is None: + return space.w_False + w_rightdiff, w_rightval = characterize(space, w_other, self) + if w_rightdiff is None: + # w_leftdiff is not None, w_rightdiff is None + return space.w_True + w_res = space.lt(w_leftdiff, w_rightdiff) + if (not space.is_true(w_res) and + space.eq_w(w_leftdiff, w_rightdiff) and + w_rightval is not None): + w_res = space.lt(w_leftval, w_rightval) + return w_res + + descr_ne = negate(descr_eq) + descr_le = negate(descr_gt) + descr_ge = negate(descr_lt) + + def descr_len(self, space): + return space.wrap(self.length()) + + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_contains(self, space, w_key): + return space.newbool(self.getitem(w_key) is not None) + + def descr_getitem(self, space, w_key): + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + + w_missing_item = self.missing_method(space, w_key) + if w_missing_item is not None: + return w_missing_item + + space.raise_key_error(w_key) + + def descr_setitem(self, space, w_newkey, w_newvalue): + self.setitem(w_newkey, w_newvalue) + + def descr_delitem(self, space, w_key): + try: + self.delitem(w_key) + except KeyError: + space.raise_key_error(w_key) + + def descr_reversed(self, space): + raise OperationError(space.w_TypeError, space.wrap( + 'argument to reversed() must be a sequence')) + + def descr_copy(self, space): + """D.copy() -> a shallow copy of D""" + w_new = W_DictMultiObject.allocate_and_init_instance(space) + update1_dict_dict(space, w_new, self) + return w_new + + def descr_items(self, space): + """D.items() -> list of D's (key, value) pairs, as 2-tuples""" + return space.newlist(self.items()) + + def descr_keys(self, space): + """D.keys() -> list of D's keys""" + return self.w_keys() + + def descr_values(self, space): + """D.values() -> list of D's values""" + return space.newlist(self.values()) + + def descr_iteritems(self, space): + """D.iteritems() -> an iterator over the (key, value) items of D""" + return W_DictMultiIterItemsObject(space, self.iteritems()) + + def descr_iterkeys(self, space): + """D.iterkeys() -> an iterator over the keys of D""" + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_itervalues(self, space): + """D.itervalues() -> an iterator over the values of D""" + return W_DictMultiIterValuesObject(space, self.itervalues()) + + def descr_viewitems(self, space): + """D.viewitems() -> a set-like object providing a view on D's items""" + return W_DictViewItemsObject(space, self) + + def descr_viewkeys(self, space): + """D.viewkeys() -> a set-like object providing a view on D's keys""" + return W_DictViewKeysObject(space, self) + + def descr_viewvalues(self, space): + """D.viewvalues() -> an object providing a view on D's values""" + return W_DictViewValuesObject(space, self) + + def descr_has_key(self, space, w_key): + """D.has_key(k) -> True if D has a key k, else False""" + return space.newbool(self.getitem(w_key) is not None) + + def descr_clear(self, space): + """D.clear() -> None. Remove all items from D.""" + self.clear() + + @unwrap_spec(w_default=WrappedDefault(None)) + def descr_get(self, space, w_key, w_default): + """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" + w_value = self.getitem(w_key) + return w_value if w_value is not None else w_default + + @unwrap_spec(defaults_w='args_w') + def descr_pop(self, space, w_key, defaults_w): + """D.pop(k[,d]) -> v, remove specified key and return the + corresponding value\nIf key is not found, d is returned if given, + otherwise KeyError is raised + """ + len_defaults = len(defaults_w) + if len_defaults > 1: + raise operationerrfmt(space.w_TypeError, + "pop expected at most 2 arguments, got %d", + 1 + len_defaults) + w_item = self.getitem(w_key) + if w_item is None: + if len_defaults > 0: + return defaults_w[0] + else: + space.raise_key_error(w_key) + else: + self.delitem(w_key) + return w_item + + def descr_popitem(self, space): + """D.popitem() -> (k, v), remove and return some (key, value) pair as + a\n2-tuple; but raise KeyError if D is empty""" + try: + w_key, w_value = self.popitem() + except KeyError: + raise OperationError(space.w_KeyError, + space.wrap("popitem(): dictionary is empty")) + return space.newtuple([w_key, w_value]) + + @unwrap_spec(w_default=WrappedDefault(None)) + def descr_setdefault(self, space, w_key, w_default): + """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" + return self.setdefault(w_key, w_default) + + def descr_update(self, space, __args__): + """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] + = E[k]\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in + F: D[k] = F[k]""" + init_or_update(space, self, __args__, 'dict.update') + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -128,8 +358,87 @@ _add_indirections() + +app = applevel(''' + def dictrepr(currently_in_repr, d): + if len(d) == 0: + return "{}" + dict_id = id(d) + if dict_id in currently_in_repr: + return '{...}' + currently_in_repr[dict_id] = 1 + try: + items = [] + # XXX for now, we cannot use iteritems() at app-level because + # we want a reasonable result instead of a RuntimeError + # even if the dict is mutated by the repr() in the loop. + for k, v in dict.items(d): + items.append(repr(k) + ": " + repr(v)) + return "{" + ', '.join(items) + "}" + finally: + try: + del currently_in_repr[dict_id] + except: + pass +''', filename=__file__) + +dictrepr = app.interphook("dictrepr") + + +W_DictMultiObject.typedef = StdTypeDef("dict", + __doc__ = '''dict() -> new empty dictionary. +dict(mapping) -> new dictionary initialized from a mapping object\'s + (key, value) pairs. +dict(seq) -> new dictionary initialized as if via: + d = {} + for k, v in seq: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)''', + __new__ = interp2app(W_DictMultiObject.descr_new), + fromkeys = interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), + __hash__ = None, + __repr__ = interp2app(W_DictMultiObject.descr_repr), + __init__ = interp2app(W_DictMultiObject.descr_init), + + __eq__ = interp2app(W_DictMultiObject.descr_eq), + __ne__ = interp2app(W_DictMultiObject.descr_ne), + __lt__ = interp2app(W_DictMultiObject.descr_lt), + __le__ = interp2app(W_DictMultiObject.descr_le), + __gt__ = interp2app(W_DictMultiObject.descr_gt), + __ge__ = interp2app(W_DictMultiObject.descr_ge), + + __len__ = interp2app(W_DictMultiObject.descr_len), + __iter__ = interp2app(W_DictMultiObject.descr_iter), + __contains__ = interp2app(W_DictMultiObject.descr_contains), + + __getitem__ = interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = interp2app(W_DictMultiObject.descr_delitem), + + __reversed__ = interp2app(W_DictMultiObject.descr_reversed), + copy = interp2app(W_DictMultiObject.descr_copy), + items = interp2app(W_DictMultiObject.descr_items), + keys = interp2app(W_DictMultiObject.descr_keys), + values = interp2app(W_DictMultiObject.descr_values), + iteritems = interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = interp2app(W_DictMultiObject.descr_viewvalues), + has_key = interp2app(W_DictMultiObject.descr_has_key), + clear = interp2app(W_DictMultiObject.descr_clear), + get = interp2app(W_DictMultiObject.descr_get), + pop = interp2app(W_DictMultiObject.descr_pop), + popitem = interp2app(W_DictMultiObject.descr_popitem), + setdefault = interp2app(W_DictMultiObject.descr_setdefault), + update = interp2app(W_DictMultiObject.descr_update), + ) + + class DictStrategy(object): - def __init__(self, space): self.space = space @@ -139,7 +448,7 @@ def w_keys(self, w_dict): iterator = self.iterkeys(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key = iterator.next_key() if w_key is not None: result.append(w_key) @@ -149,7 +458,7 @@ def values(self, w_dict): iterator = self.itervalues(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_value = iterator.next_value() if w_value is not None: result.append(w_value) @@ -159,7 +468,7 @@ def items(self, w_dict): iterator = self.iteritems(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is not None: result.append(self.space.newtuple([w_key, w_value])) @@ -171,7 +480,6 @@ # it ends up taking n**2 time, because the next() calls below # will take longer and longer. But all interesting strategies # provide a better one. - space = self.space iterator = self.iteritems(w_dict) w_key, w_value = iterator.next_item() self.delitem(w_dict, w_key) @@ -195,14 +503,14 @@ def view_as_kwargs(self, w_dict): return (None, None) + class EmptyDictStrategy(DictStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) def get_empty_storage(self): - return self.erase(None) + return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): withidentitydict = self.space.config.objspace.std.withidentitydict @@ -301,21 +609,24 @@ def getiteritems(self, w_dict): return iter([(None, None)]) + # Iterator Implementation base classes def _new_next(TP): - if TP == 'key' or TP == 'value': + if TP in ('key', 'value'): EMPTY = None else: EMPTY = None, None - + def next(self): if self.dictimplementation is None: return EMPTY + space = self.space if self.len != self.dictimplementation.length(): self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed size during iteration")) + msg = "dictionary changed size during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + # look for the next entry if self.pos < self.len: result = getattr(self, 'next_' + TP + '_entry')() @@ -333,8 +644,8 @@ w_value = self.dictimplementation.getitem(w_key) if w_value is None: self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed during iteration")) + msg = "dictionary changed during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) return (w_key, w_value) # no more entries self.dictimplementation = None @@ -372,7 +683,7 @@ wrapvalue = lambda space, key : key else: wrapvalue = dictimpl.wrapvalue.im_func - + class IterClassKeys(BaseKeyIterator): def __init__(self, space, strategy, impl): self.iterator = strategy.getiterkeys(impl) @@ -424,11 +735,6 @@ create_iterator_classes(EmptyDictStrategy) -registerimplementation(W_DictMultiObject) - -# DictImplementation lattice -# XXX fix me - # concrete subclasses of the above @@ -472,7 +778,8 @@ def setdefault(self, w_dict, w_key, w_default): if self.is_correct_type(w_key): - return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), + w_default) else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) @@ -512,7 +819,7 @@ space = self.space dict_w = self.unerase(w_dict.dstorage) return [space.newtuple([self.wrap(key), w_value]) - for (key, w_value) in dict_w.iteritems()] + for (key, w_value) in dict_w.iteritems()] def popitem(self, w_dict): key, value = self.unerase(w_dict.dstorage).popitem() @@ -543,7 +850,6 @@ class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -558,9 +864,9 @@ return True def get_empty_storage(self): - new_dict = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.erase(new_dict) + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) def _never_equal_to(self, w_lookup_type): return False @@ -576,8 +882,8 @@ create_iterator_classes(ObjectDictStrategy) + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -642,7 +948,6 @@ class UnicodeDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("unicode") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -744,9 +1049,6 @@ create_iterator_classes(IntDictStrategy) -init_signature = Signature(['seq_or_map'], None, 'kwargs') -init_defaults = [None] - def update1(space, w_dict, w_data): if space.findattr(w_data, space.wrap("keys")) is None: @@ -764,7 +1066,7 @@ w_dict_unrolling_heuristic(w_data)) def update1_dict_dict(space, w_dict, w_data): iterator = w_data.iteritems() - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is None: break @@ -788,6 +1090,9 @@ w_dict.setitem(w_key, w_value) +init_signature = Signature(['seq_or_map'], None, 'kwargs') +init_defaults = [None] + def init_or_update(space, w_dict, __args__, funcname): w_src, w_kwds = __args__.parse_obj( None, funcname, @@ -798,72 +1103,19 @@ if space.is_true(w_kwds): update1(space, w_dict, w_kwds) -def init__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict') - -def dict_update__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict.update') - -def getitem__DictMulti_ANY(space, w_dict, w_key): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - - w_missing_item = w_dict.missing_method(space, w_key) - if w_missing_item is not None: - return w_missing_item - - space.raise_key_error(w_key) - -def setitem__DictMulti_ANY_ANY(space, w_dict, w_newkey, w_newvalue): - w_dict.setitem(w_newkey, w_newvalue) - -def delitem__DictMulti_ANY(space, w_dict, w_key): - try: - w_dict.delitem(w_key) - except KeyError: - space.raise_key_error(w_key) - -def len__DictMulti(space, w_dict): - return space.wrap(w_dict.length()) - -def contains__DictMulti_ANY(space, w_dict, w_key): - return space.newbool(w_dict.getitem(w_key) is not None) - -dict_has_key__DictMulti_ANY = contains__DictMulti_ANY - -def iter__DictMulti(space, w_dict): - return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) - -def eq__DictMulti_DictMulti(space, w_left, w_right): - if space.is_w(w_left, w_right): - return space.w_True - - if w_left.length() != w_right.length(): - return space.w_False - iteratorimplementation = w_left.iteritems() - while 1: +def characterize(space, w_a, w_b): + """(similar to CPython) + returns the smallest key in acontent for which b's value is + different or absent and this value""" + w_smallest_diff_a_key = None + w_its_value = None + iteratorimplementation = w_a.iteritems() + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break - w_rightval = w_right.getitem(w_key) - if w_rightval is None: - return space.w_False - if not space.eq_w(w_val, w_rightval): - return space.w_False - return space.w_True - -def characterize(space, w_a, w_b): - """ (similar to CPython) - returns the smallest key in acontent for which b's value is different or absent and this value """ - w_smallest_diff_a_key = None - w_its_value = None - iteratorimplementation = w_a.iteritems() - while 1: - w_key, w_val = iteratorimplementation.next_item() - if w_key is None: - break - if w_smallest_diff_a_key is None or space.is_true(space.lt(w_key, w_smallest_diff_a_key)): + if w_smallest_diff_a_key is None or space.is_true(space.lt( + w_key, w_smallest_diff_a_key)): w_bvalue = w_b.getitem(w_key) if w_bvalue is None: w_its_value = w_val @@ -874,105 +1126,11 @@ w_smallest_diff_a_key = w_key return w_smallest_diff_a_key, w_its_value -def lt__DictMulti_DictMulti(space, w_left, w_right): - # Different sizes, no problem - if w_left.length() < w_right.length(): - return space.w_True - if w_left.length() > w_right.length(): - return space.w_False - - # Same size - w_leftdiff, w_leftval = characterize(space, w_left, w_right) - if w_leftdiff is None: - return space.w_False - w_rightdiff, w_rightval = characterize(space, w_right, w_left) - if w_rightdiff is None: - # w_leftdiff is not None, w_rightdiff is None - return space.w_True - w_res = space.lt(w_leftdiff, w_rightdiff) - if (not space.is_true(w_res) and - space.eq_w(w_leftdiff, w_rightdiff) and - w_rightval is not None): - w_res = space.lt(w_leftval, w_rightval) - return w_res - -def dict_copy__DictMulti(space, w_self): - w_new = W_DictMultiObject.allocate_and_init_instance(space) - update1_dict_dict(space, w_new, w_self) - return w_new - -def dict_items__DictMulti(space, w_self): - return space.newlist(w_self.items()) - -def dict_keys__DictMulti(space, w_self): - return w_self.w_keys() - -def dict_values__DictMulti(space, w_self): - return space.newlist(w_self.values()) - -def dict_iteritems__DictMulti(space, w_self): - return W_DictMultiIterItemsObject(space, w_self.iteritems()) - -def dict_iterkeys__DictMulti(space, w_self): - return W_DictMultiIterKeysObject(space, w_self.iterkeys()) - -def dict_itervalues__DictMulti(space, w_self): - return W_DictMultiIterValuesObject(space, w_self.itervalues()) - -def dict_viewitems__DictMulti(space, w_self): - return W_DictViewItemsObject(space, w_self) - -def dict_viewkeys__DictMulti(space, w_self): - return W_DictViewKeysObject(space, w_self) - -def dict_viewvalues__DictMulti(space, w_self): - return W_DictViewValuesObject(space, w_self) - -def dict_clear__DictMulti(space, w_self): - w_self.clear() - -def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default - -def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - return w_dict.setdefault(w_key, w_default) - -def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w): - len_defaults = len(defaults_w) - if len_defaults > 1: - raise operationerrfmt(space.w_TypeError, - "pop expected at most 2 arguments, got %d", - 1 + len_defaults) - w_item = w_dict.getitem(w_key) - if w_item is None: - if len_defaults > 0: - return defaults_w[0] - else: - space.raise_key_error(w_key) - else: - w_dict.delitem(w_key) - return w_item - -def dict_popitem__DictMulti(space, w_dict): - try: - w_key, w_value = w_dict.popitem() - except KeyError: - raise OperationError(space.w_KeyError, - space.wrap("popitem(): dictionary is empty")) - return space.newtuple([w_key, w_value]) - # ____________________________________________________________ # Iteration - -class W_BaseDictMultiIterObject(W_Object): - from pypy.objspace.std.dicttype import dictiter_typedef as typedef - +class W_BaseDictMultiIterObject(W_Root): _immutable_fields_ = ["iteratorimplementation"] ignore_for_isinstance_cache = True @@ -981,139 +1139,203 @@ w_self.space = space w_self.iteratorimplementation = iteratorimplementation + def descr_iter(self, space): + return self + + def descr_length_hint(self, space): + return space.wrap(self.iteratorimplementation.length()) + + def descr_reduce(self, space): + """ + This is a slightly special case of pickling. + Since iteration over a dict is a bit hairy, + we do the following: + - create a clone of the dict iterator + - run it to the original position + - collect all remaining elements into a list + At unpickling time, we just use that list + and create an iterator on it. + This is of course not the standard way. + + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('dictiter_surrogate_new') + w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) + + raise OperationError( + space.w_TypeError, + space.wrap("can't pickle dictionary-keyiterator objects")) + # XXXXXX get that working again + + # we cannot call __init__ since we don't have the original dict + if isinstance(self, W_DictIter_Keys): + w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) + elif isinstance(self, W_DictIter_Values): + w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) + elif isinstance(self, W_DictIter_Items): + w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + else: + msg = "unsupported dictiter type '%s' during pickling" % (self,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_clone.space = space + w_clone.content = self.content + w_clone.len = self.len + w_clone.pos = 0 + w_clone.setup_iterator() + # spool until we have the same pos + while w_clone.pos < self.pos: + w_obj = w_clone.next_entry() + w_clone.pos += 1 + stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] + w_res = space.newlist(stuff) + w_ret = space.newtuple([new_inst, space.newtuple([w_res])]) + return w_ret + + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key = iteratorimplementation.next_key() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterValuesObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_value = iteratorimplementation.next_value() + if w_value is not None: + return w_value + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterItemsObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key, w_value = iteratorimplementation.next_item() + if w_key is not None: + return space.newtuple([w_key, w_value]) + raise OperationError(space.w_StopIteration, space.w_None) -registerimplementation(W_DictMultiIterKeysObject) -registerimplementation(W_DictMultiIterValuesObject) -registerimplementation(W_DictMultiIterItemsObject) +W_DictMultiIterItemsObject.typedef = StdTypeDef( + "dict_iteritems", + __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), + next = interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterKeysObject(space, w_dictiter): - return w_dictiter +W_DictMultiIterKeysObject.typedef = StdTypeDef( + "dict_iterkeys", + __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), + next = interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def next__DictMultiIterKeysObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key = iteratorimplementation.next_key() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) +W_DictMultiIterValuesObject.typedef = StdTypeDef( + "dict_itervalues", + __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), + next = interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterValuesObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterValuesObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_value = iteratorimplementation.next_value() - if w_value is not None: - return w_value - raise OperationError(space.w_StopIteration, space.w_None) - -def iter__DictMultiIterItemsObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterItemsObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key, w_value = iteratorimplementation.next_item() - if w_key is not None: - return space.newtuple([w_key, w_value]) - raise OperationError(space.w_StopIteration, space.w_None) # ____________________________________________________________ # Views -class W_DictViewObject(W_Object): +class W_DictViewObject(W_Root): def __init__(w_self, space, w_dict): w_self.w_dict = w_dict -class W_DictViewKeysObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_keys_typedef as typedef -registerimplementation(W_DictViewKeysObject) + def descr_repr(self, space): + w_seq = space.call_function(space.w_list, self) + w_repr = space.repr(w_seq) + return space.wrap("%s(%s)" % (space.type(self).getname(space), + space.str_w(w_repr))) -class W_DictViewItemsObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_items_typedef as typedef -registerimplementation(W_DictViewItemsObject) + def descr_eq(self, space, w_otherview): + if not space.eq_w(space.len(self), space.len(w_otherview)): + return space.w_False + + w_iter = space.iter(self) + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if not space.is_true(space.contains(w_otherview, w_item)): + return space.w_False + return space.w_True + + def descr_len(self, space): + return space.len(self.w_dict) + +class SetLikeDictView(object): + _mixin_ = True + + def descr_sub(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "difference_update", w_otherview) + return w_set + + def descr_and(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "intersection_update", w_otherview) + return w_set + + def descr_or(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "update", w_otherview) + return w_set + + def descr_xor(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "symmetric_difference_update", w_otherview) + return w_set + +class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): + def descr_iter(self, space): + return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) + +class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView): + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) class W_DictViewValuesObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_values_typedef as typedef -registerimplementation(W_DictViewValuesObject) + def descr_iter(self, space): + return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) -def len__DictViewKeys(space, w_dictview): - return space.len(w_dictview.w_dict) -len__DictViewItems = len__DictViewValues = len__DictViewKeys +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + __repr__ = interp2app(W_DictViewItemsObject.descr_repr), + __eq__ = interp2app(W_DictViewItemsObject.descr_eq), + __len__ = interp2app(W_DictViewItemsObject.descr_len), + __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), + __and__ = interp2app(W_DictViewItemsObject.descr_and), + __or__ = interp2app(W_DictViewItemsObject.descr_or), + __xor__ = interp2app(W_DictViewItemsObject.descr_xor) + ) -def iter__DictViewKeys(space, w_dictview): - return dict_iterkeys__DictMulti(space, w_dictview.w_dict) -def iter__DictViewItems(space, w_dictview): - return dict_iteritems__DictMulti(space, w_dictview.w_dict) -def iter__DictViewValues(space, w_dictview): - return dict_itervalues__DictMulti(space, w_dictview.w_dict) +W_DictViewKeysObject.typedef = StdTypeDef( + "dict_keys", + __repr__ = interp2app(W_DictViewKeysObject.descr_repr), + __eq__ = interp2app(W_DictViewKeysObject.descr_eq), + __len__ = interp2app(W_DictViewKeysObject.descr_len), + __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), + __and__ = interp2app(W_DictViewKeysObject.descr_and), + __or__ = interp2app(W_DictViewKeysObject.descr_or), + __xor__ = interp2app(W_DictViewKeysObject.descr_xor) + ) -def all_contained_in(space, w_dictview, w_otherview): - w_iter = space.iter(w_dictview) - - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - - return space.w_True - -def eq__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - if space.eq_w(space.len(w_dictview), space.len(w_otherview)): - return all_contained_in(space, w_dictview, w_otherview) - return space.w_False -eq__DictViewKeys_settypedef = eq__DictViewKeys_DictViewKeys -eq__DictViewKeys_frozensettypedef = eq__DictViewKeys_DictViewKeys - -eq__DictViewKeys_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_settypedef = eq__DictViewItems_DictViewItems -eq__DictViewItems_frozensettypedef = eq__DictViewItems_DictViewItems - -def repr__DictViewKeys(space, w_dictview): - w_seq = space.call_function(space.w_list, w_dictview) - w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), - space.str_w(w_repr))) -repr__DictViewItems = repr__DictViewKeys -repr__DictViewValues = repr__DictViewKeys - -def and__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set -and__DictViewKeys_settypedef = and__DictViewKeys_DictViewKeys -and__DictViewItems_DictViewItems = and__DictViewKeys_DictViewKeys -and__DictViewItems_settypedef = and__DictViewKeys_DictViewKeys - -def or__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "update", w_otherview) - return w_set -or__DictViewKeys_settypedef = or__DictViewKeys_DictViewKeys -or__DictViewItems_DictViewItems = or__DictViewKeys_DictViewKeys -or__DictViewItems_settypedef = or__DictViewKeys_DictViewKeys - -def xor__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set -xor__DictViewKeys_settypedef = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_DictViewItems = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_settypedef = xor__DictViewKeys_DictViewKeys - -# ____________________________________________________________ - -from pypy.objspace.std import dicttype -register_all(vars(), dicttype) +W_DictViewValuesObject.typedef = StdTypeDef( + "dict_values", + __repr__ = interp2app(W_DictViewValuesObject.descr_repr), + __eq__ = interp2app(W_DictViewValuesObject.descr_eq), + __len__ = interp2app(W_DictViewValuesObject.descr_len), + __iter__ = interp2app(W_DictViewValuesObject.descr_iter), + ) diff --git a/pypy/objspace/std/dicttype.py b/pypy/objspace/std/dicttype.py deleted file mode 100644 --- a/pypy/objspace/std/dicttype.py +++ /dev/null @@ -1,221 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter.mixedmodule import MixedModule -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.register_all import register_all - -dict_copy = SMM('copy', 1, - doc='D.copy() -> a shallow copy of D') -dict_items = SMM('items', 1, - doc="D.items() -> list of D's (key, value) pairs, as" - ' 2-tuples') -dict_keys = SMM('keys', 1, - doc="D.keys() -> list of D's keys") -dict_values = SMM('values', 1, - doc="D.values() -> list of D's values") -dict_has_key = SMM('has_key', 2, - doc='D.has_key(k) -> True if D has a key k, else False') -dict_clear = SMM('clear', 1, - doc='D.clear() -> None. Remove all items from D.') -dict_get = SMM('get', 3, defaults=(None,), - doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' - ' to None.') -dict_pop = SMM('pop', 2, varargs_w=True, - doc='D.pop(k[,d]) -> v, remove specified key and return' - ' the corresponding value\nIf key is not found, d is' - ' returned if given, otherwise KeyError is raised') -dict_popitem = SMM('popitem', 1, - doc='D.popitem() -> (k, v), remove and return some (key,' - ' value) pair as a\n2-tuple; but raise KeyError if D' - ' is empty') -dict_setdefault = SMM('setdefault', 3, defaults=(None,), - doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' - ' if k not in D') -dict_update = SMM('update', 1, general__args__=True, - doc='D.update(E, **F) -> None. Update D from E and F:' - ' for k in E: D[k] = E[k]\n(if E has keys else: for' - ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' - ' F[k]') -dict_iteritems = SMM('iteritems', 1, - doc='D.iteritems() -> an iterator over the (key, value)' - ' items of D') -dict_iterkeys = SMM('iterkeys', 1, - doc='D.iterkeys() -> an iterator over the keys of D') -dict_itervalues = SMM('itervalues', 1, - doc='D.itervalues() -> an iterator over the values of D') -dict_viewkeys = SMM('viewkeys', 1, - doc="D.viewkeys() -> a set-like object providing a view on D's keys") -dict_viewitems = SMM('viewitems', 1, - doc="D.viewitems() -> a set-like object providing a view on D's items") -dict_viewvalues = SMM('viewvalues', 1, - doc="D.viewvalues() -> an object providing a view on D's values") -dict_reversed = SMM('__reversed__', 1) - -def dict_reversed__ANY(space, w_dict): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - -register_all(vars(), globals()) - -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - - -app = gateway.applevel(''' - def dictrepr(currently_in_repr, d): - if len(d) == 0: - return "{}" - dict_id = id(d) - if dict_id in currently_in_repr: - return '{...}' - currently_in_repr[dict_id] = 1 - try: - items = [] - # XXX for now, we cannot use iteritems() at app-level because - # we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in dict.items(d): - items.append(repr(k) + ": " + repr(v)) - return "{" + ', '.join(items) + "}" - finally: - try: - del currently_in_repr[dict_id] - except: - pass -''', filename=__file__) - -dictrepr = app.interphook("dictrepr") - - -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - -dict_typedef = StdTypeDef("dict", - __doc__ = '''dict() -> new empty dictionary. -dict(mapping) -> new dictionary initialized from a mapping object\'s - (key, value) pairs. -dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v -dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), - ) -dict_typedef.registermethods(globals()) - -# ____________________________________________________________ - -def descr_dictiter__length_hint__(space, w_self): - from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject - assert isinstance(w_self, W_BaseDictMultiIterObject) - return space.wrap(w_self.iteratorimplementation.length()) - - -def descr_dictiter__reduce__(w_self, space): - """ - This is a slightly special case of pickling. - Since iteration over a dict is a bit hairy, - we do the following: - - create a clone of the dict iterator - - run it to the original position - - collect all remaining elements into a list - At unpickling time, we just use that list - and create an iterator on it. - This is of course not the standard way. - - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) - - raise OperationError( - space.w_TypeError, - space.wrap("can't pickle dictionary-keyiterator objects")) - # XXXXXX get that working again - - # we cannot call __init__ since we don't have the original dict - if isinstance(w_self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(w_self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(w_self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) - else: - msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_clone.space = space - w_clone.content = w_self.content - w_clone.len = w_self.len - w_clone.pos = 0 - w_clone.setup_iterator() - # spool until we have the same pos - while w_clone.pos < w_self.pos: - w_obj = w_clone.next_entry() - w_clone.pos += 1 - stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] - w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) - return w_ret - -# ____________________________________________________________ - - -dictiter_typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), - __reduce__ = gateway.interp2app(descr_dictiter__reduce__), - ) - -# ____________________________________________________________ -# Dict views - -dict_keys_typedef = StdTypeDef( - "dict_keys", - ) - -dict_items_typedef = StdTypeDef( - "dict_items", - ) - -dict_values_typedef = StdTypeDef( - "dict_values", - ) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -12,6 +12,7 @@ from pypy.objspace.std.register_all import register_all from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint, intmask from pypy.objspace.std import model +from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.interpreter.special import Ellipsis from pypy.interpreter.pycode import PyCode from pypy.interpreter import gateway, unicodehelper @@ -24,7 +25,6 @@ from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.longobject import W_LongObject, newlong @@ -309,15 +309,18 @@ return space.newlist(items_w) register(TYPE_LIST, unmarshal_List) -def marshal_w__DictMulti(space, w_dict, m): +def marshal_w_dict(space, w_dict, m): + if not isinstance(w_dict, W_DictMultiObject): + raise_exception(space, "unmarshallable object") m.start(TYPE_DICT) for w_tuple in w_dict.items(): w_key, w_value = space.fixedview(w_tuple, 2) m.put_w_obj(w_key) m.put_w_obj(w_value) m.atom(TYPE_NULL) +handled_by_any.append(('dict', marshal_w_dict)) -def unmarshal_DictMulti(space, u, tc): +def unmarshal_dict(space, u, tc): # since primitive lists are not optimized and we don't know # the dict size in advance, use the dict's setitem instead # of building a list of tuples. @@ -329,7 +332,7 @@ w_value = u.get_w_obj() space.setitem(w_dic, w_key, w_value) return w_dic -register(TYPE_DICT, unmarshal_DictMulti) +register(TYPE_DICT, unmarshal_dict) def unmarshal_NULL(self, u, tc): return None diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -40,7 +40,6 @@ from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef - from pypy.objspace.std.dicttype import dict_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -81,6 +80,7 @@ # not-multimethod based types + self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -92,10 +92,6 @@ floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], listobject.W_ListObject: [], - dictmultiobject.W_DictMultiObject: [], - dictmultiobject.W_DictMultiIterKeysObject: [], - dictmultiobject.W_DictMultiIterValuesObject: [], - dictmultiobject.W_DictMultiIterItemsObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -108,9 +104,6 @@ iterobject.W_FastTupleIterObject: [], iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], - dictmultiobject.W_DictViewKeysObject: [], - dictmultiobject.W_DictViewItemsObject: [], - dictmultiobject.W_DictViewValuesObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], } @@ -333,9 +326,6 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(self, space): - raise UnwrapError('cannot unwrap %r' % self) - class UnwrapError(Exception): pass diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -253,10 +253,9 @@ def unwrap(self, w_obj): """NOT_RPYTHON""" - if isinstance(w_obj, model.W_Object): + # _____ this code is here to support testing only _____ + if isinstance(w_obj, W_Root): return w_obj.unwrap(self) - if isinstance(w_obj, W_Root): - return w_obj raise model.UnwrapError("cannot unwrap: %r" % w_obj) def newint(self, intval): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -2,8 +2,7 @@ import py from pypy.objspace.std.dictmultiobject import (W_DictMultiObject, - setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, StringDictStrategy, - ObjectDictStrategy) + StringDictStrategy, ObjectDictStrategy) class TestW_DictObject(object): @@ -409,6 +408,24 @@ assert {'a': 1 } < { 'b': 1} assert {'a': 1, 'x': 2 } < { 'b': 1, 'x': 2} + def test_other_rich_cmp(self): + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} + + assert d1 <= d2 + assert d1 <= d3 + assert not d1 <= d4 + + assert not d1 > d2 + assert not d1 > d3 + assert d1 > d4 + + assert d1 >= d2 + assert not d1 >= d3 + assert d1 >= d4 + def test_str_repr(self): assert '{}' == str({}) assert '{1: 2}' == str({1: 2}) @@ -604,6 +621,9 @@ assert d.values() == [] assert d.keys() == [] + def test_cmp_with_noncmp(self): + assert not {} > object() + class AppTest_DictMultiObject(AppTest_DictObject): def test_emptydict_unhashable(self): @@ -754,6 +774,13 @@ assert d1.viewkeys() ^ set(d2.viewkeys()) == set('ac') assert d1.viewkeys() ^ set(d3.viewkeys()) == set('abde') + assert d1.viewkeys() - d1.viewkeys() == set() + assert d1.viewkeys() - d2.viewkeys() == set('a') + assert d1.viewkeys() - d3.viewkeys() == set('ab') + assert d1.viewkeys() - set(d1.viewkeys()) == set() + assert d1.viewkeys() - set(d2.viewkeys()) == set('a') + assert d1.viewkeys() - set(d3.viewkeys()) == set('ab') + def test_items_set_operations(self): d1 = {'a': 1, 'b': 2} d2 = {'a': 2, 'b': 2} @@ -782,6 +809,10 @@ assert (d1.viewitems() ^ d3.viewitems() == set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) + assert d1.viewitems() - d1.viewitems() == set() + assert d1.viewitems() - d2.viewitems() == set([('a', 1)]) + assert d1.viewitems() - d3.viewitems() == set([('a', 1), ('b', 2)]) + class AppTestStrategies(object): def setup_class(cls): @@ -971,10 +1002,10 @@ pydict = {} for i in range(N): x = randint(-N, N) - setitem__DictMulti_ANY_ANY(self.space, d, x, i) + d.descr_setitem(self.space, x, i) pydict[x] = i for key, value in pydict.iteritems(): - assert value == getitem__DictMulti_ANY(self.space, d, key) + assert value == d.descr_getitem(self.space, key) class BaseTestRDictImplementation: From noreply at buildbot.pypy.org Sat May 18 22:32:37 2013 From: noreply at buildbot.pypy.org (stefanor) Date: Sat, 18 May 2013 22:32:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Add GNU/kFreeBSD platform description that was accidentally deleted Message-ID: <20130518203237.D47051C12F3@cobra.cs.uni-duesseldorf.de> Author: Stefano Rivera Branch: Changeset: r64285:35005b65ed35 Date: 2013-05-18 21:05 +0200 http://bitbucket.org/pypy/pypy/changeset/35005b65ed35/ Log: Add GNU/kFreeBSD platform description that was accidentally deleted diff --git a/rpython/translator/platform/freebsd.py b/rpython/translator/platform/freebsd.py --- a/rpython/translator/platform/freebsd.py +++ b/rpython/translator/platform/freebsd.py @@ -12,3 +12,9 @@ class Freebsd_64(Freebsd): shared_only = ('-fPIC',) + +class GNUkFreebsd(Freebsd): + extra_libs = ('-lrt',) + +class GNUkFreebsd_64(Freebsd_64): + extra_libs = ('-lrt',) From noreply at buildbot.pypy.org Sat May 18 22:32:39 2013 From: noreply at buildbot.pypy.org (stefanor) Date: Sat, 18 May 2013 22:32:39 +0200 (CEST) Subject: [pypy-commit] pypy default: The default compiler on GNUkFreebsd is not clang Message-ID: <20130518203239.195F21C1306@cobra.cs.uni-duesseldorf.de> Author: Stefano Rivera Branch: Changeset: r64286:be55314fd6a9 Date: 2013-05-18 21:14 +0200 http://bitbucket.org/pypy/pypy/changeset/be55314fd6a9/ Log: The default compiler on GNUkFreebsd is not clang diff --git a/rpython/translator/platform/freebsd.py b/rpython/translator/platform/freebsd.py --- a/rpython/translator/platform/freebsd.py +++ b/rpython/translator/platform/freebsd.py @@ -14,7 +14,9 @@ shared_only = ('-fPIC',) class GNUkFreebsd(Freebsd): + DEFAULT_CC = 'cc' extra_libs = ('-lrt',) class GNUkFreebsd_64(Freebsd_64): + DEFAULT_CC = 'cc' extra_libs = ('-lrt',) From noreply at buildbot.pypy.org Sat May 18 22:32:36 2013 From: noreply at buildbot.pypy.org (stefanor) Date: Sat, 18 May 2013 22:32:36 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove _detect_arm_cpu - no longer needed Message-ID: <20130518203236.8BEC31C1260@cobra.cs.uni-duesseldorf.de> Author: Stefano Rivera Branch: Changeset: r64284:265780e12b1d Date: 2013-05-18 19:46 +0200 http://bitbucket.org/pypy/pypy/changeset/265780e12b1d/ Log: Remove _detect_arm_cpu - no longer needed diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -165,10 +165,6 @@ else: data = ''.join(data) linepos = 0 - # Currently on ARM-linux we won't find any information about caches in - # cpuinfo - if _detect_arm_cpu(data): - return -1 while True: start = _findend(data, '\n' + label, linepos) if start < 0: @@ -319,11 +315,6 @@ pos += 1 return pos -def _detect_arm_cpu(data): - # check for the presence of a 'Processor' entry - p = _findend(data, 'Processor', 0) - return p >= 0 and _findend(data, 'ARMv', p) > 0 - # ---------- Darwin ---------- sysctlbyname = rffi.llexternal('sysctlbyname', diff --git a/rpython/memory/gc/test/test_env.py b/rpython/memory/gc/test/test_env.py --- a/rpython/memory/gc/test/test_env.py +++ b/rpython/memory/gc/test/test_env.py @@ -165,12 +165,3 @@ def test_estimate_best_nursery_size_linux2_arm(): result = env.get_L2cache_linux2() assert result == -1 - -def test__detect_arm(): - assert env._detect_arm_cpu("Processor : ARMv6-compatible processor rev 7 (v6l)") - assert not env._detect_arm_cpu("""\ -processor : 0 -vendor_id : GenuineIntel -cpu family : 6 -model : 37 -""") From noreply at buildbot.pypy.org Sat May 18 22:32:35 2013 From: noreply at buildbot.pypy.org (stefanor) Date: Sat, 18 May 2013 22:32:35 +0200 (CEST) Subject: [pypy-commit] pypy default: L2 cache size detection for non-x86 architectures Message-ID: <20130518203235.42F881C01D1@cobra.cs.uni-duesseldorf.de> Author: Stefano Rivera Branch: Changeset: r64283:ed146ac82e63 Date: 2013-05-18 19:45 +0200 http://bitbucket.org/pypy/pypy/changeset/ed146ac82e63/ Log: L2 cache size detection for non-x86 architectures diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -1,9 +1,10 @@ """ Utilities to get environ variables and platform-specific memory-related values. """ -import os, sys +import os, sys, platform from rpython.rlib.rarithmetic import r_uint from rpython.rlib.debug import debug_print, debug_start, debug_stop +from rpython.rlib.rstring import assert_str0 from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.lltypesystem.lloperation import llop @@ -130,7 +131,22 @@ # ---------- Linux2 ---------- -def get_L2cache_linux2(filename="/proc/cpuinfo"): +def get_L2cache_linux2(): + arch = platform.machine() + if arch.endswith('86') or arch == 'x86_64': + return get_L2cache_linux2_cpuinfo() + if arch in ('alpha', 'ppc', 'ppc64'): + return get_L2cache_linux2_cpuinfo(label='L2 cache') + if arch == 'ia64': + return get_L2cache_linux2_ia64() + if arch in ('parisc', 'parisc64'): + return get_L2cache_linux2_cpuinfo(label='D-cache') + if arch in ('sparc', 'sparc64'): + return get_L2cache_linux2_sparc() + return -1 + + +def get_L2cache_linux2_cpuinfo(filename="/proc/cpuinfo", label='cache size'): debug_start("gc-hardware") L2cache = sys.maxint try: @@ -154,7 +170,7 @@ if _detect_arm_cpu(data): return -1 while True: - start = _findend(data, '\ncache size', linepos) + start = _findend(data, '\n' + label, linepos) if start < 0: break # done linepos = _findend(data, '\n', start) @@ -194,6 +210,104 @@ "Warning: cannot find your CPU L2 cache size in /proc/cpuinfo") return -1 +def get_L2cache_linux2_sparc(): + debug_start("gc-hardware") + cpu = 0 + L2cache = sys.maxint + while True: + try: + fd = os.open('/sys/devices/system/cpu/cpu' + assert_str0(str(cpu)) + + '/l2_cache_size', os.O_RDONLY, 0644) + try: + number = int(os.read(fd, 4096)) + finally: + os.close(fd) + except OSError: + break + if number < L2cache: + L2cache = number + cpu += 1 + + debug_print("L2cache =", L2cache) + debug_stop("gc-hardware") + if L2cache < sys.maxint: + return L2cache + else: + # Print a top-level warning even in non-debug builds + llop.debug_print(lltype.Void, + "Warning: cannot find your CPU L2 cache size in " + "/sys/devices/system/cpu/cpuX/l2_cache_size") + return -1 + +def get_L2cache_linux2_ia64(): + debug_start("gc-hardware") + cpu = 0 + L2cache = sys.maxint + L3cache = sys.maxint + while True: + cpudir = '/sys/devices/system/cpu/cpu' + assert_str0(str(cpu)) + index = 0 + while True: + cachedir = cpudir + '/cache/index' + assert_str0(str(index)) + try: + fd = os.open(cachedir + '/level', os.O_RDONLY, 0644) + try: + level = int(os.read(fd, 4096)[:-1]) + finally: + os.close(fd) + except OSError: + break + if level not in (2, 3): + index += 1 + continue + try: + fd = os.open(cachedir + '/size', os.O_RDONLY, 0644) + try: + data = os.read(fd, 4096) + finally: + os.close(fd) + except OSError: + break + + end = 0 + while '0' <= data[end] <= '9': + end += 1 + if end == 0: + index += 1 + continue + if data[end] not in ('K', 'k'): # assume kilobytes for now + index += 1 + continue + + number = int(data[:end]) + number *= 1024 + + if level == 2: + if number < L2cache: + L2cache = number + if level == 3: + if number < L3cache: + L3cache = number + + index += 1 + + if index == 0: + break + cpu += 1 + + mangled = L2cache + L3cache + debug_print("L2cache =", mangled) + debug_stop("gc-hardware") + if mangled > 0: + return mangled + else: + # Print a top-level warning even in non-debug builds + llop.debug_print(lltype.Void, + "Warning: cannot find your CPU L2 & L3 cache size in " + "/sys/devices/system/cpu/cpuX/cache") + return -1 + + def _findend(data, pattern, pos): pos = data.find(pattern, pos) if pos < 0: diff --git a/rpython/memory/gc/test/test_env.py b/rpython/memory/gc/test/test_env.py --- a/rpython/memory/gc/test/test_env.py +++ b/rpython/memory/gc/test/test_env.py @@ -159,18 +159,11 @@ fpu : yes etc. """) - result = env.get_L2cache_linux2(str(filepath)) + result = env.get_L2cache_linux2_cpuinfo(str(filepath)) assert result == 3072 * 1024 def test_estimate_best_nursery_size_linux2_arm(): - filepath = udir.join('estimate_best_nursery_size_linux2') - filepath.write("""\ -Processor : ARMv6-compatible processor rev 7 (v6l) -# this is not actually from cpuinfo, but here for the test -cache size : 3072 KB -... -""") - result = env.get_L2cache_linux2(str(filepath)) + result = env.get_L2cache_linux2() assert result == -1 def test__detect_arm(): From noreply at buildbot.pypy.org Sat May 18 22:50:23 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 22:50:23 +0200 (CEST) Subject: [pypy-commit] pypy default: dictview fixes: Message-ID: <20130518205023.1796B1C01D1@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64287:4f5876e9b069 Date: 2013-05-18 13:47 -0700 http://bitbucket.org/pypy/pypy/changeset/4f5876e9b069/ Log: dictview fixes: o add missing right hand set like ops + tests o guard the comparisons w/ set like type checks o CPython viewvalues lacks __eq__ (though it likely shouldn't), kill it for now since it's tailored to SetLikeDictView/sets comparisons anyway diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -9,7 +9,7 @@ from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize -from rpython.tool.sourcetools import func_with_new_name +from rpython.tool.sourcetools import func_renamer, func_with_new_name UNROLL_CUTOFF = 5 @@ -1254,47 +1254,87 @@ return space.wrap("%s(%s)" % (space.type(self).getname(space), space.str_w(w_repr))) - def descr_eq(self, space, w_otherview): - if not space.eq_w(space.len(self), space.len(w_otherview)): - return space.w_False - - w_iter = space.iter(self) - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - return space.w_True - def descr_len(self, space): return space.len(self.w_dict) +def _all_contained_in(space, w_dictview, w_other): + w_iter = space.iter(w_dictview) + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if not space.is_true(space.contains(w_other, w_item)): + return space.w_False + return space.w_True + +def _is_set_like(w_other): + from pypy.objspace.std.setobject import W_BaseSetObject + return (isinstance(w_other, W_BaseSetObject) or + isinstance(w_other, SetLikeDictView)) + class SetLikeDictView(object): _mixin_ = True - def descr_sub(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "difference_update", w_otherview) - return w_set + def descr_eq(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) == space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False - def descr_and(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set + def descr_ne(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + return space.not_(space.eq(self, w_other)) - def descr_or(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "update", w_otherview) - return w_set + def descr_lt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) < space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False - def descr_xor(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set + def descr_le(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) <= space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_gt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) > space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def descr_ge(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) >= space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def _as_set_op(name, methname): + @func_renamer('descr_' + name) + def op(self, space, w_other): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, methname, w_other) + return w_set + @func_renamer('descr_r' + name) + def rop(self, space, w_other): + w_set = space.call_function(space.w_set, w_other) + space.call_method(w_set, methname, self) + return w_set + return op, rop + + descr_sub, descr_rsub = _as_set_op('sub', 'difference_update') + descr_and, descr_rand = _as_set_op('and', 'intersection_update') + descr_or, descr_ror = _as_set_op('or', 'update') + descr_xor, descr_rxor = _as_set_op('xor', 'symmetric_difference_update') class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): @@ -1311,31 +1351,52 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", __repr__ = interp2app(W_DictViewItemsObject.descr_repr), - __eq__ = interp2app(W_DictViewItemsObject.descr_eq), __len__ = interp2app(W_DictViewItemsObject.descr_len), __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + + __eq__ = interp2app(W_DictViewItemsObject.descr_eq), + __ne__ = interp2app(W_DictViewItemsObject.descr_ne), + __lt__ = interp2app(W_DictViewItemsObject.descr_lt), + __le__ = interp2app(W_DictViewItemsObject.descr_le), + __gt__ = interp2app(W_DictViewItemsObject.descr_gt), + __ge__ = interp2app(W_DictViewItemsObject.descr_ge), + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), + __rsub__ = interp2app(W_DictViewItemsObject.descr_rsub), __and__ = interp2app(W_DictViewItemsObject.descr_and), + __rand__ = interp2app(W_DictViewItemsObject.descr_rand), __or__ = interp2app(W_DictViewItemsObject.descr_or), - __xor__ = interp2app(W_DictViewItemsObject.descr_xor) + __ror__ = interp2app(W_DictViewItemsObject.descr_ror), + __xor__ = interp2app(W_DictViewItemsObject.descr_xor), + __rxor__ = interp2app(W_DictViewItemsObject.descr_rxor), ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", __repr__ = interp2app(W_DictViewKeysObject.descr_repr), - __eq__ = interp2app(W_DictViewKeysObject.descr_eq), __len__ = interp2app(W_DictViewKeysObject.descr_len), __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + + __eq__ = interp2app(W_DictViewKeysObject.descr_eq), + __ne__ = interp2app(W_DictViewKeysObject.descr_ne), + __lt__ = interp2app(W_DictViewKeysObject.descr_lt), + __le__ = interp2app(W_DictViewKeysObject.descr_le), + __gt__ = interp2app(W_DictViewKeysObject.descr_gt), + __ge__ = interp2app(W_DictViewKeysObject.descr_ge), + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), + __rsub__ = interp2app(W_DictViewKeysObject.descr_rsub), __and__ = interp2app(W_DictViewKeysObject.descr_and), + __rand__ = interp2app(W_DictViewKeysObject.descr_rand), __or__ = interp2app(W_DictViewKeysObject.descr_or), - __xor__ = interp2app(W_DictViewKeysObject.descr_xor) + __ror__ = interp2app(W_DictViewKeysObject.descr_ror), + __xor__ = interp2app(W_DictViewKeysObject.descr_xor), + __rxor__ = interp2app(W_DictViewKeysObject.descr_rxor), ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", __repr__ = interp2app(W_DictViewValuesObject.descr_repr), - __eq__ = interp2app(W_DictViewValuesObject.descr_eq), __len__ = interp2app(W_DictViewValuesObject.descr_len), __iter__ = interp2app(W_DictViewValuesObject.descr_iter), ) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -696,6 +696,7 @@ assert d.viewkeys() == e.viewkeys() del e["a"] assert d.viewkeys() != e.viewkeys() + assert not d.viewkeys() == 42 def test_dict_items(self): d = {1: 10, "a": "ABC"} @@ -720,6 +721,7 @@ assert d.viewitems() == e.viewitems() e["a"] = "def" assert d.viewitems() != e.viewitems() + assert not d.viewitems() == 42 def test_dict_mixed_keys_items(self): d = {(1, 1): 11, (2, 2): 22} @@ -732,6 +734,7 @@ values = d.viewvalues() assert set(values) == set([10, "ABC"]) assert len(values) == 2 + assert not values == 42 def test_dict_repr(self): d = {1: 10, "a": "ABC"} @@ -813,6 +816,109 @@ assert d1.viewitems() - d2.viewitems() == set([('a', 1)]) assert d1.viewitems() - d3.viewitems() == set([('a', 1), ('b', 2)]) + def test_keys_set_operations_any_type(self): + d = {1: u'a', 2: u'b', 3: u'c'} + assert d.viewkeys() & set([1]) == set([1]) + assert d.viewkeys() & {1: u'foo'} == set([1]) + assert d.viewkeys() & [1, 2] == set([1, 2]) + # + assert set([1]) & d.viewkeys() == set([1]) + assert {1: u'foo'} & d.viewkeys() == set([1]) + assert [1, 2] & d.viewkeys() == set([1, 2]) + # + assert d.viewkeys() - set([1]) == set([2, 3]) + assert set([1, 4]) - d.viewkeys() == set([4]) + # + assert d.viewkeys() == set([1, 2, 3]) + # XXX: The following 4 commented out are CPython 2.7 bugs + #assert set([1, 2, 3]) == d.viewkeys() + assert d.viewkeys() == frozenset(set([1, 2, 3])) + #assert frozenset(set([1, 2, 3])) == d.viewkeys() + assert not d.viewkeys() != set([1, 2, 3]) + #assert not set([1, 2, 3]) != d.viewkeys() + assert not d.viewkeys() != frozenset(set([1, 2, 3])) + #assert not frozenset(set([1, 2, 3])) != d.viewkeys() + + def test_items_set_operations_any_type(self): + d = {1: u'a', 2: u'b', 3: u'c'} + assert d.viewitems() & set([(1, u'a')]) == set([(1, u'a')]) + assert d.viewitems() & {(1, u'a'): u'foo'} == set([(1, u'a')]) + assert d.viewitems() & [(1, u'a'), (2, u'b')] == set([(1, u'a'), (2, u'b')]) + # + assert set([(1, u'a')]) & d.viewitems() == set([(1, u'a')]) + assert {(1, u'a'): u'foo'} & d.viewitems() == set([(1, u'a')]) + assert [(1, u'a'), (2, u'b')] & d.viewitems() == set([(1, u'a'), (2, u'b')]) + # + assert d.viewitems() - set([(1, u'a')]) == set([(2, u'b'), (3, u'c')]) + assert set([(1, u'a'), 4]) - d.viewitems() == set([4]) + # + assert d.viewitems() == set([(1, u'a'), (2, u'b'), (3, u'c')]) + # XXX: The following 4 commented out are CPython 2.7 bugs + #assert set([(1, u'a'), (2, u'b'), (3, u'c')]) == d.viewitems() + assert d.viewitems() == frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) + #assert frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) == d.viewitems() + assert not d.viewitems() != set([(1, u'a'), (2, u'b'), (3, u'c')]) + #assert not set([(1, u'a'), (2, u'b'), (3, u'c')]) != d.viewitems() + assert not d.viewitems() != frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) + #assert not frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) != d.viewitems() + + def test_dictviewset_unhashable_values(self): + class C: + def __eq__(self, other): + return True + d = {1: C()} + assert d.viewitems() <= d.viewitems() + + def test_compare_keys_and_items(self): + d1 = {1: 2} + d2 = {(1, 2): 'foo'} + assert d1.viewitems() == d2.viewkeys() + + def test_keys_items_contained(self): + def helper(fn): + empty = fn(dict()) + empty2 = fn(dict()) + smaller = fn({1:1, 2:2}) + larger = fn({1:1, 2:2, 3:3}) + larger2 = fn({1:1, 2:2, 3:3}) + larger3 = fn({4:1, 2:2, 3:3}) + + assert smaller < larger + assert smaller <= larger + assert larger > smaller + assert larger >= smaller + + assert not smaller >= larger + assert not smaller > larger + assert not larger <= smaller + assert not larger < smaller + + assert not smaller < larger3 + assert not smaller <= larger3 + assert not larger3 > smaller + assert not larger3 >= smaller + + # Inequality strictness + assert larger2 >= larger + assert larger2 <= larger + assert not larger2 > larger + assert not larger2 < larger + + assert larger == larger2 + assert smaller != larger + + # There is an optimization on the zero-element case. + assert empty == empty2 + assert not empty != empty2 + assert not empty == smaller + assert empty != smaller + + # With the same size, an elementwise compare happens + assert larger != larger3 + assert not larger == larger3 + + helper(lambda x: x.viewkeys()) + helper(lambda x: x.viewitems()) class AppTestStrategies(object): def setup_class(cls): From noreply at buildbot.pypy.org Sat May 18 23:14:16 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 23:14:16 +0200 (CEST) Subject: [pypy-commit] pypy default: simplify Message-ID: <20130518211416.6C1E41C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64288:3e8ddc62dedc Date: 2013-05-18 14:10 -0700 http://bitbucket.org/pypy/pypy/changeset/3e8ddc62dedc/ Log: simplify diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1259,13 +1259,7 @@ def _all_contained_in(space, w_dictview, w_other): w_iter = space.iter(w_dictview) - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break + for w_item in space.iteriterable(w_iter): if not space.is_true(space.contains(w_other, w_item)): return space.w_False return space.w_True From noreply at buildbot.pypy.org Sat May 18 23:14:18 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 23:14:18 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130518211418.0D33B1C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64289:bd92c9da8b05 Date: 2013-05-17 11:28 -0700 http://bitbucket.org/pypy/pypy/changeset/bd92c9da8b05/ Log: merge default diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python 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 @@ -19,3 +19,6 @@ .. branch: numpy-subarrays Implement subarrays for numpy + +.. branch: remove-dict-smm +Remove multi-methods on dict diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -245,6 +245,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): 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 @@ -1039,7 +1039,7 @@ import app_main app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + [self.goal_dir] + assert sys.path == old_sys_path app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,19 +1,19 @@ -import py, sys -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.setobject import set_typedef as settypedef -from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef +from rpython.rlib import rerased, jit +from rpython.rlib.debug import mark_dict_non_null from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint -from rpython.rlib.debug import mark_dict_non_null from rpython.tool.sourcetools import func_with_new_name -from rpython.rlib import rerased, jit UNROLL_CUTOFF = 5 + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) @@ -40,9 +40,20 @@ w_dct.length() <= UNROLL_CUTOFF) -class W_DictMultiObject(W_Object): - from pypy.objspace.std.dicttype import dict_typedef as typedef +def negate(f): + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator +class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, instance=False, strdict=False, kwargs=False): @@ -109,6 +120,230 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + @staticmethod + def descr_new(space, w_dicttype, __args__): + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + + @staticmethod + def descr_fromkeys(space, w_type, w_keys, w_fill=None): + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + + def descr_init(self, space, __args__): + init_or_update(space, self, __args__, 'dict') + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if space.is_w(self, w_other): + return space.w_True + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + + if self.length() != w_other.length(): + return space.w_False + iteratorimplementation = self.iteritems() + while 1: + w_key, w_val = iteratorimplementation.next_item() + if w_key is None: + break + w_rightval = w_other.getitem(w_key) + if w_rightval is None: + return space.w_False + if not space.eq_w(w_val, w_rightval): + return space.w_False + return space.w_True + + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return self._compare_lt(space, w_other) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return w_other._compare_lt(space, self) + + def _compare_lt(self, space, w_other): + # Different sizes, no problem + if self.length() < w_other.length(): + return space.w_True + if self.length() > w_other.length(): + return space.w_False + + # Same size + w_leftdiff, w_leftval = characterize(space, self, w_other) + if w_leftdiff is None: + return space.w_False + w_rightdiff, w_rightval = characterize(space, w_other, self) + if w_rightdiff is None: + # w_leftdiff is not None, w_rightdiff is None + return space.w_True + w_res = space.lt(w_leftdiff, w_rightdiff) + if (not space.is_true(w_res) and + space.eq_w(w_leftdiff, w_rightdiff) and + w_rightval is not None): + w_res = space.lt(w_leftval, w_rightval) + return w_res + + descr_ne = negate(descr_eq) + descr_le = negate(descr_gt) + descr_ge = negate(descr_lt) + + def descr_len(self, space): + return space.wrap(self.length()) + + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_contains(self, space, w_key): + return space.newbool(self.getitem(w_key) is not None) + + def descr_getitem(self, space, w_key): + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + + w_missing_item = self.missing_method(space, w_key) + if w_missing_item is not None: + return w_missing_item + + space.raise_key_error(w_key) + + def descr_setitem(self, space, w_newkey, w_newvalue): + self.setitem(w_newkey, w_newvalue) + + def descr_delitem(self, space, w_key): + try: + self.delitem(w_key) + except KeyError: + space.raise_key_error(w_key) + + def descr_reversed(self, space): + raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + + def descr_copy(self, space): + """D.copy() -> a shallow copy of D""" + w_new = W_DictMultiObject.allocate_and_init_instance(space) + update1_dict_dict(space, w_new, self) + return w_new + + def descr_items(self, space): + """D.items() -> list of D's (key, value) pairs, as 2-tuples""" + return space.newlist(self.items()) + + def descr_keys(self, space): + """D.keys() -> list of D's keys""" + return self.w_keys() + + def descr_values(self, space): + """D.values() -> list of D's values""" + return space.newlist(self.values()) + + def descr_iteritems(self, space): + """D.iteritems() -> an iterator over the (key, value) items of D""" + return W_DictMultiIterItemsObject(space, self.iteritems()) + + def descr_iterkeys(self, space): + """D.iterkeys() -> an iterator over the keys of D""" + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_itervalues(self, space): + """D.itervalues() -> an iterator over the values of D""" + return W_DictMultiIterValuesObject(space, self.itervalues()) + + def descr_viewitems(self, space): + """D.viewitems() -> a set-like object providing a view on D's items""" + return W_DictViewItemsObject(space, self) + + def descr_viewkeys(self, space): + """D.viewkeys() -> a set-like object providing a view on D's keys""" + return W_DictViewKeysObject(space, self) + + def descr_viewvalues(self, space): + """D.viewvalues() -> an object providing a view on D's values""" + return W_DictViewValuesObject(space, self) + + def descr_has_key(self, space, w_key): + """D.has_key(k) -> True if D has a key k, else False""" + return space.newbool(self.getitem(w_key) is not None) + + def descr_clear(self, space): + """D.clear() -> None. Remove all items from D.""" + self.clear() + + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_get(self, space, w_key, w_default): + """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + else: + return w_default + + @gateway.unwrap_spec(defaults_w='args_w') + def descr_pop(self, space, w_key, defaults_w): + """D.pop(k[,d]) -> v, remove specified key and return the + corresponding value\nIf key is not found, d is returned if given, + otherwise KeyError is raised + """ + len_defaults = len(defaults_w) + if len_defaults > 1: + raise operationerrfmt(space.w_TypeError, + "pop expected at most 2 arguments, got %d", + 1 + len_defaults) + w_item = self.getitem(w_key) + if w_item is None: + if len_defaults > 0: + return defaults_w[0] + else: + space.raise_key_error(w_key) + else: + self.delitem(w_key) + return w_item + + def descr_popitem(self, space): + """D.popitem() -> (k, v), remove and return some (key, value) pair as + a\n2-tuple; but raise KeyError if D is empty""" + try: + w_key, w_value = self.popitem() + except KeyError: + raise OperationError(space.w_KeyError, + space.wrap("popitem(): dictionary is empty")) + return space.newtuple([w_key, w_value]) + + @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + def descr_setdefault(self, space, w_key, w_default): + """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" + return self.setdefault(w_key, w_default) + + def descr_update(self, space, __args__): + """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] + = E[k]\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in + F: D[k] = F[k]""" + init_or_update(space, self, __args__, 'dict.update') + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -129,8 +364,87 @@ _add_indirections() + +app = gateway.applevel(''' + def dictrepr(currently_in_repr, d): + if len(d) == 0: + return "{}" + dict_id = id(d) + if dict_id in currently_in_repr: + return '{...}' + currently_in_repr[dict_id] = 1 + try: + items = [] + # XXX for now, we cannot use iteritems() at app-level because + # we want a reasonable result instead of a RuntimeError + # even if the dict is mutated by the repr() in the loop. + for k, v in dict.items(d): + items.append(repr(k) + ": " + repr(v)) + return "{" + ', '.join(items) + "}" + finally: + try: + del currently_in_repr[dict_id] + except: + pass +''', filename=__file__) + +dictrepr = app.interphook("dictrepr") + + +W_DictMultiObject.typedef = StdTypeDef("dict", + __doc__ = '''dict() -> new empty dictionary. +dict(mapping) -> new dictionary initialized from a mapping object\'s + (key, value) pairs. +dict(seq) -> new dictionary initialized as if via: + d = {} + for k, v in seq: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)''', + __new__ = gateway.interp2app(W_DictMultiObject.descr_new), + fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), + __hash__ = None, + __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), + __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + + __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), + __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), + __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), + __le__ = gateway.interp2app(W_DictMultiObject.descr_le), + __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), + __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), + + __len__ = gateway.interp2app(W_DictMultiObject.descr_len), + __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), + __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + + __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + + __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), + copy = gateway.interp2app(W_DictMultiObject.descr_copy), + items = gateway.interp2app(W_DictMultiObject.descr_items), + keys = gateway.interp2app(W_DictMultiObject.descr_keys), + values = gateway.interp2app(W_DictMultiObject.descr_values), + iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), + has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), + clear = gateway.interp2app(W_DictMultiObject.descr_clear), + get = gateway.interp2app(W_DictMultiObject.descr_get), + pop = gateway.interp2app(W_DictMultiObject.descr_pop), + popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), + setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), + update = gateway.interp2app(W_DictMultiObject.descr_update), + ) + + class DictStrategy(object): - def __init__(self, space): self.space = space @@ -172,7 +486,6 @@ # it ends up taking n**2 time, because the next() calls below # will take longer and longer. But all interesting strategies # provide a better one. - space = self.space iterator = self.iteritems(w_dict) w_key, w_value = iterator.next_item() self.delitem(w_dict, w_key) @@ -196,8 +509,8 @@ def view_as_kwargs(self, w_dict): return (None, None) + class EmptyDictStrategy(DictStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -304,6 +617,7 @@ def getiteritems(self, w_dict): return iter([(None, None)]) + # Iterator Implementation base classes def _new_next(TP): @@ -311,7 +625,7 @@ EMPTY = None else: EMPTY = None, None - + def next(self): if self.dictimplementation is None: return EMPTY @@ -375,7 +689,7 @@ wrapvalue = lambda space, key : key else: wrapvalue = dictimpl.wrapvalue.im_func - + class IterClassKeys(BaseKeyIterator): def __init__(self, space, strategy, impl): self.iterator = strategy.getiterkeys(impl) @@ -427,11 +741,6 @@ create_iterator_classes(EmptyDictStrategy) -registerimplementation(W_DictMultiObject) - -# DictImplementation lattice -# XXX fix me - # concrete subclasses of the above @@ -546,7 +855,6 @@ class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -579,8 +887,8 @@ create_iterator_classes(ObjectDictStrategy) + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -646,7 +954,6 @@ class UnicodeDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("unicode") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -748,9 +1055,6 @@ create_iterator_classes(IntDictStrategy) -init_signature = Signature(['seq_or_map'], None, 'kwargs') -init_defaults = [None] - def update1(space, w_dict, w_data): if space.findattr(w_data, space.wrap("keys")) is None: @@ -792,6 +1096,9 @@ w_dict.setitem(w_key, w_value) +init_signature = Signature(['seq_or_map'], None, 'kwargs') +init_defaults = [None] + def init_or_update(space, w_dict, __args__, funcname): w_src, w_kwds = __args__.parse_obj( None, funcname, @@ -802,131 +1109,32 @@ if space.is_true(w_kwds): update1(space, w_dict, w_kwds) -def init__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict') - -def dict_update__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict.update') - -def getitem__DictMulti_ANY(space, w_dict, w_key): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - - w_missing_item = w_dict.missing_method(space, w_key) - if w_missing_item is not None: - return w_missing_item - - space.raise_key_error(w_key) - -def setitem__DictMulti_ANY_ANY(space, w_dict, w_newkey, w_newvalue): - w_dict.setitem(w_newkey, w_newvalue) - -def delitem__DictMulti_ANY(space, w_dict, w_key): - try: - w_dict.delitem(w_key) - except KeyError: - space.raise_key_error(w_key) - -def len__DictMulti(space, w_dict): - return space.wrap(w_dict.length()) - -def contains__DictMulti_ANY(space, w_dict, w_key): - return space.newbool(w_dict.getitem(w_key) is not None) - -def iter__DictMulti(space, w_dict): - return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) - -def eq__DictMulti_DictMulti(space, w_left, w_right): - if space.is_w(w_left, w_right): - return space.w_True - - if w_left.length() != w_right.length(): - return space.w_False - iteratorimplementation = w_left.iteritems() +def characterize(space, w_a, w_b): + """ (similar to CPython) + returns the smallest key in acontent for which b's value is different or absent and this value """ + w_smallest_diff_a_key = None + w_its_value = None + iteratorimplementation = w_a.iteritems() while 1: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break - w_rightval = w_right.getitem(w_key) - if w_rightval is None: - return space.w_False - if not space.eq_w(w_val, w_rightval): - return space.w_False - return space.w_True - -def dict_copy__DictMulti(space, w_self): - w_new = W_DictMultiObject.allocate_and_init_instance(space) - update1_dict_dict(space, w_new, w_self) - return w_new - - -def dict_items__DictMulti(space, w_self): - return W_DictViewItemsObject(space, w_self) - -def dict_keys__DictMulti(space, w_self): - return W_DictViewKeysObject(space, w_self) - # XXX on default this is a fast path when keys are string, do we want to - # port it to py3k? - # return w_self.w_keys() - -def dict_values__DictMulti(space, w_self): - return W_DictViewValuesObject(space, w_self) - -def dict_iteritems__DictMulti(space, w_self): - return W_DictMultiIterItemsObject(space, w_self.iteritems()) - -def dict_iterkeys__DictMulti(space, w_self): - return W_DictMultiIterKeysObject(space, w_self.iterkeys()) - -def dict_itervalues__DictMulti(space, w_self): - return W_DictMultiIterValuesObject(space, w_self.itervalues()) - -def dict_clear__DictMulti(space, w_self): - w_self.clear() - -def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default - -def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - return w_dict.setdefault(w_key, w_default) - -def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w): - len_defaults = len(defaults_w) - if len_defaults > 1: - raise operationerrfmt(space.w_TypeError, - "pop expected at most 2 arguments, got %d", - 1 + len_defaults) - w_item = w_dict.getitem(w_key) - if w_item is None: - if len_defaults > 0: - return defaults_w[0] - else: - space.raise_key_error(w_key) - else: - w_dict.delitem(w_key) - return w_item - -def dict_popitem__DictMulti(space, w_dict): - try: - w_key, w_value = w_dict.popitem() - except KeyError: - raise OperationError(space.w_KeyError, - space.wrap("popitem(): dictionary is empty")) - return space.newtuple([w_key, w_value]) + if w_smallest_diff_a_key is None or space.is_true(space.lt(w_key, w_smallest_diff_a_key)): + w_bvalue = w_b.getitem(w_key) + if w_bvalue is None: + w_its_value = w_val + w_smallest_diff_a_key = w_key + else: + if not space.eq_w(w_val, w_bvalue): + w_its_value = w_val + w_smallest_diff_a_key = w_key + return w_smallest_diff_a_key, w_its_value # ____________________________________________________________ # Iteration - -class W_BaseDictMultiIterObject(W_Object): - from pypy.objspace.std.dicttype import dictiter_typedef as typedef - +class W_BaseDictMultiIterObject(W_Root): _immutable_fields_ = ["iteratorimplementation"] ignore_for_isinstance_cache = True @@ -935,177 +1143,199 @@ w_self.space = space w_self.iteratorimplementation = iteratorimplementation + def descr_iter(self, space): + return self + + def descr_length_hint(self, space): + return space.wrap(self.iteratorimplementation.length()) + + def descr_reduce(self, space): + """ + This is a slightly special case of pickling. + Since iteration over a dict is a bit hairy, + we do the following: + - create a clone of the dict iterator + - run it to the original position + - collect all remaining elements into a list + At unpickling time, we just use that list + and create an iterator on it. + This is of course not the standard way. + + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('dictiter_surrogate_new') + w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) + + raise OperationError( + space.w_TypeError, + space.wrap("can't pickle dictionary-keyiterator objects")) + # XXXXXX get that working again + + # we cannot call __init__ since we don't have the original dict + if isinstance(self, W_DictIter_Keys): + w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) + elif isinstance(self, W_DictIter_Values): + w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) + elif isinstance(self, W_DictIter_Items): + w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + else: + msg = "unsupported dictiter type '%s' during pickling" % (self,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_clone.space = space + w_clone.content = self.content + w_clone.len = self.len + w_clone.pos = 0 + w_clone.setup_iterator() + # spool until we have the same pos + while w_clone.pos < self.pos: + w_obj = w_clone.next_entry() + w_clone.pos += 1 + stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] + w_res = space.newlist(stuff) + tup = [ + w_res + ] + w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + return w_ret + + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key = iteratorimplementation.next_key() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterValuesObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_value = iteratorimplementation.next_value() + if w_value is not None: + return w_value + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterItemsObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key, w_value = iteratorimplementation.next_item() + if w_key is not None: + return space.newtuple([w_key, w_value]) + raise OperationError(space.w_StopIteration, space.w_None) -registerimplementation(W_DictMultiIterKeysObject) -registerimplementation(W_DictMultiIterValuesObject) -registerimplementation(W_DictMultiIterItemsObject) +W_DictMultiIterItemsObject.typedef = StdTypeDef( + "dict_iteritems", + __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterKeysObject(space, w_dictiter): - return w_dictiter +W_DictMultiIterKeysObject.typedef = StdTypeDef( + "dict_iterkeys", + __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def next__DictMultiIterKeysObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key = iteratorimplementation.next_key() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) +W_DictMultiIterValuesObject.typedef = StdTypeDef( + "dict_itervalues", + __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), + next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + ) -def iter__DictMultiIterValuesObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterValuesObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_value = iteratorimplementation.next_value() - if w_value is not None: - return w_value - raise OperationError(space.w_StopIteration, space.w_None) - -def iter__DictMultiIterItemsObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterItemsObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key, w_value = iteratorimplementation.next_item() - if w_key is not None: - return space.newtuple([w_key, w_value]) - raise OperationError(space.w_StopIteration, space.w_None) # ____________________________________________________________ # Views -class W_DictViewObject(W_Object): +class W_DictViewObject(W_Root): def __init__(w_self, space, w_dict): w_self.w_dict = w_dict -class W_DictViewKeysObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_keys_typedef as typedef -registerimplementation(W_DictViewKeysObject) + def descr_repr(self, space): + w_seq = space.call_function(space.w_list, self) + w_repr = space.repr(w_seq) + return space.wrap("%s(%s)" % (space.type(self).getname(space), + space.str_w(w_repr))) + + def descr_eq(self, space, w_otherview): + if not space.eq_w(space.len(self), space.len(w_otherview)): + return space.w_False + + w_iter = space.iter(self) + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if not space.is_true(space.contains(w_otherview, w_item)): + return space.w_False + return space.w_True + + def descr_len(self, space): + return space.len(self.w_dict) + + def descr_and(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "intersection_update", w_otherview) + return w_set + + def descr_or(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "update", w_otherview) + return w_set + + def descr_xor(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "symmetric_difference_update", w_otherview) + return w_set class W_DictViewItemsObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_items_typedef as typedef -registerimplementation(W_DictViewItemsObject) + def descr_iter(self, space): + return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) + +class W_DictViewKeysObject(W_DictViewObject): + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) class W_DictViewValuesObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_values_typedef as typedef -registerimplementation(W_DictViewValuesObject) + def descr_iter(self, space): + return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) -def len__DictViewKeys(space, w_dictview): - return space.len(w_dictview.w_dict) -len__DictViewItems = len__DictViewValues = len__DictViewKeys +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewItemsObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), + __or__ = gateway.interp2app(W_DictViewItemsObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewItemsObject.descr_xor) + ) -def iter__DictViewKeys(space, w_dictview): - return dict_iterkeys__DictMulti(space, w_dictview.w_dict) -def iter__DictViewItems(space, w_dictview): - return dict_iteritems__DictMulti(space, w_dictview.w_dict) -def iter__DictViewValues(space, w_dictview): - return dict_itervalues__DictMulti(space, w_dictview.w_dict) +W_DictViewKeysObject.typedef = StdTypeDef( + "dict_keys", + __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewKeysObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), + __or__ = gateway.interp2app(W_DictViewKeysObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewKeysObject.descr_xor) + ) -def all_contained_in(space, w_dictview, w_otherview): - w_iter = space.iter(w_dictview) - - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - - return space.w_True - -def comparison_impl(fn): - opname = fn.func_name - types = ['DictViewKeys', 'DictViewItems', 'settypedef', 'frozensettypedef'] - for lefttype in types: - for righttype in types: - fnname = '%s__%s_%s' % (opname, lefttype, righttype) - globals()[fnname] = fn - return fn - - at comparison_impl -def eq(space, w_left, w_right): - if space.eq_w(space.len(w_left), space.len(w_right)): - return all_contained_in(space, w_left, w_right) - return space.w_False - - at comparison_impl -def ne(space, w_left, w_right): - if not space.eq_w(space.len(w_left), space.len(w_right)): - return space.w_True - return space.not_(all_contained_in(space, w_left, w_right)) - - at comparison_impl -def lt(space, w_left, w_right): - if space.len_w(w_left) < space.len_w(w_right): - return all_contained_in(space, w_left, w_right) - return space.w_False - - at comparison_impl -def le(space, w_left, w_right): - if space.len_w(w_left) <= space.len_w(w_right): - return all_contained_in(space, w_left, w_right) - return space.w_False - - at comparison_impl -def gt(space, w_left, w_right): - if space.len_w(w_left) > space.len_w(w_right): - return all_contained_in(space, w_right, w_left) - return space.w_False - - at comparison_impl -def ge(space, w_left, w_right): - if space.len_w(w_left) >= space.len_w(w_right): - return all_contained_in(space, w_right, w_left) - return space.w_False - - -def repr__DictViewKeys(space, w_dictview): - typename = space.type(w_dictview).getname(space).decode('utf-8') - w_seq = space.call_function(space.w_list, w_dictview) - seq_repr = space.unicode_w(space.repr(w_seq)) - return space.wrap(u"%s(%s)" % (typename, seq_repr)) -repr__DictViewItems = repr__DictViewKeys -repr__DictViewValues = repr__DictViewKeys - - -def generate_setops(): - OPLIST = [ - ('and', 'intersection_update'), - ('or', 'update'), - ('xor', 'symmetric_difference_update'), - ('sub', 'difference_update'), - ] - - for (opname, methodname) in OPLIST: - src = py.code.Source(""" - def {opname}__DictViewKeys_ANY(space, w_dictview, w_other): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, '{methodname}', w_other) - return w_set - - def {opname}__ANY_DictViewKeys(space, w_other, w_dictview): - w_set = space.call_function(space.w_set, w_other) - space.call_method(w_set, '{methodname}', w_dictview) - return w_set - - {opname}__DictViewItems_ANY = {opname}__DictViewKeys_ANY - {opname}__ANY_DictViewItems = {opname}__ANY_DictViewKeys - """.format(opname=opname, methodname=methodname)) - exec src.compile() in globals() - -generate_setops() - -# ____________________________________________________________ - -from pypy.objspace.std import dicttype -register_all(vars(), dicttype) +W_DictViewValuesObject.typedef = StdTypeDef( + "dict_values", + __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), + __eq__ = gateway.interp2app(W_DictViewValuesObject.descr_eq), + __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), + __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), + __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), + __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), + __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) + ) diff --git a/pypy/objspace/std/dicttype.py b/pypy/objspace/std/dicttype.py deleted file mode 100644 --- a/pypy/objspace/std/dicttype.py +++ /dev/null @@ -1,243 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter.mixedmodule import MixedModule -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.register_all import register_all - -dict_copy = SMM('copy', 1, - doc='D.copy() -> a shallow copy of D') -dict_items = SMM('items', 1, - doc="D.items() -> a set-like object providing a view on D's item") -dict_keys = SMM('keys', 1, - doc="D.keys() -> a set-like object providing a view on D's keys") -dict_values = SMM('values', 1, - doc="D.values() -> an object providing a view on D's values") -dict_clear = SMM('clear', 1, - doc='D.clear() -> None. Remove all items from D.') -dict_get = SMM('get', 3, defaults=(None,), - doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' - ' to None.') -dict_pop = SMM('pop', 2, varargs_w=True, - doc='D.pop(k[,d]) -> v, remove specified key and return' - ' the corresponding value\nIf key is not found, d is' - ' returned if given, otherwise KeyError is raised') -dict_popitem = SMM('popitem', 1, - doc='D.popitem() -> (k, v), remove and return some (key,' - ' value) pair as a\n2-tuple; but raise KeyError if D' - ' is empty') -dict_setdefault = SMM('setdefault', 3, defaults=(None,), - doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' - ' if k not in D') -dict_update = SMM('update', 1, general__args__=True, - doc='D.update(E, **F) -> None. Update D from E and F:' - ' for k in E: D[k] = E[k]\n(if E has keys else: for' - ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' - ' F[k]') -dict_iteritems = SMM('iteritems', 1, - doc='D.iteritems() -> an iterator over the (key, value)' - ' items of D') -dict_iterkeys = SMM('iterkeys', 1, - doc='D.iterkeys() -> an iterator over the keys of D') -dict_itervalues = SMM('itervalues', 1, - doc='D.itervalues() -> an iterator over the values of D') -dict_reversed = SMM('__reversed__', 1) - - -def dict_reversed__ANY(space, w_dict): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - -register_all(vars(), globals()) - -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - - -app = gateway.applevel(''' - def dictrepr(currently_in_repr, d): - if len(d) == 0: - return "{}" - dict_id = id(d) - if dict_id in currently_in_repr: - return '{...}' - currently_in_repr[dict_id] = 1 - try: - items = [] - # XXX for now, we cannot use items() withut list at app-level - # because we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in list(dict.items(d)): - items.append(repr(k) + ": " + repr(v)) - return "{" + ', '.join(items) + "}" - finally: - try: - del currently_in_repr[dict_id] - except: - pass -''', filename=__file__) - -dictrepr = app.interphook("dictrepr") - - -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - -dict_typedef = StdTypeDef("dict", - __doc__ = '''dict() -> new empty dictionary. -dict(mapping) -> new dictionary initialized from a mapping object\'s - (key, value) pairs. -dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v -dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), - ) -dict_typedef.registermethods(globals()) - -# ____________________________________________________________ - -def descr_dictiter__length_hint__(space, w_self): - from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject - assert isinstance(w_self, W_BaseDictMultiIterObject) - return space.wrap(w_self.iteratorimplementation.length()) - - -def descr_dictiter__reduce__(w_self, space): - """ - This is a slightly special case of pickling. - Since iteration over a dict is a bit hairy, - we do the following: - - create a clone of the dict iterator - - run it to the original position - - collect all remaining elements into a list - At unpickling time, we just use that list - and create an iterator on it. - This is of course not the standard way. - - XXX to do: remove this __reduce__ method and do - a registration with copyreg, instead. - """ - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) - - raise OperationError( - space.w_TypeError, - space.wrap("can't pickle dictionary-keyiterator objects")) - # XXXXXX get that working again - - # we cannot call __init__ since we don't have the original dict - if isinstance(w_self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(w_self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(w_self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) - else: - msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_clone.space = space - w_clone.content = w_self.content - w_clone.len = w_self.len - w_clone.pos = 0 - w_clone.setup_iterator() - # spool until we have the same pos - while w_clone.pos < w_self.pos: - w_obj = w_clone.next_entry() - w_clone.pos += 1 - stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] - w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) - return w_ret - -# ____________________________________________________________ - - -dictiter_typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), - __reduce__ = gateway.interp2app(descr_dictiter__reduce__), - ) - -# ____________________________________________________________ -# Dict views - -def descr_dictview_isdisjoin(space, w_self, w_other): - from pypy.objspace.std.dictmultiobject import W_DictViewObject - if w_self is w_other: - if space.len_w(w_self) == 0: - return space.w_True - else: - return space.w_False - - # check whether w_other is a set-like object - if (space.isinstance_w(w_other, space.w_set) or - space.isinstance_w(w_other, space.w_frozenset) or - isinstance(w_other, W_DictViewObject)): - # if w_other is set-like and it's longer, we iterate over w_self - # instead - len_self = space.len_w(w_self) - len_other = space.len_w(w_other) - if len_other > len_self: - w_self, w_other = w_other, w_self - - w_it = space.iter(w_other) - for w_item in space.iteriterable(w_it): - if space.is_true(space.contains(w_self, w_item)): - return space.w_False - return space.w_True - - -dict_keys_typedef = StdTypeDef( - "dict_keys", - isdisjoint = gateway.interp2app(descr_dictview_isdisjoin), - - ) -dict_keys_typedef.registermethods(globals()) - -dict_items_typedef = StdTypeDef( - "dict_items", - isdisjoint = gateway.interp2app(descr_dictview_isdisjoin), - ) - -dict_values_typedef = StdTypeDef( - "dict_values", - ) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -12,6 +12,7 @@ from pypy.objspace.std.register_all import register_all from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint, intmask from pypy.objspace.std import model +from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.interpreter.special import Ellipsis from pypy.interpreter.pycode import PyCode from pypy.interpreter import gateway, unicodehelper @@ -24,7 +25,6 @@ from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.longobject import W_LongObject, newlong @@ -279,15 +279,18 @@ return space.newlist(items_w) register(TYPE_LIST, unmarshal_List) -def marshal_w__DictMulti(space, w_dict, m): +def marshal_w_dict(space, w_dict, m): + if not isinstance(w_dict, W_DictMultiObject): + raise_exception(space, "unmarshallable object") m.start(TYPE_DICT) for w_tuple in w_dict.items(): w_key, w_value = space.fixedview(w_tuple, 2) m.put_w_obj(w_key) m.put_w_obj(w_value) m.atom(TYPE_NULL) +handled_by_any.append(('dict', marshal_w_dict)) -def unmarshal_DictMulti(space, u, tc): +def unmarshal_dict(space, u, tc): # since primitive lists are not optimized and we don't know # the dict size in advance, use the dict's setitem instead # of building a list of tuples. @@ -299,7 +302,7 @@ w_value = u.get_w_obj() space.setitem(w_dic, w_key, w_value) return w_dic -register(TYPE_DICT, unmarshal_DictMulti) +register(TYPE_DICT, unmarshal_dict) def unmarshal_NULL(self, u, tc): return None diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -40,7 +40,6 @@ from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef - from pypy.objspace.std.dicttype import dict_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef from pypy.objspace.std.typeobject import type_typedef @@ -80,6 +79,7 @@ # not-multimethod based types + self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -91,10 +91,6 @@ floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], listobject.W_ListObject: [], - dictmultiobject.W_DictMultiObject: [], - dictmultiobject.W_DictMultiIterKeysObject: [], - dictmultiobject.W_DictMultiIterValuesObject: [], - dictmultiobject.W_DictMultiIterItemsObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -107,9 +103,6 @@ iterobject.W_FastTupleIterObject: [], iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], - dictmultiobject.W_DictViewKeysObject: [], - dictmultiobject.W_DictViewItemsObject: [], - dictmultiobject.W_DictViewValuesObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], } @@ -327,9 +320,6 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(self, space): - raise UnwrapError('cannot unwrap %r' % self) - class UnwrapError(Exception): pass diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -276,10 +276,9 @@ def unwrap(self, w_obj): """NOT_RPYTHON""" - if isinstance(w_obj, model.W_Object): + # _____ this code is here to support testing only _____ + if isinstance(w_obj, W_Root): return w_obj.unwrap(self) - if isinstance(w_obj, W_Root): - return w_obj raise model.UnwrapError("cannot unwrap: %r" % w_obj) def newint(self, intval): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -3,8 +3,7 @@ import py from pypy.objspace.std.dictmultiobject import (W_DictMultiObject, - setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, StringDictStrategy, - ObjectDictStrategy) + StringDictStrategy, ObjectDictStrategy) class TestW_DictObject(object): @@ -398,6 +397,24 @@ f = getattr(operator, op) raises(TypeError, f, d1, d2) + def test_other_rich_cmp(self): + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} + + assert d1 <= d2 + assert d1 <= d3 + assert not d1 <= d4 + + assert not d1 > d2 + assert not d1 > d3 + assert d1 > d4 + + assert d1 >= d2 + assert not d1 >= d3 + assert d1 >= d4 + def test_str_repr(self): assert '{}' == str({}) assert '{1: 2}' == str({1: 2}) @@ -597,6 +614,9 @@ assert isinstance(list({b'a': 1})[0], bytes) + def test_cmp_with_noncmp(self): + assert not {} > object() + class AppTest_DictMultiObject(AppTest_DictObject): def test_emptydict_unhashable(self): @@ -1127,10 +1147,10 @@ pydict = {} for i in range(N): x = randint(-N, N) - setitem__DictMulti_ANY_ANY(self.space, d, x, i) + d.descr_setitem(self.space, x, i) pydict[x] = i for key, value in pydict.iteritems(): - assert value == getitem__DictMulti_ANY(self.space, d, key) + assert value == d.descr_getitem(self.space, key) class BaseTestRDictImplementation: From noreply at buildbot.pypy.org Sat May 18 23:14:19 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 23:14:19 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130518211419.7C18F1C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64290:affecb147320 Date: 2013-05-17 11:59 -0700 http://bitbucket.org/pypy/pypy/changeset/affecb147320/ Log: merge default diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,13 +1,14 @@ -from pypy.interpreter import gateway from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import ( + WrappedDefault, applevel, interp2app, unwrap_spec) from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef -from rpython.rlib import rerased, jit +from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null -from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint +from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize from rpython.tool.sourcetools import func_with_new_name @@ -18,7 +19,7 @@ return space.is_w(space.type(w_key), space.w_str) def _never_equal_to_string(space, w_lookup_type): - """ Handles the case of a non string key lookup. + """Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. XXX The types should provide such a flag. """ @@ -32,7 +33,7 @@ @specialize.call_location() def w_dict_unrolling_heuristic(w_dct): - """ In which cases iterating over dict items can be unrolled. + """In which cases iterating over dict items can be unrolled. Note that w_dct is an instance of W_DictMultiObject, not necesarilly an actual dict """ @@ -56,8 +57,8 @@ class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, - instance=False, strdict=False, kwargs=False): - + instance=False, strdict=False, + kwargs=False): if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None @@ -67,16 +68,13 @@ elif space.config.objspace.std.withmapdict and instance: from pypy.objspace.std.mapdict import MapDictStrategy strategy = space.fromcache(MapDictStrategy) - - # elif instance or strdict or module: - # assert w_type is None - # strategy = space.fromcache(StringDictStrategy) - + #elif instance or strdict or module: + # assert w_type is None + # strategy = space.fromcache(StringDictStrategy) elif False and kwargs: assert w_type is None from pypy.objspace.std.kwargsdict import EmptyKwargsDictStrategy strategy = space.fromcache(EmptyKwargsDictStrategy) - else: strategy = space.fromcache(EmptyDictStrategy) if w_type is None: @@ -93,7 +91,7 @@ self.dstorage = storage def __repr__(w_self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): @@ -106,12 +104,10 @@ def missing_method(w_dict, space, w_key): if not space.is_w(space.type(w_dict), space.w_dict): - w_missing = space.lookup(w_dict, "__missing__") - if w_missing is None: - return None - return space.get_and_call_function(w_missing, w_dict, w_key) - else: - return None + w_missing = space.lookup(w_dict, '__missing__') + if w_missing is not None: + return space.get_and_call_function(w_missing, w_dict, w_key) + return None def initialize_content(w_self, list_pairs_w): for w_k, w_v in list_pairs_w: @@ -164,7 +160,7 @@ if self.length() != w_other.length(): return space.w_False iteratorimplementation = self.iteritems() - while 1: + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break @@ -241,7 +237,8 @@ space.raise_key_error(w_key) def descr_reversed(self, space): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + raise OperationError(space.w_TypeError, space.wrap( + 'argument to reversed() must be a sequence')) def descr_copy(self, space): """D.copy() -> a shallow copy of D""" @@ -293,16 +290,13 @@ """D.clear() -> None. Remove all items from D.""" self.clear() - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_get(self, space, w_key, w_default): """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" w_value = self.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default + return w_value if w_value is not None else w_default - @gateway.unwrap_spec(defaults_w='args_w') + @unwrap_spec(defaults_w='args_w') def descr_pop(self, space, w_key, defaults_w): """D.pop(k[,d]) -> v, remove specified key and return the corresponding value\nIf key is not found, d is returned if given, @@ -333,7 +327,7 @@ space.wrap("popitem(): dictionary is empty")) return space.newtuple([w_key, w_value]) - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_setdefault(self, space, w_key, w_default): """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" return self.setdefault(w_key, w_default) @@ -365,7 +359,7 @@ _add_indirections() -app = gateway.applevel(''' +app = applevel(''' def dictrepr(currently_in_repr, d): if len(d) == 0: return "{}" @@ -401,46 +395,46 @@ d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(W_DictMultiObject.descr_new), - fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, - as_classmethod=True), + __new__ = interp2app(W_DictMultiObject.descr_new), + fromkeys = interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), __hash__ = None, - __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), - __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + __repr__ = interp2app(W_DictMultiObject.descr_repr), + __init__ = interp2app(W_DictMultiObject.descr_init), - __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), - __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), - __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), - __le__ = gateway.interp2app(W_DictMultiObject.descr_le), - __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), - __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), + __eq__ = interp2app(W_DictMultiObject.descr_eq), + __ne__ = interp2app(W_DictMultiObject.descr_ne), + __lt__ = interp2app(W_DictMultiObject.descr_lt), + __le__ = interp2app(W_DictMultiObject.descr_le), + __gt__ = interp2app(W_DictMultiObject.descr_gt), + __ge__ = interp2app(W_DictMultiObject.descr_ge), - __len__ = gateway.interp2app(W_DictMultiObject.descr_len), - __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), - __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + __len__ = interp2app(W_DictMultiObject.descr_len), + __iter__ = interp2app(W_DictMultiObject.descr_iter), + __contains__ = interp2app(W_DictMultiObject.descr_contains), - __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), - __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), - __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + __getitem__ = interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = interp2app(W_DictMultiObject.descr_delitem), - __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), - copy = gateway.interp2app(W_DictMultiObject.descr_copy), - items = gateway.interp2app(W_DictMultiObject.descr_items), - keys = gateway.interp2app(W_DictMultiObject.descr_keys), - values = gateway.interp2app(W_DictMultiObject.descr_values), - iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), - iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), - itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), - viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), - viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), - viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), - has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), - clear = gateway.interp2app(W_DictMultiObject.descr_clear), - get = gateway.interp2app(W_DictMultiObject.descr_get), - pop = gateway.interp2app(W_DictMultiObject.descr_pop), - popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), - setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), - update = gateway.interp2app(W_DictMultiObject.descr_update), + __reversed__ = interp2app(W_DictMultiObject.descr_reversed), + copy = interp2app(W_DictMultiObject.descr_copy), + items = interp2app(W_DictMultiObject.descr_items), + keys = interp2app(W_DictMultiObject.descr_keys), + values = interp2app(W_DictMultiObject.descr_values), + iteritems = interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = interp2app(W_DictMultiObject.descr_viewvalues), + has_key = interp2app(W_DictMultiObject.descr_has_key), + clear = interp2app(W_DictMultiObject.descr_clear), + get = interp2app(W_DictMultiObject.descr_get), + pop = interp2app(W_DictMultiObject.descr_pop), + popitem = interp2app(W_DictMultiObject.descr_popitem), + setdefault = interp2app(W_DictMultiObject.descr_setdefault), + update = interp2app(W_DictMultiObject.descr_update), ) @@ -454,7 +448,7 @@ def w_keys(self, w_dict): iterator = self.iterkeys(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key = iterator.next_key() if w_key is not None: result.append(w_key) @@ -464,7 +458,7 @@ def values(self, w_dict): iterator = self.itervalues(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_value = iterator.next_value() if w_value is not None: result.append(w_value) @@ -474,7 +468,7 @@ def items(self, w_dict): iterator = self.iteritems(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is not None: result.append(self.space.newtuple([w_key, w_value])) @@ -516,7 +510,7 @@ unerase = staticmethod(unerase) def get_empty_storage(self): - return self.erase(None) + return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): withidentitydict = self.space.config.objspace.std.withidentitydict @@ -621,7 +615,7 @@ # Iterator Implementation base classes def _new_next(TP): - if TP == 'key' or TP == 'value': + if TP in ('key', 'value'): EMPTY = None else: EMPTY = None, None @@ -629,10 +623,12 @@ def next(self): if self.dictimplementation is None: return EMPTY + space = self.space if self.len != self.dictimplementation.length(): self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed size during iteration")) + msg = "dictionary changed size during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + # look for the next entry if self.pos < self.len: result = getattr(self, 'next_' + TP + '_entry')() @@ -650,8 +646,8 @@ w_value = self.dictimplementation.getitem(w_key) if w_value is None: self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed during iteration")) + msg = "dictionary changed during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) return (w_key, w_value) # no more entries self.dictimplementation = None @@ -784,7 +780,8 @@ def setdefault(self, w_dict, w_key, w_default): if self.is_correct_type(w_key): - return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), + w_default) else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) @@ -824,7 +821,7 @@ space = self.space dict_w = self.unerase(w_dict.dstorage) return [space.newtuple([self.wrap(key), w_value]) - for (key, w_value) in dict_w.iteritems()] + for (key, w_value) in dict_w.iteritems()] def popitem(self, w_dict): key, value = self.unerase(w_dict.dstorage).popitem() @@ -869,9 +866,9 @@ return True def get_empty_storage(self): - new_dict = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.erase(new_dict) + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) def _never_equal_to(self, w_lookup_type): return False @@ -1072,7 +1069,7 @@ w_dict_unrolling_heuristic(w_data)) def update1_dict_dict(space, w_dict, w_data): iterator = w_data.iteritems() - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is None: break @@ -1110,16 +1107,18 @@ update1(space, w_dict, w_kwds) def characterize(space, w_a, w_b): - """ (similar to CPython) - returns the smallest key in acontent for which b's value is different or absent and this value """ + """(similar to CPython) + returns the smallest key in acontent for which b's value is + different or absent and this value""" w_smallest_diff_a_key = None w_its_value = None iteratorimplementation = w_a.iteritems() - while 1: + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break - if w_smallest_diff_a_key is None or space.is_true(space.lt(w_key, w_smallest_diff_a_key)): + if w_smallest_diff_a_key is None or space.is_true(space.lt( + w_key, w_smallest_diff_a_key)): w_bvalue = w_b.getitem(w_key) if w_bvalue is None: w_its_value = w_val @@ -1195,10 +1194,7 @@ w_clone.pos += 1 stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + w_ret = space.newtuple([new_inst, space.newtuple([w_res])]) return w_ret @@ -1228,23 +1224,23 @@ W_DictMultiIterItemsObject.typedef = StdTypeDef( "dict_iteritems", - __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), + next = interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterKeysObject.typedef = StdTypeDef( "dict_iterkeys", - __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), + next = interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterValuesObject.typedef = StdTypeDef( "dict_itervalues", - __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), + next = interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) @@ -1309,33 +1305,33 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", - __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewItemsObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), - __or__ = gateway.interp2app(W_DictViewItemsObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewItemsObject.descr_xor) + __repr__ = interp2app(W_DictViewItemsObject.descr_repr), + __eq__ = interp2app(W_DictViewItemsObject.descr_eq), + __len__ = interp2app(W_DictViewItemsObject.descr_len), + __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + __and__ = interp2app(W_DictViewItemsObject.descr_and), + __or__ = interp2app(W_DictViewItemsObject.descr_or), + __xor__ = interp2app(W_DictViewItemsObject.descr_xor) ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", - __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewKeysObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), - __or__ = gateway.interp2app(W_DictViewKeysObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewKeysObject.descr_xor) + __repr__ = interp2app(W_DictViewKeysObject.descr_repr), + __eq__ = interp2app(W_DictViewKeysObject.descr_eq), + __len__ = interp2app(W_DictViewKeysObject.descr_len), + __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + __and__ = interp2app(W_DictViewKeysObject.descr_and), + __or__ = interp2app(W_DictViewKeysObject.descr_or), + __xor__ = interp2app(W_DictViewKeysObject.descr_xor) ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", - __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewValuesObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), - __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) + __repr__ = interp2app(W_DictViewValuesObject.descr_repr), + __eq__ = interp2app(W_DictViewValuesObject.descr_eq), + __len__ = interp2app(W_DictViewValuesObject.descr_len), + __iter__ = interp2app(W_DictViewValuesObject.descr_iter), + __and__ = interp2app(W_DictViewValuesObject.descr_and), + __or__ = interp2app(W_DictViewValuesObject.descr_or), + __xor__ = interp2app(W_DictViewValuesObject.descr_xor) ) From noreply at buildbot.pypy.org Sat May 18 23:14:20 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 23:14:20 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130518211420.D4ABE1C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64291:b1432cb778e6 Date: 2013-05-17 16:43 -0700 http://bitbucket.org/pypy/pypy/changeset/b1432cb778e6/ Log: merge default diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1276,6 +1276,14 @@ def descr_len(self, space): return space.len(self.w_dict) +class SetLikeDictView(object): + _mixin_ = True + + def descr_sub(self, space, w_otherview): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, "difference_update", w_otherview) + return w_set + def descr_and(self, space, w_otherview): w_set = space.call_function(space.w_set, self) space.call_method(w_set, "intersection_update", w_otherview) @@ -1291,11 +1299,11 @@ space.call_method(w_set, "symmetric_difference_update", w_otherview) return w_set -class W_DictViewItemsObject(W_DictViewObject): +class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) -class W_DictViewKeysObject(W_DictViewObject): +class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) @@ -1309,6 +1317,7 @@ __eq__ = interp2app(W_DictViewItemsObject.descr_eq), __len__ = interp2app(W_DictViewItemsObject.descr_len), __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), __and__ = interp2app(W_DictViewItemsObject.descr_and), __or__ = interp2app(W_DictViewItemsObject.descr_or), __xor__ = interp2app(W_DictViewItemsObject.descr_xor) @@ -1320,6 +1329,7 @@ __eq__ = interp2app(W_DictViewKeysObject.descr_eq), __len__ = interp2app(W_DictViewKeysObject.descr_len), __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), __and__ = interp2app(W_DictViewKeysObject.descr_and), __or__ = interp2app(W_DictViewKeysObject.descr_or), __xor__ = interp2app(W_DictViewKeysObject.descr_xor) @@ -1331,7 +1341,4 @@ __eq__ = interp2app(W_DictViewValuesObject.descr_eq), __len__ = interp2app(W_DictViewValuesObject.descr_len), __iter__ = interp2app(W_DictViewValuesObject.descr_iter), - __and__ = interp2app(W_DictViewValuesObject.descr_and), - __or__ = interp2app(W_DictViewValuesObject.descr_or), - __xor__ = interp2app(W_DictViewValuesObject.descr_xor) ) From noreply at buildbot.pypy.org Sat May 18 23:14:22 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 23:14:22 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130518211422.129161C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64292:f05520ba4cf5 Date: 2013-05-18 13:49 -0700 http://bitbucket.org/pypy/pypy/changeset/f05520ba4cf5/ Log: merge default diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -11,6 +11,8 @@ from rpython.rlib import rlocale from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -124,6 +126,15 @@ source = rffi.charp2str(ll_source) return _pypy_execute_source(source) + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + rthread.gc_thread_start() + w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), space.builtin_modules['builtins']) @@ -141,6 +152,8 @@ return 0 return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, 'pypy_setup_home': pypy_setup_home} def call_finish(space): diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -9,7 +9,7 @@ from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize -from rpython.tool.sourcetools import func_with_new_name +from rpython.tool.sourcetools import func_renamer, func_with_new_name UNROLL_CUTOFF = 5 @@ -1257,47 +1257,87 @@ return space.wrap("%s(%s)" % (space.type(self).getname(space), space.str_w(w_repr))) - def descr_eq(self, space, w_otherview): - if not space.eq_w(space.len(self), space.len(w_otherview)): - return space.w_False - - w_iter = space.iter(self) - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - return space.w_True - def descr_len(self, space): return space.len(self.w_dict) +def _all_contained_in(space, w_dictview, w_other): + w_iter = space.iter(w_dictview) + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + if not space.is_true(space.contains(w_other, w_item)): + return space.w_False + return space.w_True + +def _is_set_like(w_other): + from pypy.objspace.std.setobject import W_BaseSetObject + return (isinstance(w_other, W_BaseSetObject) or + isinstance(w_other, SetLikeDictView)) + class SetLikeDictView(object): _mixin_ = True - def descr_sub(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "difference_update", w_otherview) - return w_set + def descr_eq(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) == space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False - def descr_and(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set + def descr_ne(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + return space.not_(space.eq(self, w_other)) - def descr_or(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "update", w_otherview) - return w_set + def descr_lt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) < space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False - def descr_xor(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set + def descr_le(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) <= space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_gt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) > space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def descr_ge(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) >= space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def _as_set_op(name, methname): + @func_renamer('descr_' + name) + def op(self, space, w_other): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, methname, w_other) + return w_set + @func_renamer('descr_r' + name) + def rop(self, space, w_other): + w_set = space.call_function(space.w_set, w_other) + space.call_method(w_set, methname, self) + return w_set + return op, rop + + descr_sub, descr_rsub = _as_set_op('sub', 'difference_update') + descr_and, descr_rand = _as_set_op('and', 'intersection_update') + descr_or, descr_ror = _as_set_op('or', 'update') + descr_xor, descr_rxor = _as_set_op('xor', 'symmetric_difference_update') class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): @@ -1314,31 +1354,52 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", __repr__ = interp2app(W_DictViewItemsObject.descr_repr), - __eq__ = interp2app(W_DictViewItemsObject.descr_eq), __len__ = interp2app(W_DictViewItemsObject.descr_len), __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + + __eq__ = interp2app(W_DictViewItemsObject.descr_eq), + __ne__ = interp2app(W_DictViewItemsObject.descr_ne), + __lt__ = interp2app(W_DictViewItemsObject.descr_lt), + __le__ = interp2app(W_DictViewItemsObject.descr_le), + __gt__ = interp2app(W_DictViewItemsObject.descr_gt), + __ge__ = interp2app(W_DictViewItemsObject.descr_ge), + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), + __rsub__ = interp2app(W_DictViewItemsObject.descr_rsub), __and__ = interp2app(W_DictViewItemsObject.descr_and), + __rand__ = interp2app(W_DictViewItemsObject.descr_rand), __or__ = interp2app(W_DictViewItemsObject.descr_or), - __xor__ = interp2app(W_DictViewItemsObject.descr_xor) + __ror__ = interp2app(W_DictViewItemsObject.descr_ror), + __xor__ = interp2app(W_DictViewItemsObject.descr_xor), + __rxor__ = interp2app(W_DictViewItemsObject.descr_rxor), ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", __repr__ = interp2app(W_DictViewKeysObject.descr_repr), - __eq__ = interp2app(W_DictViewKeysObject.descr_eq), __len__ = interp2app(W_DictViewKeysObject.descr_len), __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + + __eq__ = interp2app(W_DictViewKeysObject.descr_eq), + __ne__ = interp2app(W_DictViewKeysObject.descr_ne), + __lt__ = interp2app(W_DictViewKeysObject.descr_lt), + __le__ = interp2app(W_DictViewKeysObject.descr_le), + __gt__ = interp2app(W_DictViewKeysObject.descr_gt), + __ge__ = interp2app(W_DictViewKeysObject.descr_ge), + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), + __rsub__ = interp2app(W_DictViewKeysObject.descr_rsub), __and__ = interp2app(W_DictViewKeysObject.descr_and), + __rand__ = interp2app(W_DictViewKeysObject.descr_rand), __or__ = interp2app(W_DictViewKeysObject.descr_or), - __xor__ = interp2app(W_DictViewKeysObject.descr_xor) + __ror__ = interp2app(W_DictViewKeysObject.descr_ror), + __xor__ = interp2app(W_DictViewKeysObject.descr_xor), + __rxor__ = interp2app(W_DictViewKeysObject.descr_rxor), ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", __repr__ = interp2app(W_DictViewValuesObject.descr_repr), - __eq__ = interp2app(W_DictViewValuesObject.descr_eq), __len__ = interp2app(W_DictViewValuesObject.descr_len), __iter__ = interp2app(W_DictViewValuesObject.descr_iter), ) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -681,6 +681,7 @@ assert keys != set([1, "b"]) assert keys != set([1]) assert keys != 42 + assert not keys == 42 assert 1 in keys assert "a" in keys assert 10 not in keys @@ -702,6 +703,7 @@ assert items != set([(1, 10), ("a", "def")]) assert items != set([(1, 10)]) assert items != 42 + assert not items == 42 assert (1, 10) in items assert ("a", "ABC") in items assert (1, 11) not in items @@ -726,6 +728,7 @@ values = d.values() assert set(values) == set([10, "ABC"]) assert len(values) == 2 + assert not values == 42 def test_dict_repr(self): d = {1: 10, "a": "ABC"} @@ -892,7 +895,7 @@ assert not frozenset({(1, 'a'), (2, 'b'), (3, 'c')}) != d.items() """ - def test_dictviewset_unshasable_values(self): + def test_dictviewset_unhashable_values(self): class C: def __eq__(self, other): return True diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -1,9 +1,10 @@ """ Utilities to get environ variables and platform-specific memory-related values. """ -import os, sys +import os, sys, platform from rpython.rlib.rarithmetic import r_uint from rpython.rlib.debug import debug_print, debug_start, debug_stop +from rpython.rlib.rstring import assert_str0 from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.lltypesystem.lloperation import llop @@ -130,7 +131,22 @@ # ---------- Linux2 ---------- -def get_L2cache_linux2(filename="/proc/cpuinfo"): +def get_L2cache_linux2(): + arch = platform.machine() + if arch.endswith('86') or arch == 'x86_64': + return get_L2cache_linux2_cpuinfo() + if arch in ('alpha', 'ppc', 'ppc64'): + return get_L2cache_linux2_cpuinfo(label='L2 cache') + if arch == 'ia64': + return get_L2cache_linux2_ia64() + if arch in ('parisc', 'parisc64'): + return get_L2cache_linux2_cpuinfo(label='D-cache') + if arch in ('sparc', 'sparc64'): + return get_L2cache_linux2_sparc() + return -1 + + +def get_L2cache_linux2_cpuinfo(filename="/proc/cpuinfo", label='cache size'): debug_start("gc-hardware") L2cache = sys.maxint try: @@ -149,12 +165,8 @@ else: data = ''.join(data) linepos = 0 - # Currently on ARM-linux we won't find any information about caches in - # cpuinfo - if _detect_arm_cpu(data): - return -1 while True: - start = _findend(data, '\ncache size', linepos) + start = _findend(data, '\n' + label, linepos) if start < 0: break # done linepos = _findend(data, '\n', start) @@ -194,6 +206,104 @@ "Warning: cannot find your CPU L2 cache size in /proc/cpuinfo") return -1 +def get_L2cache_linux2_sparc(): + debug_start("gc-hardware") + cpu = 0 + L2cache = sys.maxint + while True: + try: + fd = os.open('/sys/devices/system/cpu/cpu' + assert_str0(str(cpu)) + + '/l2_cache_size', os.O_RDONLY, 0644) + try: + number = int(os.read(fd, 4096)) + finally: + os.close(fd) + except OSError: + break + if number < L2cache: + L2cache = number + cpu += 1 + + debug_print("L2cache =", L2cache) + debug_stop("gc-hardware") + if L2cache < sys.maxint: + return L2cache + else: + # Print a top-level warning even in non-debug builds + llop.debug_print(lltype.Void, + "Warning: cannot find your CPU L2 cache size in " + "/sys/devices/system/cpu/cpuX/l2_cache_size") + return -1 + +def get_L2cache_linux2_ia64(): + debug_start("gc-hardware") + cpu = 0 + L2cache = sys.maxint + L3cache = sys.maxint + while True: + cpudir = '/sys/devices/system/cpu/cpu' + assert_str0(str(cpu)) + index = 0 + while True: + cachedir = cpudir + '/cache/index' + assert_str0(str(index)) + try: + fd = os.open(cachedir + '/level', os.O_RDONLY, 0644) + try: + level = int(os.read(fd, 4096)[:-1]) + finally: + os.close(fd) + except OSError: + break + if level not in (2, 3): + index += 1 + continue + try: + fd = os.open(cachedir + '/size', os.O_RDONLY, 0644) + try: + data = os.read(fd, 4096) + finally: + os.close(fd) + except OSError: + break + + end = 0 + while '0' <= data[end] <= '9': + end += 1 + if end == 0: + index += 1 + continue + if data[end] not in ('K', 'k'): # assume kilobytes for now + index += 1 + continue + + number = int(data[:end]) + number *= 1024 + + if level == 2: + if number < L2cache: + L2cache = number + if level == 3: + if number < L3cache: + L3cache = number + + index += 1 + + if index == 0: + break + cpu += 1 + + mangled = L2cache + L3cache + debug_print("L2cache =", mangled) + debug_stop("gc-hardware") + if mangled > 0: + return mangled + else: + # Print a top-level warning even in non-debug builds + llop.debug_print(lltype.Void, + "Warning: cannot find your CPU L2 & L3 cache size in " + "/sys/devices/system/cpu/cpuX/cache") + return -1 + + def _findend(data, pattern, pos): pos = data.find(pattern, pos) if pos < 0: @@ -205,11 +315,6 @@ pos += 1 return pos -def _detect_arm_cpu(data): - # check for the presence of a 'Processor' entry - p = _findend(data, 'Processor', 0) - return p >= 0 and _findend(data, 'ARMv', p) > 0 - # ---------- Darwin ---------- sysctlbyname = rffi.llexternal('sysctlbyname', diff --git a/rpython/memory/gc/test/test_env.py b/rpython/memory/gc/test/test_env.py --- a/rpython/memory/gc/test/test_env.py +++ b/rpython/memory/gc/test/test_env.py @@ -159,25 +159,9 @@ fpu : yes etc. """) - result = env.get_L2cache_linux2(str(filepath)) + result = env.get_L2cache_linux2_cpuinfo(str(filepath)) assert result == 3072 * 1024 def test_estimate_best_nursery_size_linux2_arm(): - filepath = udir.join('estimate_best_nursery_size_linux2') - filepath.write("""\ -Processor : ARMv6-compatible processor rev 7 (v6l) -# this is not actually from cpuinfo, but here for the test -cache size : 3072 KB -... -""") - result = env.get_L2cache_linux2(str(filepath)) + result = env.get_L2cache_linux2() assert result == -1 - -def test__detect_arm(): - assert env._detect_arm_cpu("Processor : ARMv6-compatible processor rev 7 (v6l)") - assert not env._detect_arm_cpu("""\ -processor : 0 -vendor_id : GenuineIntel -cpu family : 6 -model : 37 -""") diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -447,11 +447,11 @@ @jit.elidable def repr(self): - return _format(self, BASE10, '', 'L') + return _format_decimal(self, addL=True) @jit.elidable def str(self): - return _format(self, BASE10) + return _format_decimal(self) @jit.elidable def eq(self, other): @@ -2101,6 +2101,101 @@ return ''.join(s[p:]) +DECIMAL_SHIFT = 0 # computed as max(E such that 10**E fits in a digit) +while 10 ** (DECIMAL_SHIFT + 1) <= 2 ** SHIFT: + DECIMAL_SHIFT += 1 +DECIMAL_BASE = 10 ** DECIMAL_SHIFT + +# an RPython trick: this creates a nested sequence of calls that are +# all inlined into each other, making an unrolled loop. Moreover the +# calls are done in the "wrong" order to be written as a regular loop: +# the first digit that is append-ed to the builder is the most +# significant one (corresponding to the innermost call). +_succ = specialize.memo()(lambda n: n + 1) + at specialize.arg(3) +def _add_decimal_digits(builder, value, ndigits, digit_index=1): + assert value >= 0 + if digit_index < ndigits: + assert digit_index < DECIMAL_SHIFT + _add_decimal_digits(builder, value // 10, ndigits, _succ(digit_index)) + builder.append(chr(ord('0') + value % 10)) + else: + assert value < 10 + builder.append(chr(ord('0') + value)) +_add_decimal_digits._always_inline_ = True + + +def _format_decimal(a, addL=False): + """ Optimized version of _format(a, BASE10, '', 'L' if addL else ''). """ + if a.sign == 0: + if addL: + return "0L" + else: + return "0" + + size_a = a.numdigits() + negative = a.sign < 0 + + # quick and dirty upper bound for the number of digits + # required to express a in base DECIMAL_BASE: + # + # #digits = 1 + floor(log2(a) / log2(DECIMAL_BASE)) + # + # But log2(a) < size_a * PyLong_SHIFT, and + # log2(DECIMAL_BASE) = log2(10) * DECIMAL_SHIFT + # > 3 * DECIMAL_SHIFT + + size = 1 + size_a * SHIFT // (3 * DECIMAL_SHIFT) + pout = [NULLDIGIT] * size + + # convert array of base _PyLong_BASE digits in pin to an array of + # base _PyLong_DECIMAL_BASE digits in pout, following Knuth (TAOCP, + # Volume 2 (3rd edn), section 4.4, Method 1b). + size = 0 + for i in range(size_a-1, -1, -1): + hi = a.digit(i) + for j in range(size): + z = (_widen_digit(pout[j]) << SHIFT) | hi + hi = _store_digit(z // DECIMAL_BASE) + pout[j] = _store_digit(z - _widen_digit(hi) * DECIMAL_BASE) + assert hi >= 0 + while hi: + pout[size] = hi % DECIMAL_BASE + hi //= DECIMAL_BASE + size += 1 + sizem1 = size - 1 + assert sizem1 >= 0 + + # calculate exact length of output string, and allocate + decimal_digits_in_last_part = 1 + rem = pout[sizem1] + tenpow = 10 + while rem >= tenpow: + tenpow *= 10 + decimal_digits_in_last_part += 1 + strlen = (addL + negative + + decimal_digits_in_last_part + (sizem1) * DECIMAL_SHIFT) + + builder = StringBuilder(strlen) + + # start with the negative sign, if needed + if negative: + builder.append('-') + + # pout[size-1] produces 'decimal_digits_in_last_part' digits. + # Then the remaining pout[size-2] through pout[0] contribute exactly + # DECIMAL_SHIFT digits each. + decimal_digits = decimal_digits_in_last_part + for i in range(sizem1, -1, -1): + _add_decimal_digits(builder, pout[i], decimal_digits) + decimal_digits = DECIMAL_SHIFT + + # done + if addL: + builder.append('L') + return builder.build() + + def _bitwise(a, op, b): # '&', '|', '^' """ Bitwise and/or/xor operations """ diff --git a/rpython/translator/platform/freebsd.py b/rpython/translator/platform/freebsd.py --- a/rpython/translator/platform/freebsd.py +++ b/rpython/translator/platform/freebsd.py @@ -12,3 +12,11 @@ class Freebsd_64(Freebsd): shared_only = ('-fPIC',) + +class GNUkFreebsd(Freebsd): + DEFAULT_CC = 'cc' + extra_libs = ('-lrt',) + +class GNUkFreebsd_64(Freebsd_64): + DEFAULT_CC = 'cc' + extra_libs = ('-lrt',) From noreply at buildbot.pypy.org Sat May 18 23:14:23 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 23:14:23 +0200 (CEST) Subject: [pypy-commit] pypy py3k: reapply the py3k dict modifications Message-ID: <20130518211423.6A78E1C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64293:a4bb67b9f4e1 Date: 2013-05-18 14:12 -0700 http://bitbucket.org/pypy/pypy/changeset/a4bb67b9f4e1/ Log: reapply the py3k dict modifications diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -171,41 +171,7 @@ return space.w_False return space.w_True - def descr_lt(self, space, w_other): - if not isinstance(w_other, W_DictMultiObject): - return space.w_NotImplemented - return self._compare_lt(space, w_other) - - def descr_gt(self, space, w_other): - if not isinstance(w_other, W_DictMultiObject): - return space.w_NotImplemented - return w_other._compare_lt(space, self) - - def _compare_lt(self, space, w_other): - # Different sizes, no problem - if self.length() < w_other.length(): - return space.w_True - if self.length() > w_other.length(): - return space.w_False - - # Same size - w_leftdiff, w_leftval = characterize(space, self, w_other) - if w_leftdiff is None: - return space.w_False - w_rightdiff, w_rightval = characterize(space, w_other, self) - if w_rightdiff is None: - # w_leftdiff is not None, w_rightdiff is None - return space.w_True - w_res = space.lt(w_leftdiff, w_rightdiff) - if (not space.is_true(w_res) and - space.eq_w(w_leftdiff, w_rightdiff) and - w_rightval is not None): - w_res = space.lt(w_leftval, w_rightval) - return w_res - descr_ne = negate(descr_eq) - descr_le = negate(descr_gt) - descr_ge = negate(descr_lt) def descr_len(self, space): return space.wrap(self.length()) @@ -247,16 +213,16 @@ return w_new def descr_items(self, space): - """D.items() -> list of D's (key, value) pairs, as 2-tuples""" - return space.newlist(self.items()) + """D.items() -> a set-like object providing a view on D's items""" + return W_DictViewItemsObject(space, self) def descr_keys(self, space): - """D.keys() -> list of D's keys""" - return self.w_keys() + """D.keys() -> a set-like object providing a view on D's keys""" + return W_DictViewKeysObject(space, self) def descr_values(self, space): - """D.values() -> list of D's values""" - return space.newlist(self.values()) + """D.values() -> an object providing a view on D's values""" + return W_DictViewValuesObject(space, self) def descr_iteritems(self, space): """D.iteritems() -> an iterator over the (key, value) items of D""" @@ -270,22 +236,6 @@ """D.itervalues() -> an iterator over the values of D""" return W_DictMultiIterValuesObject(space, self.itervalues()) - def descr_viewitems(self, space): - """D.viewitems() -> a set-like object providing a view on D's items""" - return W_DictViewItemsObject(space, self) - - def descr_viewkeys(self, space): - """D.viewkeys() -> a set-like object providing a view on D's keys""" - return W_DictViewKeysObject(space, self) - - def descr_viewvalues(self, space): - """D.viewvalues() -> an object providing a view on D's values""" - return W_DictViewValuesObject(space, self) - - def descr_has_key(self, space, w_key): - """D.has_key(k) -> True if D has a key k, else False""" - return space.newbool(self.getitem(w_key) is not None) - def descr_clear(self, space): """D.clear() -> None. Remove all items from D.""" self.clear() @@ -369,10 +319,11 @@ currently_in_repr[dict_id] = 1 try: items = [] - # XXX for now, we cannot use iteritems() at app-level because - # we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in dict.items(d): + # XXX for now, we cannot use items() without list at + # app-level because we want a reasonable result instead + # of a RuntimeError even if the dict is mutated by the + # repr() in the loop. + for k, v in list(dict.items(d)): items.append(repr(k) + ": " + repr(v)) return "{" + ', '.join(items) + "}" finally: @@ -404,10 +355,6 @@ __eq__ = interp2app(W_DictMultiObject.descr_eq), __ne__ = interp2app(W_DictMultiObject.descr_ne), - __lt__ = interp2app(W_DictMultiObject.descr_lt), - __le__ = interp2app(W_DictMultiObject.descr_le), - __gt__ = interp2app(W_DictMultiObject.descr_gt), - __ge__ = interp2app(W_DictMultiObject.descr_ge), __len__ = interp2app(W_DictMultiObject.descr_len), __iter__ = interp2app(W_DictMultiObject.descr_iter), @@ -422,13 +369,10 @@ items = interp2app(W_DictMultiObject.descr_items), keys = interp2app(W_DictMultiObject.descr_keys), values = interp2app(W_DictMultiObject.descr_values), + # XXX: iteritems = interp2app(W_DictMultiObject.descr_iteritems), iterkeys = interp2app(W_DictMultiObject.descr_iterkeys), itervalues = interp2app(W_DictMultiObject.descr_itervalues), - viewkeys = interp2app(W_DictMultiObject.descr_viewkeys), - viewitems = interp2app(W_DictMultiObject.descr_viewitems), - viewvalues = interp2app(W_DictMultiObject.descr_viewvalues), - has_key = interp2app(W_DictMultiObject.descr_has_key), clear = interp2app(W_DictMultiObject.descr_clear), get = interp2app(W_DictMultiObject.descr_get), pop = interp2app(W_DictMultiObject.descr_pop), @@ -1106,29 +1050,6 @@ if space.is_true(w_kwds): update1(space, w_dict, w_kwds) -def characterize(space, w_a, w_b): - """(similar to CPython) - returns the smallest key in acontent for which b's value is - different or absent and this value""" - w_smallest_diff_a_key = None - w_its_value = None - iteratorimplementation = w_a.iteritems() - while True: - w_key, w_val = iteratorimplementation.next_item() - if w_key is None: - break - if w_smallest_diff_a_key is None or space.is_true(space.lt( - w_key, w_smallest_diff_a_key)): - w_bvalue = w_b.getitem(w_key) - if w_bvalue is None: - w_its_value = w_val - w_smallest_diff_a_key = w_key - else: - if not space.eq_w(w_val, w_bvalue): - w_its_value = w_val - w_smallest_diff_a_key = w_key - return w_smallest_diff_a_key, w_its_value - # ____________________________________________________________ # Iteration @@ -1161,7 +1082,7 @@ This is of course not the standard way. XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. + a registration with copyreg, instead. """ w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) @@ -1225,21 +1146,21 @@ W_DictMultiIterItemsObject.typedef = StdTypeDef( "dict_iteritems", __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), - next = interp2app(W_DictMultiIterItemsObject.descr_next), + __next__ = interp2app(W_DictMultiIterItemsObject.descr_next), __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterKeysObject.typedef = StdTypeDef( "dict_iterkeys", __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), - next = interp2app(W_DictMultiIterKeysObject.descr_next), + __next__ = interp2app(W_DictMultiIterKeysObject.descr_next), __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterValuesObject.typedef = StdTypeDef( "dict_itervalues", __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), - next = interp2app(W_DictMultiIterValuesObject.descr_next), + __next__ = interp2app(W_DictMultiIterValuesObject.descr_next), __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) @@ -1252,10 +1173,10 @@ w_self.w_dict = w_dict def descr_repr(self, space): + typename = space.type(self).getname(space).decode('utf-8') w_seq = space.call_function(space.w_list, self) - w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(self).getname(space), - space.str_w(w_repr))) + seq_repr = space.unicode_w(space.repr(w_seq)) + return space.wrap(u"%s(%s)" % (typename, seq_repr)) def descr_len(self, space): return space.len(self.w_dict) @@ -1321,6 +1242,27 @@ return _all_contained_in(space, w_other, self) return space.w_False + def descr_isdisjoint(self, space, w_other): + """"Return True if the view and the given iterable have a null + intersection. + """ + if self is w_other: + return space.newbool(space.len_w(self) == 0) + + if _is_set_like(w_other): + # if w_other is set-like and it's longer, we iterate over + # self instead + len_self = space.len_w(self) + len_other = space.len_w(w_other) + if len_other > len_self: + self, w_other = w_other, self + + w_iter = space.iter(w_other) + for w_item in space.iteriterable(w_iter): + if space.is_true(space.contains(self, w_item)): + return space.w_False + return space.w_True + def _as_set_op(name, methname): @func_renamer('descr_' + name) def op(self, space, w_other): @@ -1372,6 +1314,7 @@ __ror__ = interp2app(W_DictViewItemsObject.descr_ror), __xor__ = interp2app(W_DictViewItemsObject.descr_xor), __rxor__ = interp2app(W_DictViewItemsObject.descr_rxor), + isdisjoint = interp2app(W_DictViewItemsObject.descr_isdisjoint), ) W_DictViewKeysObject.typedef = StdTypeDef( @@ -1395,6 +1338,7 @@ __ror__ = interp2app(W_DictViewKeysObject.descr_ror), __xor__ = interp2app(W_DictViewKeysObject.descr_xor), __rxor__ = interp2app(W_DictViewKeysObject.descr_rxor), + isdisjoint = interp2app(W_DictViewKeysObject.descr_isdisjoint), ) W_DictViewValuesObject.typedef = StdTypeDef( From noreply at buildbot.pypy.org Sat May 18 23:33:18 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 18 May 2013 23:33:18 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill py2's dict iter methods, and dicts are now unorderable Message-ID: <20130518213318.23DB81C12F3@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64294:206e3e4d5b47 Date: 2013-05-18 14:32 -0700 http://bitbucket.org/pypy/pypy/changeset/206e3e4d5b47/ Log: kill py2's dict iter methods, and dicts are now unorderable diff --git a/lib_pypy/_ctypes/pointer.py b/lib_pypy/_ctypes/pointer.py --- a/lib_pypy/_ctypes/pointer.py +++ b/lib_pypy/_ctypes/pointer.py @@ -28,7 +28,7 @@ # XXX check if typedict['_type_'] is any sane # XXX remember about paramfunc obj = type.__new__(self, name, cls, typedict) - for k, v in d.iteritems(): + for k, v in d.items(): setattr(obj, k, v) if '_type_' in typedict: self.set_type(obj, typedict['_type_']) diff --git a/lib_pypy/_functools.py b/lib_pypy/_functools.py --- a/lib_pypy/_functools.py +++ b/lib_pypy/_functools.py @@ -60,7 +60,7 @@ return "{}({})".format(name, ', '.join(tmp)) def __reduce__(self): - d = dict((k, v) for k, v in self.__dict__.iteritems() if k not in + d = dict((k, v) for k, v in self.__dict__.items() if k not in ('func', 'args', 'keywords')) if len(d) == 0: d = None diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -224,18 +224,6 @@ """D.values() -> an object providing a view on D's values""" return W_DictViewValuesObject(space, self) - def descr_iteritems(self, space): - """D.iteritems() -> an iterator over the (key, value) items of D""" - return W_DictMultiIterItemsObject(space, self.iteritems()) - - def descr_iterkeys(self, space): - """D.iterkeys() -> an iterator over the keys of D""" - return W_DictMultiIterKeysObject(space, self.iterkeys()) - - def descr_itervalues(self, space): - """D.itervalues() -> an iterator over the values of D""" - return W_DictMultiIterValuesObject(space, self.itervalues()) - def descr_clear(self, space): """D.clear() -> None. Remove all items from D.""" self.clear() @@ -369,10 +357,6 @@ items = interp2app(W_DictMultiObject.descr_items), keys = interp2app(W_DictMultiObject.descr_keys), values = interp2app(W_DictMultiObject.descr_values), - # XXX: - iteritems = interp2app(W_DictMultiObject.descr_iteritems), - iterkeys = interp2app(W_DictMultiObject.descr_iterkeys), - itervalues = interp2app(W_DictMultiObject.descr_itervalues), clear = interp2app(W_DictMultiObject.descr_clear), get = interp2app(W_DictMultiObject.descr_get), pop = interp2app(W_DictMultiObject.descr_pop), @@ -1144,21 +1128,21 @@ raise OperationError(space.w_StopIteration, space.w_None) W_DictMultiIterItemsObject.typedef = StdTypeDef( - "dict_iteritems", + "dict_itemiterator", __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), __next__ = interp2app(W_DictMultiIterItemsObject.descr_next), __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterKeysObject.typedef = StdTypeDef( - "dict_iterkeys", + "dict_keyiterator", __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), __next__ = interp2app(W_DictMultiIterKeysObject.descr_next), __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) ) W_DictMultiIterValuesObject.typedef = StdTypeDef( - "dict_itervalues", + "dict_valueiterator", __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), __next__ = interp2app(W_DictMultiIterValuesObject.descr_next), __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -238,7 +238,7 @@ def test_iteritems(self): d = {1: 2, 3: 4} dd = d.copy() - for k, v in d.iteritems(): + for k, v in d.items(): assert v == dd[k] del dd[k] assert not dd @@ -246,14 +246,14 @@ def test_iterkeys(self): d = {1: 2, 3: 4} dd = d.copy() - for k in d.iterkeys(): + for k in d.keys(): del dd[k] assert not dd def test_itervalues(self): d = {1: 2, 3: 4} values = [] - for k in d.itervalues(): + for k in d.values(): values.append(k) assert values == list(d.values()) @@ -397,24 +397,6 @@ f = getattr(operator, op) raises(TypeError, f, d1, d2) - def test_other_rich_cmp(self): - d1 = {1: 2, 3: 4} - d2 = {1: 2, 3: 4} - d3 = {1: 2, 3: 5} - d4 = {1: 2} - - assert d1 <= d2 - assert d1 <= d3 - assert not d1 <= d4 - - assert not d1 > d2 - assert not d1 > d3 - assert d1 > d4 - - assert d1 >= d2 - assert not d1 >= d3 - assert d1 >= d4 - def test_str_repr(self): assert '{}' == str({}) assert '{1: 2}' == str({1: 2}) @@ -613,10 +595,6 @@ def test_bytes_keys(self): assert isinstance(list({b'a': 1})[0], bytes) - - def test_cmp_with_noncmp(self): - assert not {} > object() - class AppTest_DictMultiObject(AppTest_DictObject): def test_emptydict_unhashable(self): @@ -997,14 +975,14 @@ def test_iter_dict_length_change(self): d = {1: 2, 3: 4, 5: 6} - it = d.iteritems() + it = iter(d.items()) d[7] = 8 # 'd' is now length 4 - raises(RuntimeError, it.__next__) + raises(RuntimeError, next, it) def test_iter_dict_strategy_only_change_1(self): d = {1: 2, 3: 4, 5: 6} - it = d.iteritems() + it = d.items() class Foo(object): def __eq__(self, other): return False @@ -1016,7 +994,7 @@ def test_iter_dict_strategy_only_change_2(self): d = {1: 2, 3: 4, 5: 6} - it = d.iteritems() + it = d.items() d['foo'] = 'bar' del d[1] # on default the strategy changes and thus we get the RuntimeError From noreply at buildbot.pypy.org Sun May 19 01:18:04 2013 From: noreply at buildbot.pypy.org (stefanor) Date: Sun, 19 May 2013 01:18:04 +0200 (CEST) Subject: [pypy-commit] pypy default: Oops, delete that test too. It will only return -1 *on* ARM Message-ID: <20130518231804.108E81C01CD@cobra.cs.uni-duesseldorf.de> Author: Stefano Rivera Branch: Changeset: r64295:658619199c14 Date: 2013-05-19 01:17 +0200 http://bitbucket.org/pypy/pypy/changeset/658619199c14/ Log: Oops, delete that test too. It will only return -1 *on* ARM diff --git a/rpython/memory/gc/test/test_env.py b/rpython/memory/gc/test/test_env.py --- a/rpython/memory/gc/test/test_env.py +++ b/rpython/memory/gc/test/test_env.py @@ -161,7 +161,3 @@ """) result = env.get_L2cache_linux2_cpuinfo(str(filepath)) assert result == 3072 * 1024 - -def test_estimate_best_nursery_size_linux2_arm(): - result = env.get_L2cache_linux2() - assert result == -1 From noreply at buildbot.pypy.org Sun May 19 01:35:01 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 01:35:01 +0200 (CEST) Subject: [pypy-commit] pypy default: fix: isinstance fails against mixins Message-ID: <20130518233501.842291C01D1@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64296:117fde40e6a8 Date: 2013-05-18 16:20 -0700 http://bitbucket.org/pypy/pypy/changeset/117fde40e6a8/ Log: fix: isinstance fails against mixins diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1267,7 +1267,8 @@ def _is_set_like(w_other): from pypy.objspace.std.setobject import W_BaseSetObject return (isinstance(w_other, W_BaseSetObject) or - isinstance(w_other, SetLikeDictView)) + isinstance(w_other, W_DictViewKeysObject) or + isinstance(w_other, W_DictViewItemsObject)) class SetLikeDictView(object): _mixin_ = True From noreply at buildbot.pypy.org Sun May 19 01:35:02 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 01:35:02 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill Message-ID: <20130518233502.E0B721C01D1@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64297:1f020dbe6b02 Date: 2013-05-18 16:34 -0700 http://bitbucket.org/pypy/pypy/changeset/1f020dbe6b02/ Log: kill diff --git a/pypy/module/_collections/app_defaultdict.py b/pypy/module/_collections/app_defaultdict.py --- a/pypy/module/_collections/app_defaultdict.py +++ b/pypy/module/_collections/app_defaultdict.py @@ -63,4 +63,4 @@ This API is used by pickle.py and copy.py. """ - return (type(self), (self._default_factory,), None, None, self.iteritems()) + return (type(self), (self._default_factory,), None, None, self.items()) diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -679,7 +679,7 @@ def test_sizes_and_alignments(self): import _rawffi - for k, (s, a) in self.sizes_and_alignments.iteritems(): + for k, (s, a) in self.sizes_and_alignments.items(): assert _rawffi.sizeof(k) == s assert _rawffi.alignment(k) == a diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py --- a/pypy/module/cpyext/dictobject.py +++ b/pypy/module/cpyext/dictobject.py @@ -175,7 +175,7 @@ # not complete. try: - w_iter = space.call_method(w_dict, "iteritems") + w_iter = space.call_method(w_dict, "items") pos = ppos[0] while pos: space.next(w_iter) diff --git a/pypy/module/errno/test/test_errno.py b/pypy/module/errno/test/test_errno.py --- a/pypy/module/errno/test/test_errno.py +++ b/pypy/module/errno/test/test_errno.py @@ -11,7 +11,7 @@ assert self.errno.__file__ def test_constants(self): - for code, name in self.errorcode.iteritems(): + for code, name in self.errorcode.items(): assert getattr(self.errno, name) == code def test_errorcode(self): diff --git a/pypy/objspace/std/test/test_kwargsdict.py b/pypy/objspace/std/test/test_kwargsdict.py --- a/pypy/objspace/std/test/test_kwargsdict.py +++ b/pypy/objspace/std/test/test_kwargsdict.py @@ -146,7 +146,7 @@ return args assert dict.fromkeys(f(a=2, b=3)) == {"a": None, "b": None} - assert sorted(f(a=2, b=3).itervalues()) == [2, 3] + assert sorted(f(a=2, b=3).values()) == [2, 3] def test_setdefault(self): py3k_skip("XXX: strategies are currently broken") diff --git a/pypy/objspace/std/test/test_lengthhint.py b/pypy/objspace/std/test/test_lengthhint.py --- a/pypy/objspace/std/test/test_lengthhint.py +++ b/pypy/objspace/std/test/test_lengthhint.py @@ -41,7 +41,7 @@ space = self.space w_iterkeys, w_mutate = space.fixedview(space.appexec([], """(): d = dict.fromkeys(%r) - return d.iterkeys(), d.popitem + return d.keys(), d.popitem """ % self.ITEMS), 2) self._test_length_hint(w_iterkeys, w_mutate) @@ -49,7 +49,7 @@ space = self.space w_itervalues, w_mutate = space.fixedview(space.appexec([], """(): d = dict.fromkeys(%r) - return d.itervalues(), d.popitem + return d.values(), d.popitem """ % self.ITEMS), 2) self._test_length_hint(w_itervalues, w_mutate) diff --git a/pypy/objspace/std/unicodetype.py b/pypy/objspace/std/unicodetype.py --- a/pypy/objspace/std/unicodetype.py +++ b/pypy/objspace/std/unicodetype.py @@ -348,7 +348,7 @@ "if you give only one argument " "to maketrans it must be a dict")) # copy entries into the new dict, converting string keys to int keys - w_iter = space.call_method(w_x, "iteritems") + w_iter = space.call_method(w_x, "items") while True: try: w_item = space.next(w_iter) From noreply at buildbot.pypy.org Sun May 19 01:37:46 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 01:37:46 +0200 (CEST) Subject: [pypy-commit] pypy default: fold lists of constants into a constant tuple in the AST Message-ID: <20130518233746.33B401C01CD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64298:a9007a4abb78 Date: 2013-05-18 16:37 -0700 http://bitbucket.org/pypy/pypy/changeset/a9007a4abb78/ Log: fold lists of constants into a constant tuple in the AST diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -853,9 +853,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -864,6 +865,30 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists of constants in the context of "in"/"not in". + + lists are folded into tuples, otherwise returns False + """ + if op in (ast.In, ast.NotIn) and isinstance(node, ast.List): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -973,3 +973,16 @@ counts = self.count_instructions(source3) assert counts[ops.BUILD_LIST] == 1 assert ops.BUILD_LIST_FROM_ARG not in counts + + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -936,6 +936,13 @@ output = s.getvalue() assert "LOAD_GLOBAL" not in output + def test_folding_of_list_constants(self): + source = 'a in [1, 2, 3]' + co = compile(source, '', 'exec') + i = co.co_consts.index((1, 2, 3)) + assert i > -1 + assert isinstance(co.co_consts[i], tuple) + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} From noreply at buildbot.pypy.org Sun May 19 01:51:59 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 01:51:59 +0200 (CEST) Subject: [pypy-commit] pypy default: fold sets of constants into frozensets in the AST too. from cpython 3.x Message-ID: <20130518235159.1FF321C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64299:56d0fccb8339 Date: 2013-05-18 16:51 -0700 http://bitbucket.org/pypy/pypy/changeset/56d0fccb8339/ Log: fold sets of constants into frozensets in the AST too. from cpython 3.x (cpython 2.7 doesn't have it) diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -866,15 +866,22 @@ self.use_next_block(end) def _optimize_comparator(self, op, node): - """Fold lists of constants in the context of "in"/"not in". + """Fold lists/sets of constants in the context of "in"/"not in". - lists are folded into tuples, otherwise returns False + lists are folded into tuples, sets into frozensets, otherwise + returns False """ - if op in (ast.In, ast.NotIn) and isinstance(node, ast.List): - w_const = self._tuple_of_consts(node.elts) - if w_const is not None: - self.load_const(w_const) - return True + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True return False def _tuple_of_consts(self, elts): diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -986,3 +986,17 @@ counts = self.count_instructions(source) assert ops.BUILD_LIST not in counts assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -943,6 +943,14 @@ assert i > -1 assert isinstance(co.co_consts[i], tuple) + def test_folding_of_set_constants(self): + source = 'a in {1, 2, 3}' + co = compile(source, '', 'exec') + i = co.co_consts.index(set([1, 2, 3])) + assert i > -1 + assert isinstance(co.co_consts[i], frozenset) + + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} From noreply at buildbot.pypy.org Sun May 19 01:52:31 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 01:52:31 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130518235231.BF9AE1C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64300:0b33c638a659 Date: 2013-05-18 16:42 -0700 http://bitbucket.org/pypy/pypy/changeset/0b33c638a659/ Log: merge default diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -916,9 +916,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -927,6 +928,30 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists of constants in the context of "in"/"not in". + + lists are folded into tuples, otherwise returns False + """ + if op in (ast.In, ast.NotIn) and isinstance(node, ast.List): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -1046,3 +1046,15 @@ """) assert 'generator' in space.str_w(space.repr(w_generator)) + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -1047,6 +1047,13 @@ output = s.getvalue() assert "LOAD_GLOBAL" not in output + def test_folding_of_list_constants(self): + source = 'a in [1, 2, 3]' + co = compile(source, '', 'exec') + i = co.co_consts.index((1, 2, 3)) + assert i > -1 + assert isinstance(co.co_consts[i], tuple) + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1167,13 +1167,7 @@ def _all_contained_in(space, w_dictview, w_other): w_iter = space.iter(w_dictview) - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break + for w_item in space.iteriterable(w_iter): if not space.is_true(space.contains(w_other, w_item)): return space.w_False return space.w_True @@ -1181,7 +1175,8 @@ def _is_set_like(w_other): from pypy.objspace.std.setobject import W_BaseSetObject return (isinstance(w_other, W_BaseSetObject) or - isinstance(w_other, SetLikeDictView)) + isinstance(w_other, W_DictViewKeysObject) or + isinstance(w_other, W_DictViewItemsObject)) class SetLikeDictView(object): _mixin_ = True diff --git a/rpython/memory/gc/test/test_env.py b/rpython/memory/gc/test/test_env.py --- a/rpython/memory/gc/test/test_env.py +++ b/rpython/memory/gc/test/test_env.py @@ -161,7 +161,3 @@ """) result = env.get_L2cache_linux2_cpuinfo(str(filepath)) assert result == 3072 * 1024 - -def test_estimate_best_nursery_size_linux2_arm(): - result = env.get_L2cache_linux2() - assert result == -1 From noreply at buildbot.pypy.org Sun May 19 01:52:33 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 01:52:33 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130518235233.158B01C1241@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64301:f4dfafbc4ac8 Date: 2013-05-18 16:51 -0700 http://bitbucket.org/pypy/pypy/changeset/f4dfafbc4ac8/ Log: merge default diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -929,15 +929,22 @@ self.use_next_block(end) def _optimize_comparator(self, op, node): - """Fold lists of constants in the context of "in"/"not in". + """Fold lists/sets of constants in the context of "in"/"not in". - lists are folded into tuples, otherwise returns False + lists are folded into tuples, sets into frozensets, otherwise + returns False """ - if op in (ast.In, ast.NotIn) and isinstance(node, ast.List): - w_const = self._tuple_of_consts(node.elts) - if w_const is not None: - self.load_const(w_const) - return True + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True return False def _tuple_of_consts(self, elts): diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -1058,3 +1058,17 @@ counts = self.count_instructions(source) assert ops.BUILD_LIST not in counts assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -1054,6 +1054,14 @@ assert i > -1 assert isinstance(co.co_consts[i], tuple) + def test_folding_of_set_constants(self): + source = 'a in {1, 2, 3}' + co = compile(source, '', 'exec') + i = co.co_consts.index(set([1, 2, 3])) + assert i > -1 + assert isinstance(co.co_consts[i], frozenset) + + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} From noreply at buildbot.pypy.org Sun May 19 02:07:28 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 02:07:28 +0200 (CEST) Subject: [pypy-commit] pypy default: make the broken dictiter reduce less broken (but still broken) Message-ID: <20130519000728.235131C10FA@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64302:15a1cc1604b3 Date: 2013-05-18 17:05 -0700 http://bitbucket.org/pypy/pypy/changeset/15a1cc1604b3/ Log: make the broken dictiter reduce less broken (but still broken) diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1163,7 +1163,7 @@ w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) + w_typeobj = space.type(self) raise OperationError( space.w_TypeError, @@ -1171,12 +1171,15 @@ # XXXXXX get that working again # we cannot call __init__ since we don't have the original dict - if isinstance(self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + if isinstance(self, W_DictMultiIterKeysObject): + w_clone = space.allocate_instance(W_DictMultiIterKeysObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterValuesObject): + w_clone = space.allocate_instance(W_DictMultiIterValuesObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterItemsObject): + w_clone = space.allocate_instance(W_DictMultiIterItemsObject, + w_typeobj) else: msg = "unsupported dictiter type '%s' during pickling" % (self,) raise OperationError(space.w_TypeError, space.wrap(msg)) @@ -1223,21 +1226,24 @@ "dict_iteritems", __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), next = interp2app(W_DictMultiIterItemsObject.descr_next), - __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) W_DictMultiIterKeysObject.typedef = StdTypeDef( "dict_iterkeys", __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), next = interp2app(W_DictMultiIterKeysObject.descr_next), - __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) W_DictMultiIterValuesObject.typedef = StdTypeDef( "dict_itervalues", __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), next = interp2app(W_DictMultiIterValuesObject.descr_next), - __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) From noreply at buildbot.pypy.org Sun May 19 02:07:29 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 02:07:29 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130519000729.6D4F01C10FA@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64303:d1bd8ee630b6 Date: 2013-05-18 17:06 -0700 http://bitbucket.org/pypy/pypy/changeset/d1bd8ee630b6/ Log: merge default diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1071,7 +1071,7 @@ w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) + w_typeobj = space.type(self) raise OperationError( space.w_TypeError, @@ -1079,12 +1079,15 @@ # XXXXXX get that working again # we cannot call __init__ since we don't have the original dict - if isinstance(self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + if isinstance(self, W_DictMultiIterKeysObject): + w_clone = space.allocate_instance(W_DictMultiIterKeysObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterValuesObject): + w_clone = space.allocate_instance(W_DictMultiIterValuesObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterItemsObject): + w_clone = space.allocate_instance(W_DictMultiIterItemsObject, + w_typeobj) else: msg = "unsupported dictiter type '%s' during pickling" % (self,) raise OperationError(space.w_TypeError, space.wrap(msg)) @@ -1131,21 +1134,24 @@ "dict_itemiterator", __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), __next__ = interp2app(W_DictMultiIterItemsObject.descr_next), - __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) W_DictMultiIterKeysObject.typedef = StdTypeDef( "dict_keyiterator", __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), __next__ = interp2app(W_DictMultiIterKeysObject.descr_next), - __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) W_DictMultiIterValuesObject.typedef = StdTypeDef( "dict_valueiterator", __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), __next__ = interp2app(W_DictMultiIterValuesObject.descr_next), - __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) From noreply at buildbot.pypy.org Sun May 19 03:06:02 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 03:06:02 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill more py2 dict iters Message-ID: <20130519010602.06EDD1C1260@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64304:253f29c79ec2 Date: 2013-05-18 18:05 -0700 http://bitbucket.org/pypy/pypy/changeset/253f29c79ec2/ Log: kill more py2 dict iters diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -573,7 +573,7 @@ append = components.append level += 1 saferepr = _safe_repr - for k, v in object.iteritems(): + for k, v in object.items(): krepr, kreadable, krecur = saferepr(k, context, maxlevels, level) vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level) append("%s: %s" % (krepr, vrepr)) @@ -679,13 +679,13 @@ self.assert_(hasattr(iter, '__iter__')) x = list(iter) self.assert_(set(x)==set(lst)==set(ref)) - check_iterandlist(d.iterkeys(), d.keys(), self.reference.keys()) + check_iterandlist(iter(d.keys()), d.keys(), self.reference.keys()) check_iterandlist(iter(d), d.keys(), self.reference.keys()) - check_iterandlist(d.itervalues(), d.values(), self.reference.values()) - check_iterandlist(d.iteritems(), d.items(), self.reference.items()) + check_iterandlist(iter(d.values()), d.values(), self.reference.values()) + check_iterandlist(iter(d.items()), d.items(), self.reference.items()) #get - key, value = next(d.iteritems()) - knownkey, knownvalue = next(self.other.iteritems()) + key, value = next(iter(d.items())) + knownkey, knownvalue = next(iter(self.other.items())) self.assertEqual(d.get(key, knownvalue), value) self.assertEqual(d.get(knownkey, knownvalue), knownvalue) self.failIf(knownkey in d) From noreply at buildbot.pypy.org Sun May 19 03:06:03 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 03:06:03 +0200 (CEST) Subject: [pypy-commit] pypy py3k: oops, expecting actual iterators Message-ID: <20130519010603.4B9501C12F3@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64305:adc5e19b5567 Date: 2013-05-18 18:05 -0700 http://bitbucket.org/pypy/pypy/changeset/adc5e19b5567/ Log: oops, expecting actual iterators diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py --- a/pypy/module/cpyext/dictobject.py +++ b/pypy/module/cpyext/dictobject.py @@ -175,7 +175,7 @@ # not complete. try: - w_iter = space.call_method(w_dict, "items") + w_iter = space.iter(space.call_method(w_dict, "items")) pos = ppos[0] while pos: space.next(w_iter) diff --git a/pypy/objspace/std/unicodetype.py b/pypy/objspace/std/unicodetype.py --- a/pypy/objspace/std/unicodetype.py +++ b/pypy/objspace/std/unicodetype.py @@ -348,7 +348,7 @@ "if you give only one argument " "to maketrans it must be a dict")) # copy entries into the new dict, converting string keys to int keys - w_iter = space.call_method(w_x, "items") + w_iter = space.iter(space.call_method(w_x, "items")) while True: try: w_item = space.next(w_iter) From noreply at buildbot.pypy.org Sun May 19 03:24:32 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 03:24:32 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill Message-ID: <20130519012432.5D4411C10FA@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64306:1a50c0638c3d Date: 2013-05-18 18:22 -0700 http://bitbucket.org/pypy/pypy/changeset/1a50c0638c3d/ Log: kill diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py b/pypy/interpreter/test/test_zzpickle_and_slow.py --- a/pypy/interpreter/test/test_zzpickle_and_slow.py +++ b/pypy/interpreter/test/test_zzpickle_and_slow.py @@ -509,6 +509,22 @@ result = pickle.loads(pckl) assert pack.mod is result + def test_dict_subclass(self): + import pickle + import sys + import types + sys.modules['mod'] = mod = types.ModuleType('mod') + try: + class MyDict(dict): + __module__ = 'mod' + mod.MyDict = MyDict + obj = MyDict() + pckl = pickle.dumps(obj) + result = pickle.loads(pckl) + assert obj == result + finally: + del sys.modules['mod'] + class AppTestGeneratorCloning: diff --git a/pypy/module/oracle/interp_cursor.py b/pypy/module/oracle/interp_cursor.py --- a/pypy/module/oracle/interp_cursor.py +++ b/pypy/module/oracle/interp_cursor.py @@ -591,7 +591,7 @@ if self.bindDict is None: self.bindDict = space.newdict() - items = space.fixedview(space.call_method(w_vars, "iteritems")) + items = space.fixedview(space.call_method(w_vars, "items")) for item in items: w_key, w_value = space.fixedview(item, 2) origVar = space.finditem(self.bindDict, w_key) @@ -670,7 +670,7 @@ var.bind(space, self, None, i + 1) if self.bindDict: items_w = space.fixedview( - space.call_method(self.bindDict, "iteritems")) + space.call_method(self.bindDict, "items")) for w_item in items_w: w_key, var = space.fixedview(w_item, 2) assert isinstance(var, interp_variable.W_Variable) diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -168,7 +168,7 @@ listitems = None if isinstance(obj, dict): - dictitems = obj.iteritems() + dictitems = iter(obj.items()) else: dictitems = None From noreply at buildbot.pypy.org Sun May 19 11:11:45 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 19 May 2013 11:11:45 +0200 (CEST) Subject: [pypy-commit] pypy default: fix test_setup_bootstrap_path in the case we are not supposed to find the stdlib Message-ID: <20130519091145.A65401C01CD@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64307:20c6bdafbddc Date: 2013-05-19 11:10 +0200 http://bitbucket.org/pypy/pypy/changeset/20c6bdafbddc/ Log: fix test_setup_bootstrap_path in the case we are not supposed to find the stdlib 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 @@ -903,24 +903,35 @@ expected_path = [str(prefix.join(subdir).ensure(dir=1)) for subdir in ('lib_pypy', 'lib-python/%s' % cpy_ver)] + # an empty directory from where we can't find the stdlib + tmp_dir = str(udir.join('tmp').ensure(dir=1)) self.w_goal_dir = self.space.wrap(goal_dir) self.w_fake_exe = self.space.wrap(str(fake_exe)) self.w_expected_path = self.space.wrap(expected_path) self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir)) + self.w_tmp_dir = self.space.wrap(tmp_dir) + foo_py = prefix.join('foo.py').write("pass") self.w_foo_py = self.space.wrap(str(foo_py)) def test_setup_bootstrap_path(self): - import sys + # Check how sys.path is handled depending on if we can find a copy of + # the stdlib in setup_bootstrap_path. + import sys, os old_sys_path = sys.path[:] + old_cwd = os.getcwd() + sys.path.append(self.goal_dir) + # make sure cwd does not contain a stdlib + os.chdir(self.tmp_dir) + tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c') try: import app_main - app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found + app_main.setup_bootstrap_path(tmp_pypy_c) # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + assert sys.path == old_sys_path + [self.goal_dir] app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe @@ -933,6 +944,7 @@ assert newpath[:len(self.expected_path)] == self.expected_path finally: sys.path[:] = old_sys_path + os.chdir(old_cwd) def test_trunk_can_be_prefix(self): import sys From noreply at buildbot.pypy.org Sun May 19 11:11:47 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 19 May 2013 11:11:47 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130519091147.EC18B1C01CD@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64308:2708b1ed0639 Date: 2013-05-19 11:10 +0200 http://bitbucket.org/pypy/pypy/changeset/2708b1ed0639/ Log: merge heads diff too long, truncating to 2000 out of 2290 lines diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python 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 @@ -19,3 +19,6 @@ .. branch: numpy-subarrays Implement subarrays for numpy + +.. branch: remove-dict-smm +Remove multi-methods on dict diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -10,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -120,6 +122,15 @@ source = rffi.charp2str(ll_source) return _pypy_execute_source(source) + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + rthread.gc_thread_start() + w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), space.builtin_modules['__builtin__']) @@ -137,6 +148,8 @@ return 0 return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, 'pypy_setup_home': pypy_setup_home} def call_finish(space): diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -853,9 +853,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -864,6 +865,37 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists/sets of constants in the context of "in"/"not in". + + lists are folded into tuples, sets into frozensets, otherwise + returns False + """ + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -973,3 +973,30 @@ counts = self.count_instructions(source3) assert counts[ops.BUILD_LIST] == 1 assert ops.BUILD_LIST_FROM_ARG not in counts + + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -936,6 +936,21 @@ output = s.getvalue() assert "LOAD_GLOBAL" not in output + def test_folding_of_list_constants(self): + source = 'a in [1, 2, 3]' + co = compile(source, '', 'exec') + i = co.co_consts.index((1, 2, 3)) + assert i > -1 + assert isinstance(co.co_consts[i], tuple) + + def test_folding_of_set_constants(self): + source = 'a in {1, 2, 3}' + co = compile(source, '', 'exec') + i = co.co_consts.index(set([1, 2, 3])) + assert i > -1 + assert isinstance(co.co_consts[i], frozenset) + + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,24 +1,25 @@ -import py, sys -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.setobject import set_typedef as settypedef -from pypy.objspace.std.setobject import frozenset_typedef as frozensettypedef +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import ( + WrappedDefault, applevel, interp2app, unwrap_spec) +from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef -from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint +from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null -from rpython.tool.sourcetools import func_with_new_name +from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize +from rpython.tool.sourcetools import func_renamer, func_with_new_name -from rpython.rlib import rerased, jit UNROLL_CUTOFF = 5 + def _is_str(space, w_key): return space.is_w(space.type(w_key), space.w_str) def _never_equal_to_string(space, w_lookup_type): - """ Handles the case of a non string key lookup. + """Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. XXX The types should provide such a flag. """ @@ -32,7 +33,7 @@ @specialize.call_location() def w_dict_unrolling_heuristic(w_dct): - """ In which cases iterating over dict items can be unrolled. + """In which cases iterating over dict items can be unrolled. Note that w_dct is an instance of W_DictMultiObject, not necesarilly an actual dict """ @@ -40,13 +41,24 @@ w_dct.length() <= UNROLL_CUTOFF) -class W_DictMultiObject(W_Object): - from pypy.objspace.std.dicttype import dict_typedef as typedef +def negate(f): + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator +class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, - instance=False, strdict=False, kwargs=False): - + instance=False, strdict=False, + kwargs=False): if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None @@ -56,11 +68,9 @@ elif space.config.objspace.std.withmapdict and instance: from pypy.objspace.std.mapdict import MapDictStrategy strategy = space.fromcache(MapDictStrategy) - elif instance or strdict or module: assert w_type is None strategy = space.fromcache(StringDictStrategy) - elif kwargs: assert w_type is None from pypy.objspace.std.kwargsdict import EmptyKwargsDictStrategy @@ -81,7 +91,7 @@ self.dstorage = storage def __repr__(w_self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): @@ -94,12 +104,10 @@ def missing_method(w_dict, space, w_key): if not space.is_w(space.type(w_dict), space.w_dict): - w_missing = space.lookup(w_dict, "__missing__") - if w_missing is None: - return None - return space.get_and_call_function(w_missing, w_dict, w_key) - else: - return None + w_missing = space.lookup(w_dict, '__missing__') + if w_missing is not None: + return space.get_and_call_function(w_missing, w_dict, w_key) + return None def initialize_content(w_self, list_pairs_w): for w_k, w_v in list_pairs_w: @@ -108,6 +116,228 @@ def setitem_str(self, key, w_value): self.strategy.setitem_str(self, key, w_value) + @staticmethod + def descr_new(space, w_dicttype, __args__): + w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) + return w_obj + + @staticmethod + def descr_fromkeys(space, w_type, w_keys, w_fill=None): + if w_fill is None: + w_fill = space.w_None + if space.is_w(w_type, space.w_dict): + w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) + + strlist = space.listview_str(w_keys) + if strlist is not None: + for key in strlist: + w_dict.setitem_str(key, w_fill) + else: + for w_key in space.listview(w_keys): + w_dict.setitem(w_key, w_fill) + else: + w_dict = space.call_function(w_type) + for w_key in space.listview(w_keys): + space.setitem(w_dict, w_key, w_fill) + return w_dict + + def descr_init(self, space, __args__): + init_or_update(space, self, __args__, 'dict') + + def descr_repr(self, space): + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return dictrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if space.is_w(self, w_other): + return space.w_True + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + + if self.length() != w_other.length(): + return space.w_False + iteratorimplementation = self.iteritems() + while True: + w_key, w_val = iteratorimplementation.next_item() + if w_key is None: + break + w_rightval = w_other.getitem(w_key) + if w_rightval is None: + return space.w_False + if not space.eq_w(w_val, w_rightval): + return space.w_False + return space.w_True + + def descr_lt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return self._compare_lt(space, w_other) + + def descr_gt(self, space, w_other): + if not isinstance(w_other, W_DictMultiObject): + return space.w_NotImplemented + return w_other._compare_lt(space, self) + + def _compare_lt(self, space, w_other): + # Different sizes, no problem + if self.length() < w_other.length(): + return space.w_True + if self.length() > w_other.length(): + return space.w_False + + # Same size + w_leftdiff, w_leftval = characterize(space, self, w_other) + if w_leftdiff is None: + return space.w_False + w_rightdiff, w_rightval = characterize(space, w_other, self) + if w_rightdiff is None: + # w_leftdiff is not None, w_rightdiff is None + return space.w_True + w_res = space.lt(w_leftdiff, w_rightdiff) + if (not space.is_true(w_res) and + space.eq_w(w_leftdiff, w_rightdiff) and + w_rightval is not None): + w_res = space.lt(w_leftval, w_rightval) + return w_res + + descr_ne = negate(descr_eq) + descr_le = negate(descr_gt) + descr_ge = negate(descr_lt) + + def descr_len(self, space): + return space.wrap(self.length()) + + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_contains(self, space, w_key): + return space.newbool(self.getitem(w_key) is not None) + + def descr_getitem(self, space, w_key): + w_value = self.getitem(w_key) + if w_value is not None: + return w_value + + w_missing_item = self.missing_method(space, w_key) + if w_missing_item is not None: + return w_missing_item + + space.raise_key_error(w_key) + + def descr_setitem(self, space, w_newkey, w_newvalue): + self.setitem(w_newkey, w_newvalue) + + def descr_delitem(self, space, w_key): + try: + self.delitem(w_key) + except KeyError: + space.raise_key_error(w_key) + + def descr_reversed(self, space): + raise OperationError(space.w_TypeError, space.wrap( + 'argument to reversed() must be a sequence')) + + def descr_copy(self, space): + """D.copy() -> a shallow copy of D""" + w_new = W_DictMultiObject.allocate_and_init_instance(space) + update1_dict_dict(space, w_new, self) + return w_new + + def descr_items(self, space): + """D.items() -> list of D's (key, value) pairs, as 2-tuples""" + return space.newlist(self.items()) + + def descr_keys(self, space): + """D.keys() -> list of D's keys""" + return self.w_keys() + + def descr_values(self, space): + """D.values() -> list of D's values""" + return space.newlist(self.values()) + + def descr_iteritems(self, space): + """D.iteritems() -> an iterator over the (key, value) items of D""" + return W_DictMultiIterItemsObject(space, self.iteritems()) + + def descr_iterkeys(self, space): + """D.iterkeys() -> an iterator over the keys of D""" + return W_DictMultiIterKeysObject(space, self.iterkeys()) + + def descr_itervalues(self, space): + """D.itervalues() -> an iterator over the values of D""" + return W_DictMultiIterValuesObject(space, self.itervalues()) + + def descr_viewitems(self, space): + """D.viewitems() -> a set-like object providing a view on D's items""" + return W_DictViewItemsObject(space, self) + + def descr_viewkeys(self, space): + """D.viewkeys() -> a set-like object providing a view on D's keys""" + return W_DictViewKeysObject(space, self) + + def descr_viewvalues(self, space): + """D.viewvalues() -> an object providing a view on D's values""" + return W_DictViewValuesObject(space, self) + + def descr_has_key(self, space, w_key): + """D.has_key(k) -> True if D has a key k, else False""" + return space.newbool(self.getitem(w_key) is not None) + + def descr_clear(self, space): + """D.clear() -> None. Remove all items from D.""" + self.clear() + + @unwrap_spec(w_default=WrappedDefault(None)) + def descr_get(self, space, w_key, w_default): + """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" + w_value = self.getitem(w_key) + return w_value if w_value is not None else w_default + + @unwrap_spec(defaults_w='args_w') + def descr_pop(self, space, w_key, defaults_w): + """D.pop(k[,d]) -> v, remove specified key and return the + corresponding value\nIf key is not found, d is returned if given, + otherwise KeyError is raised + """ + len_defaults = len(defaults_w) + if len_defaults > 1: + raise operationerrfmt(space.w_TypeError, + "pop expected at most 2 arguments, got %d", + 1 + len_defaults) + w_item = self.getitem(w_key) + if w_item is None: + if len_defaults > 0: + return defaults_w[0] + else: + space.raise_key_error(w_key) + else: + self.delitem(w_key) + return w_item + + def descr_popitem(self, space): + """D.popitem() -> (k, v), remove and return some (key, value) pair as + a\n2-tuple; but raise KeyError if D is empty""" + try: + w_key, w_value = self.popitem() + except KeyError: + raise OperationError(space.w_KeyError, + space.wrap("popitem(): dictionary is empty")) + return space.newtuple([w_key, w_value]) + + @unwrap_spec(w_default=WrappedDefault(None)) + def descr_setdefault(self, space, w_key, w_default): + """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" + return self.setdefault(w_key, w_default) + + def descr_update(self, space, __args__): + """D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] + = E[k]\n(if E has keys else: for (k, v) in E: D[k] = v) then: for k in + F: D[k] = F[k]""" + init_or_update(space, self, __args__, 'dict.update') + def _add_indirections(): dict_methods = "getitem getitem_str setitem setdefault \ @@ -128,8 +358,87 @@ _add_indirections() + +app = applevel(''' + def dictrepr(currently_in_repr, d): + if len(d) == 0: + return "{}" + dict_id = id(d) + if dict_id in currently_in_repr: + return '{...}' + currently_in_repr[dict_id] = 1 + try: + items = [] + # XXX for now, we cannot use iteritems() at app-level because + # we want a reasonable result instead of a RuntimeError + # even if the dict is mutated by the repr() in the loop. + for k, v in dict.items(d): + items.append(repr(k) + ": " + repr(v)) + return "{" + ', '.join(items) + "}" + finally: + try: + del currently_in_repr[dict_id] + except: + pass +''', filename=__file__) + +dictrepr = app.interphook("dictrepr") + + +W_DictMultiObject.typedef = StdTypeDef("dict", + __doc__ = '''dict() -> new empty dictionary. +dict(mapping) -> new dictionary initialized from a mapping object\'s + (key, value) pairs. +dict(seq) -> new dictionary initialized as if via: + d = {} + for k, v in seq: + d[k] = v +dict(**kwargs) -> new dictionary initialized with the name=value pairs + in the keyword argument list. For example: dict(one=1, two=2)''', + __new__ = interp2app(W_DictMultiObject.descr_new), + fromkeys = interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), + __hash__ = None, + __repr__ = interp2app(W_DictMultiObject.descr_repr), + __init__ = interp2app(W_DictMultiObject.descr_init), + + __eq__ = interp2app(W_DictMultiObject.descr_eq), + __ne__ = interp2app(W_DictMultiObject.descr_ne), + __lt__ = interp2app(W_DictMultiObject.descr_lt), + __le__ = interp2app(W_DictMultiObject.descr_le), + __gt__ = interp2app(W_DictMultiObject.descr_gt), + __ge__ = interp2app(W_DictMultiObject.descr_ge), + + __len__ = interp2app(W_DictMultiObject.descr_len), + __iter__ = interp2app(W_DictMultiObject.descr_iter), + __contains__ = interp2app(W_DictMultiObject.descr_contains), + + __getitem__ = interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = interp2app(W_DictMultiObject.descr_delitem), + + __reversed__ = interp2app(W_DictMultiObject.descr_reversed), + copy = interp2app(W_DictMultiObject.descr_copy), + items = interp2app(W_DictMultiObject.descr_items), + keys = interp2app(W_DictMultiObject.descr_keys), + values = interp2app(W_DictMultiObject.descr_values), + iteritems = interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = interp2app(W_DictMultiObject.descr_viewvalues), + has_key = interp2app(W_DictMultiObject.descr_has_key), + clear = interp2app(W_DictMultiObject.descr_clear), + get = interp2app(W_DictMultiObject.descr_get), + pop = interp2app(W_DictMultiObject.descr_pop), + popitem = interp2app(W_DictMultiObject.descr_popitem), + setdefault = interp2app(W_DictMultiObject.descr_setdefault), + update = interp2app(W_DictMultiObject.descr_update), + ) + + class DictStrategy(object): - def __init__(self, space): self.space = space @@ -139,7 +448,7 @@ def w_keys(self, w_dict): iterator = self.iterkeys(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key = iterator.next_key() if w_key is not None: result.append(w_key) @@ -149,7 +458,7 @@ def values(self, w_dict): iterator = self.itervalues(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_value = iterator.next_value() if w_value is not None: result.append(w_value) @@ -159,7 +468,7 @@ def items(self, w_dict): iterator = self.iteritems(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is not None: result.append(self.space.newtuple([w_key, w_value])) @@ -171,7 +480,6 @@ # it ends up taking n**2 time, because the next() calls below # will take longer and longer. But all interesting strategies # provide a better one. - space = self.space iterator = self.iteritems(w_dict) w_key, w_value = iterator.next_item() self.delitem(w_dict, w_key) @@ -195,14 +503,14 @@ def view_as_kwargs(self, w_dict): return (None, None) + class EmptyDictStrategy(DictStrategy): - erase, unerase = rerased.new_erasing_pair("empty") erase = staticmethod(erase) unerase = staticmethod(unerase) def get_empty_storage(self): - return self.erase(None) + return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): withidentitydict = self.space.config.objspace.std.withidentitydict @@ -301,21 +609,24 @@ def getiteritems(self, w_dict): return iter([(None, None)]) + # Iterator Implementation base classes def _new_next(TP): - if TP == 'key' or TP == 'value': + if TP in ('key', 'value'): EMPTY = None else: EMPTY = None, None - + def next(self): if self.dictimplementation is None: return EMPTY + space = self.space if self.len != self.dictimplementation.length(): self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed size during iteration")) + msg = "dictionary changed size during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + # look for the next entry if self.pos < self.len: result = getattr(self, 'next_' + TP + '_entry')() @@ -333,8 +644,8 @@ w_value = self.dictimplementation.getitem(w_key) if w_value is None: self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed during iteration")) + msg = "dictionary changed during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) return (w_key, w_value) # no more entries self.dictimplementation = None @@ -372,7 +683,7 @@ wrapvalue = lambda space, key : key else: wrapvalue = dictimpl.wrapvalue.im_func - + class IterClassKeys(BaseKeyIterator): def __init__(self, space, strategy, impl): self.iterator = strategy.getiterkeys(impl) @@ -424,11 +735,6 @@ create_iterator_classes(EmptyDictStrategy) -registerimplementation(W_DictMultiObject) - -# DictImplementation lattice -# XXX fix me - # concrete subclasses of the above @@ -472,7 +778,8 @@ def setdefault(self, w_dict, w_key, w_default): if self.is_correct_type(w_key): - return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), + w_default) else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) @@ -512,7 +819,7 @@ space = self.space dict_w = self.unerase(w_dict.dstorage) return [space.newtuple([self.wrap(key), w_value]) - for (key, w_value) in dict_w.iteritems()] + for (key, w_value) in dict_w.iteritems()] def popitem(self, w_dict): key, value = self.unerase(w_dict.dstorage).popitem() @@ -543,7 +850,6 @@ class ObjectDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("object") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -558,9 +864,9 @@ return True def get_empty_storage(self): - new_dict = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.erase(new_dict) + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) def _never_equal_to(self, w_lookup_type): return False @@ -576,8 +882,8 @@ create_iterator_classes(ObjectDictStrategy) + class StringDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("string") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -642,7 +948,6 @@ class UnicodeDictStrategy(AbstractTypedStrategy, DictStrategy): - erase, unerase = rerased.new_erasing_pair("unicode") erase = staticmethod(erase) unerase = staticmethod(unerase) @@ -744,9 +1049,6 @@ create_iterator_classes(IntDictStrategy) -init_signature = Signature(['seq_or_map'], None, 'kwargs') -init_defaults = [None] - def update1(space, w_dict, w_data): if space.findattr(w_data, space.wrap("keys")) is None: @@ -764,7 +1066,7 @@ w_dict_unrolling_heuristic(w_data)) def update1_dict_dict(space, w_dict, w_data): iterator = w_data.iteritems() - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is None: break @@ -788,6 +1090,9 @@ w_dict.setitem(w_key, w_value) +init_signature = Signature(['seq_or_map'], None, 'kwargs') +init_defaults = [None] + def init_or_update(space, w_dict, __args__, funcname): w_src, w_kwds = __args__.parse_obj( None, funcname, @@ -798,72 +1103,19 @@ if space.is_true(w_kwds): update1(space, w_dict, w_kwds) -def init__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict') - -def dict_update__DictMulti(space, w_dict, __args__): - init_or_update(space, w_dict, __args__, 'dict.update') - -def getitem__DictMulti_ANY(space, w_dict, w_key): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - - w_missing_item = w_dict.missing_method(space, w_key) - if w_missing_item is not None: - return w_missing_item - - space.raise_key_error(w_key) - -def setitem__DictMulti_ANY_ANY(space, w_dict, w_newkey, w_newvalue): - w_dict.setitem(w_newkey, w_newvalue) - -def delitem__DictMulti_ANY(space, w_dict, w_key): - try: - w_dict.delitem(w_key) - except KeyError: - space.raise_key_error(w_key) - -def len__DictMulti(space, w_dict): - return space.wrap(w_dict.length()) - -def contains__DictMulti_ANY(space, w_dict, w_key): - return space.newbool(w_dict.getitem(w_key) is not None) - -dict_has_key__DictMulti_ANY = contains__DictMulti_ANY - -def iter__DictMulti(space, w_dict): - return W_DictMultiIterKeysObject(space, w_dict.iterkeys()) - -def eq__DictMulti_DictMulti(space, w_left, w_right): - if space.is_w(w_left, w_right): - return space.w_True - - if w_left.length() != w_right.length(): - return space.w_False - iteratorimplementation = w_left.iteritems() - while 1: +def characterize(space, w_a, w_b): + """(similar to CPython) + returns the smallest key in acontent for which b's value is + different or absent and this value""" + w_smallest_diff_a_key = None + w_its_value = None + iteratorimplementation = w_a.iteritems() + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break - w_rightval = w_right.getitem(w_key) - if w_rightval is None: - return space.w_False - if not space.eq_w(w_val, w_rightval): - return space.w_False - return space.w_True - -def characterize(space, w_a, w_b): - """ (similar to CPython) - returns the smallest key in acontent for which b's value is different or absent and this value """ - w_smallest_diff_a_key = None - w_its_value = None - iteratorimplementation = w_a.iteritems() - while 1: - w_key, w_val = iteratorimplementation.next_item() - if w_key is None: - break - if w_smallest_diff_a_key is None or space.is_true(space.lt(w_key, w_smallest_diff_a_key)): + if w_smallest_diff_a_key is None or space.is_true(space.lt( + w_key, w_smallest_diff_a_key)): w_bvalue = w_b.getitem(w_key) if w_bvalue is None: w_its_value = w_val @@ -874,105 +1126,11 @@ w_smallest_diff_a_key = w_key return w_smallest_diff_a_key, w_its_value -def lt__DictMulti_DictMulti(space, w_left, w_right): - # Different sizes, no problem - if w_left.length() < w_right.length(): - return space.w_True - if w_left.length() > w_right.length(): - return space.w_False - - # Same size - w_leftdiff, w_leftval = characterize(space, w_left, w_right) - if w_leftdiff is None: - return space.w_False - w_rightdiff, w_rightval = characterize(space, w_right, w_left) - if w_rightdiff is None: - # w_leftdiff is not None, w_rightdiff is None - return space.w_True - w_res = space.lt(w_leftdiff, w_rightdiff) - if (not space.is_true(w_res) and - space.eq_w(w_leftdiff, w_rightdiff) and - w_rightval is not None): - w_res = space.lt(w_leftval, w_rightval) - return w_res - -def dict_copy__DictMulti(space, w_self): - w_new = W_DictMultiObject.allocate_and_init_instance(space) - update1_dict_dict(space, w_new, w_self) - return w_new - -def dict_items__DictMulti(space, w_self): - return space.newlist(w_self.items()) - -def dict_keys__DictMulti(space, w_self): - return w_self.w_keys() - -def dict_values__DictMulti(space, w_self): - return space.newlist(w_self.values()) - -def dict_iteritems__DictMulti(space, w_self): - return W_DictMultiIterItemsObject(space, w_self.iteritems()) - -def dict_iterkeys__DictMulti(space, w_self): - return W_DictMultiIterKeysObject(space, w_self.iterkeys()) - -def dict_itervalues__DictMulti(space, w_self): - return W_DictMultiIterValuesObject(space, w_self.itervalues()) - -def dict_viewitems__DictMulti(space, w_self): - return W_DictViewItemsObject(space, w_self) - -def dict_viewkeys__DictMulti(space, w_self): - return W_DictViewKeysObject(space, w_self) - -def dict_viewvalues__DictMulti(space, w_self): - return W_DictViewValuesObject(space, w_self) - -def dict_clear__DictMulti(space, w_self): - w_self.clear() - -def dict_get__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - w_value = w_dict.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default - -def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default): - return w_dict.setdefault(w_key, w_default) - -def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w): - len_defaults = len(defaults_w) - if len_defaults > 1: - raise operationerrfmt(space.w_TypeError, - "pop expected at most 2 arguments, got %d", - 1 + len_defaults) - w_item = w_dict.getitem(w_key) - if w_item is None: - if len_defaults > 0: - return defaults_w[0] - else: - space.raise_key_error(w_key) - else: - w_dict.delitem(w_key) - return w_item - -def dict_popitem__DictMulti(space, w_dict): - try: - w_key, w_value = w_dict.popitem() - except KeyError: - raise OperationError(space.w_KeyError, - space.wrap("popitem(): dictionary is empty")) - return space.newtuple([w_key, w_value]) - # ____________________________________________________________ # Iteration - -class W_BaseDictMultiIterObject(W_Object): - from pypy.objspace.std.dicttype import dictiter_typedef as typedef - +class W_BaseDictMultiIterObject(W_Root): _immutable_fields_ = ["iteratorimplementation"] ignore_for_isinstance_cache = True @@ -981,139 +1139,265 @@ w_self.space = space w_self.iteratorimplementation = iteratorimplementation + def descr_iter(self, space): + return self + + def descr_length_hint(self, space): + return space.wrap(self.iteratorimplementation.length()) + + def descr_reduce(self, space): + """ + This is a slightly special case of pickling. + Since iteration over a dict is a bit hairy, + we do the following: + - create a clone of the dict iterator + - run it to the original position + - collect all remaining elements into a list + At unpickling time, we just use that list + and create an iterator on it. + This is of course not the standard way. + + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('dictiter_surrogate_new') + w_typeobj = space.type(self) + + raise OperationError( + space.w_TypeError, + space.wrap("can't pickle dictionary-keyiterator objects")) + # XXXXXX get that working again + + # we cannot call __init__ since we don't have the original dict + if isinstance(self, W_DictMultiIterKeysObject): + w_clone = space.allocate_instance(W_DictMultiIterKeysObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterValuesObject): + w_clone = space.allocate_instance(W_DictMultiIterValuesObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterItemsObject): + w_clone = space.allocate_instance(W_DictMultiIterItemsObject, + w_typeobj) + else: + msg = "unsupported dictiter type '%s' during pickling" % (self,) + raise OperationError(space.w_TypeError, space.wrap(msg)) + w_clone.space = space + w_clone.content = self.content + w_clone.len = self.len + w_clone.pos = 0 + w_clone.setup_iterator() + # spool until we have the same pos + while w_clone.pos < self.pos: + w_obj = w_clone.next_entry() + w_clone.pos += 1 + stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] + w_res = space.newlist(stuff) + w_ret = space.newtuple([new_inst, space.newtuple([w_res])]) + return w_ret + + class W_DictMultiIterKeysObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key = iteratorimplementation.next_key() + if w_key is not None: + return w_key + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterValuesObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_value = iteratorimplementation.next_value() + if w_value is not None: + return w_value + raise OperationError(space.w_StopIteration, space.w_None) class W_DictMultiIterItemsObject(W_BaseDictMultiIterObject): - pass + def descr_next(self, space): + iteratorimplementation = self.iteratorimplementation + w_key, w_value = iteratorimplementation.next_item() + if w_key is not None: + return space.newtuple([w_key, w_value]) + raise OperationError(space.w_StopIteration, space.w_None) -registerimplementation(W_DictMultiIterKeysObject) -registerimplementation(W_DictMultiIterValuesObject) -registerimplementation(W_DictMultiIterItemsObject) +W_DictMultiIterItemsObject.typedef = StdTypeDef( + "dict_iteritems", + __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), + next = interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), + ) -def iter__DictMultiIterKeysObject(space, w_dictiter): - return w_dictiter +W_DictMultiIterKeysObject.typedef = StdTypeDef( + "dict_iterkeys", + __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), + next = interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), + ) -def next__DictMultiIterKeysObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key = iteratorimplementation.next_key() - if w_key is not None: - return w_key - raise OperationError(space.w_StopIteration, space.w_None) +W_DictMultiIterValuesObject.typedef = StdTypeDef( + "dict_itervalues", + __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), + next = interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), + ) -def iter__DictMultiIterValuesObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterValuesObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_value = iteratorimplementation.next_value() - if w_value is not None: - return w_value - raise OperationError(space.w_StopIteration, space.w_None) - -def iter__DictMultiIterItemsObject(space, w_dictiter): - return w_dictiter - -def next__DictMultiIterItemsObject(space, w_dictiter): - iteratorimplementation = w_dictiter.iteratorimplementation - w_key, w_value = iteratorimplementation.next_item() - if w_key is not None: - return space.newtuple([w_key, w_value]) - raise OperationError(space.w_StopIteration, space.w_None) # ____________________________________________________________ # Views -class W_DictViewObject(W_Object): +class W_DictViewObject(W_Root): def __init__(w_self, space, w_dict): w_self.w_dict = w_dict -class W_DictViewKeysObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_keys_typedef as typedef -registerimplementation(W_DictViewKeysObject) + def descr_repr(self, space): + w_seq = space.call_function(space.w_list, self) + w_repr = space.repr(w_seq) + return space.wrap("%s(%s)" % (space.type(self).getname(space), + space.str_w(w_repr))) -class W_DictViewItemsObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_items_typedef as typedef -registerimplementation(W_DictViewItemsObject) + def descr_len(self, space): + return space.len(self.w_dict) + +def _all_contained_in(space, w_dictview, w_other): + w_iter = space.iter(w_dictview) + for w_item in space.iteriterable(w_iter): + if not space.is_true(space.contains(w_other, w_item)): + return space.w_False + return space.w_True + +def _is_set_like(w_other): + from pypy.objspace.std.setobject import W_BaseSetObject + return (isinstance(w_other, W_BaseSetObject) or + isinstance(w_other, W_DictViewKeysObject) or + isinstance(w_other, W_DictViewItemsObject)) + +class SetLikeDictView(object): + _mixin_ = True + + def descr_eq(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) == space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_ne(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + return space.not_(space.eq(self, w_other)) + + def descr_lt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) < space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_le(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) <= space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_gt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) > space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def descr_ge(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) >= space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def _as_set_op(name, methname): + @func_renamer('descr_' + name) + def op(self, space, w_other): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, methname, w_other) + return w_set + @func_renamer('descr_r' + name) + def rop(self, space, w_other): + w_set = space.call_function(space.w_set, w_other) + space.call_method(w_set, methname, self) + return w_set + return op, rop + + descr_sub, descr_rsub = _as_set_op('sub', 'difference_update') + descr_and, descr_rand = _as_set_op('and', 'intersection_update') + descr_or, descr_ror = _as_set_op('or', 'update') + descr_xor, descr_rxor = _as_set_op('xor', 'symmetric_difference_update') + +class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): + def descr_iter(self, space): + return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) + +class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView): + def descr_iter(self, space): + return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) class W_DictViewValuesObject(W_DictViewObject): - from pypy.objspace.std.dicttype import dict_values_typedef as typedef -registerimplementation(W_DictViewValuesObject) + def descr_iter(self, space): + return W_DictMultiIterValuesObject(space, self.w_dict.itervalues()) -def len__DictViewKeys(space, w_dictview): - return space.len(w_dictview.w_dict) -len__DictViewItems = len__DictViewValues = len__DictViewKeys +W_DictViewItemsObject.typedef = StdTypeDef( + "dict_items", + __repr__ = interp2app(W_DictViewItemsObject.descr_repr), + __len__ = interp2app(W_DictViewItemsObject.descr_len), + __iter__ = interp2app(W_DictViewItemsObject.descr_iter), -def iter__DictViewKeys(space, w_dictview): - return dict_iterkeys__DictMulti(space, w_dictview.w_dict) -def iter__DictViewItems(space, w_dictview): - return dict_iteritems__DictMulti(space, w_dictview.w_dict) -def iter__DictViewValues(space, w_dictview): - return dict_itervalues__DictMulti(space, w_dictview.w_dict) + __eq__ = interp2app(W_DictViewItemsObject.descr_eq), + __ne__ = interp2app(W_DictViewItemsObject.descr_ne), + __lt__ = interp2app(W_DictViewItemsObject.descr_lt), + __le__ = interp2app(W_DictViewItemsObject.descr_le), + __gt__ = interp2app(W_DictViewItemsObject.descr_gt), + __ge__ = interp2app(W_DictViewItemsObject.descr_ge), -def all_contained_in(space, w_dictview, w_otherview): - w_iter = space.iter(w_dictview) + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), + __rsub__ = interp2app(W_DictViewItemsObject.descr_rsub), + __and__ = interp2app(W_DictViewItemsObject.descr_and), + __rand__ = interp2app(W_DictViewItemsObject.descr_rand), + __or__ = interp2app(W_DictViewItemsObject.descr_or), + __ror__ = interp2app(W_DictViewItemsObject.descr_ror), + __xor__ = interp2app(W_DictViewItemsObject.descr_xor), + __rxor__ = interp2app(W_DictViewItemsObject.descr_rxor), + ) - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False +W_DictViewKeysObject.typedef = StdTypeDef( + "dict_keys", + __repr__ = interp2app(W_DictViewKeysObject.descr_repr), + __len__ = interp2app(W_DictViewKeysObject.descr_len), + __iter__ = interp2app(W_DictViewKeysObject.descr_iter), - return space.w_True + __eq__ = interp2app(W_DictViewKeysObject.descr_eq), + __ne__ = interp2app(W_DictViewKeysObject.descr_ne), + __lt__ = interp2app(W_DictViewKeysObject.descr_lt), + __le__ = interp2app(W_DictViewKeysObject.descr_le), + __gt__ = interp2app(W_DictViewKeysObject.descr_gt), + __ge__ = interp2app(W_DictViewKeysObject.descr_ge), -def eq__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - if space.eq_w(space.len(w_dictview), space.len(w_otherview)): - return all_contained_in(space, w_dictview, w_otherview) - return space.w_False -eq__DictViewKeys_settypedef = eq__DictViewKeys_DictViewKeys -eq__DictViewKeys_frozensettypedef = eq__DictViewKeys_DictViewKeys + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), + __rsub__ = interp2app(W_DictViewKeysObject.descr_rsub), + __and__ = interp2app(W_DictViewKeysObject.descr_and), + __rand__ = interp2app(W_DictViewKeysObject.descr_rand), + __or__ = interp2app(W_DictViewKeysObject.descr_or), + __ror__ = interp2app(W_DictViewKeysObject.descr_ror), + __xor__ = interp2app(W_DictViewKeysObject.descr_xor), + __rxor__ = interp2app(W_DictViewKeysObject.descr_rxor), + ) -eq__DictViewKeys_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_DictViewItems = eq__DictViewKeys_DictViewKeys -eq__DictViewItems_settypedef = eq__DictViewItems_DictViewItems -eq__DictViewItems_frozensettypedef = eq__DictViewItems_DictViewItems - -def repr__DictViewKeys(space, w_dictview): - w_seq = space.call_function(space.w_list, w_dictview) - w_repr = space.repr(w_seq) - return space.wrap("%s(%s)" % (space.type(w_dictview).getname(space), - space.str_w(w_repr))) -repr__DictViewItems = repr__DictViewKeys -repr__DictViewValues = repr__DictViewKeys - -def and__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set -and__DictViewKeys_settypedef = and__DictViewKeys_DictViewKeys -and__DictViewItems_DictViewItems = and__DictViewKeys_DictViewKeys -and__DictViewItems_settypedef = and__DictViewKeys_DictViewKeys - -def or__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "update", w_otherview) - return w_set -or__DictViewKeys_settypedef = or__DictViewKeys_DictViewKeys -or__DictViewItems_DictViewItems = or__DictViewKeys_DictViewKeys -or__DictViewItems_settypedef = or__DictViewKeys_DictViewKeys - -def xor__DictViewKeys_DictViewKeys(space, w_dictview, w_otherview): - w_set = space.call_function(space.w_set, w_dictview) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set -xor__DictViewKeys_settypedef = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_DictViewItems = xor__DictViewKeys_DictViewKeys -xor__DictViewItems_settypedef = xor__DictViewKeys_DictViewKeys - -# ____________________________________________________________ - -from pypy.objspace.std import dicttype -register_all(vars(), dicttype) +W_DictViewValuesObject.typedef = StdTypeDef( + "dict_values", + __repr__ = interp2app(W_DictViewValuesObject.descr_repr), + __len__ = interp2app(W_DictViewValuesObject.descr_len), + __iter__ = interp2app(W_DictViewValuesObject.descr_iter), + ) diff --git a/pypy/objspace/std/dicttype.py b/pypy/objspace/std/dicttype.py deleted file mode 100644 --- a/pypy/objspace/std/dicttype.py +++ /dev/null @@ -1,221 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.interpreter.mixedmodule import MixedModule -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.register_all import register_all - -dict_copy = SMM('copy', 1, - doc='D.copy() -> a shallow copy of D') -dict_items = SMM('items', 1, - doc="D.items() -> list of D's (key, value) pairs, as" - ' 2-tuples') -dict_keys = SMM('keys', 1, - doc="D.keys() -> list of D's keys") -dict_values = SMM('values', 1, - doc="D.values() -> list of D's values") -dict_has_key = SMM('has_key', 2, - doc='D.has_key(k) -> True if D has a key k, else False') -dict_clear = SMM('clear', 1, - doc='D.clear() -> None. Remove all items from D.') -dict_get = SMM('get', 3, defaults=(None,), - doc='D.get(k[,d]) -> D[k] if k in D, else d. d defaults' - ' to None.') -dict_pop = SMM('pop', 2, varargs_w=True, - doc='D.pop(k[,d]) -> v, remove specified key and return' - ' the corresponding value\nIf key is not found, d is' - ' returned if given, otherwise KeyError is raised') -dict_popitem = SMM('popitem', 1, - doc='D.popitem() -> (k, v), remove and return some (key,' - ' value) pair as a\n2-tuple; but raise KeyError if D' - ' is empty') -dict_setdefault = SMM('setdefault', 3, defaults=(None,), - doc='D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d' - ' if k not in D') -dict_update = SMM('update', 1, general__args__=True, - doc='D.update(E, **F) -> None. Update D from E and F:' - ' for k in E: D[k] = E[k]\n(if E has keys else: for' - ' (k, v) in E: D[k] = v) then: for k in F: D[k] =' - ' F[k]') -dict_iteritems = SMM('iteritems', 1, - doc='D.iteritems() -> an iterator over the (key, value)' - ' items of D') -dict_iterkeys = SMM('iterkeys', 1, - doc='D.iterkeys() -> an iterator over the keys of D') -dict_itervalues = SMM('itervalues', 1, - doc='D.itervalues() -> an iterator over the values of D') -dict_viewkeys = SMM('viewkeys', 1, - doc="D.viewkeys() -> a set-like object providing a view on D's keys") -dict_viewitems = SMM('viewitems', 1, - doc="D.viewitems() -> a set-like object providing a view on D's items") -dict_viewvalues = SMM('viewvalues', 1, - doc="D.viewvalues() -> an object providing a view on D's values") -dict_reversed = SMM('__reversed__', 1) - -def dict_reversed__ANY(space, w_dict): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) - -register_all(vars(), globals()) - -def descr_fromkeys(space, w_type, w_keys, w_fill=None): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - if w_fill is None: - w_fill = space.w_None - if space.is_w(w_type, space.w_dict): - w_dict = W_DictMultiObject.allocate_and_init_instance(space, w_type) - - strlist = space.listview_str(w_keys) - if strlist is not None: - for key in strlist: - w_dict.setitem_str(key, w_fill) - else: - for w_key in space.listview(w_keys): - w_dict.setitem(w_key, w_fill) - else: - w_dict = space.call_function(w_type) - for w_key in space.listview(w_keys): - space.setitem(w_dict, w_key, w_fill) - return w_dict - - -app = gateway.applevel(''' - def dictrepr(currently_in_repr, d): - if len(d) == 0: - return "{}" - dict_id = id(d) - if dict_id in currently_in_repr: - return '{...}' - currently_in_repr[dict_id] = 1 - try: - items = [] - # XXX for now, we cannot use iteritems() at app-level because - # we want a reasonable result instead of a RuntimeError - # even if the dict is mutated by the repr() in the loop. - for k, v in dict.items(d): - items.append(repr(k) + ": " + repr(v)) - return "{" + ', '.join(items) + "}" - finally: - try: - del currently_in_repr[dict_id] - except: - pass -''', filename=__file__) - -dictrepr = app.interphook("dictrepr") - - -def descr_repr(space, w_dict): - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return dictrepr(space, w_currently_in_repr, w_dict) - - -# ____________________________________________________________ - -def descr__new__(space, w_dicttype, __args__): - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - w_obj = W_DictMultiObject.allocate_and_init_instance(space, w_dicttype) - return w_obj - -# ____________________________________________________________ - -dict_typedef = StdTypeDef("dict", - __doc__ = '''dict() -> new empty dictionary. -dict(mapping) -> new dictionary initialized from a mapping object\'s - (key, value) pairs. -dict(seq) -> new dictionary initialized as if via: - d = {} - for k, v in seq: - d[k] = v -dict(**kwargs) -> new dictionary initialized with the name=value pairs - in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(descr__new__), - __hash__ = None, - __repr__ = gateway.interp2app(descr_repr), - fromkeys = gateway.interp2app(descr_fromkeys, as_classmethod=True), - ) -dict_typedef.registermethods(globals()) - -# ____________________________________________________________ - -def descr_dictiter__length_hint__(space, w_self): - from pypy.objspace.std.dictmultiobject import W_BaseDictMultiIterObject - assert isinstance(w_self, W_BaseDictMultiIterObject) - return space.wrap(w_self.iteratorimplementation.length()) - - -def descr_dictiter__reduce__(w_self, space): - """ - This is a slightly special case of pickling. - Since iteration over a dict is a bit hairy, - we do the following: - - create a clone of the dict iterator - - run it to the original position - - collect all remaining elements into a list - At unpickling time, we just use that list - and create an iterator on it. - This is of course not the standard way. - - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(dictiter_typedef) - - raise OperationError( - space.w_TypeError, - space.wrap("can't pickle dictionary-keyiterator objects")) - # XXXXXX get that working again - - # we cannot call __init__ since we don't have the original dict - if isinstance(w_self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(w_self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(w_self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) - else: - msg = "unsupported dictiter type '%s' during pickling" % (w_self, ) - raise OperationError(space.w_TypeError, space.wrap(msg)) - w_clone.space = space - w_clone.content = w_self.content - w_clone.len = w_self.len - w_clone.pos = 0 - w_clone.setup_iterator() - # spool until we have the same pos - while w_clone.pos < w_self.pos: - w_obj = w_clone.next_entry() - w_clone.pos += 1 - stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] - w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) - return w_ret - -# ____________________________________________________________ - - -dictiter_typedef = StdTypeDef("dictionaryiterator", - __length_hint__ = gateway.interp2app(descr_dictiter__length_hint__), - __reduce__ = gateway.interp2app(descr_dictiter__reduce__), - ) - -# ____________________________________________________________ -# Dict views - -dict_keys_typedef = StdTypeDef( - "dict_keys", - ) - -dict_items_typedef = StdTypeDef( - "dict_items", - ) - -dict_values_typedef = StdTypeDef( - "dict_values", - ) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -12,6 +12,7 @@ from pypy.objspace.std.register_all import register_all from rpython.rlib.rarithmetic import LONG_BIT, r_longlong, r_uint, intmask from pypy.objspace.std import model +from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.interpreter.special import Ellipsis from pypy.interpreter.pycode import PyCode from pypy.interpreter import gateway, unicodehelper @@ -24,7 +25,6 @@ from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.longobject import W_LongObject, newlong @@ -309,15 +309,18 @@ return space.newlist(items_w) register(TYPE_LIST, unmarshal_List) -def marshal_w__DictMulti(space, w_dict, m): +def marshal_w_dict(space, w_dict, m): + if not isinstance(w_dict, W_DictMultiObject): + raise_exception(space, "unmarshallable object") m.start(TYPE_DICT) for w_tuple in w_dict.items(): w_key, w_value = space.fixedview(w_tuple, 2) m.put_w_obj(w_key) m.put_w_obj(w_value) m.atom(TYPE_NULL) +handled_by_any.append(('dict', marshal_w_dict)) -def unmarshal_DictMulti(space, u, tc): +def unmarshal_dict(space, u, tc): # since primitive lists are not optimized and we don't know # the dict size in advance, use the dict's setitem instead # of building a list of tuples. @@ -329,7 +332,7 @@ w_value = u.get_w_obj() space.setitem(w_dic, w_key, w_value) return w_dic -register(TYPE_DICT, unmarshal_DictMulti) +register(TYPE_DICT, unmarshal_dict) def unmarshal_NULL(self, u, tc): return None diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -40,7 +40,6 @@ from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.listobject import list_typedef - from pypy.objspace.std.dicttype import dict_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -81,6 +80,7 @@ # not-multimethod based types + self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -92,10 +92,6 @@ floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], listobject.W_ListObject: [], - dictmultiobject.W_DictMultiObject: [], - dictmultiobject.W_DictMultiIterKeysObject: [], - dictmultiobject.W_DictMultiIterValuesObject: [], - dictmultiobject.W_DictMultiIterItemsObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -108,9 +104,6 @@ iterobject.W_FastTupleIterObject: [], iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], - dictmultiobject.W_DictViewKeysObject: [], - dictmultiobject.W_DictViewItemsObject: [], - dictmultiobject.W_DictViewValuesObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], } @@ -333,9 +326,6 @@ s += ' instance of %s' % self.w__class__ return '<%s>' % s - def unwrap(self, space): - raise UnwrapError('cannot unwrap %r' % self) - class UnwrapError(Exception): pass diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -253,10 +253,9 @@ def unwrap(self, w_obj): """NOT_RPYTHON""" - if isinstance(w_obj, model.W_Object): + # _____ this code is here to support testing only _____ + if isinstance(w_obj, W_Root): return w_obj.unwrap(self) - if isinstance(w_obj, W_Root): - return w_obj raise model.UnwrapError("cannot unwrap: %r" % w_obj) def newint(self, intval): diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -2,8 +2,7 @@ import py from pypy.objspace.std.dictmultiobject import (W_DictMultiObject, - setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, StringDictStrategy, - ObjectDictStrategy) + StringDictStrategy, ObjectDictStrategy) class TestW_DictObject(object): @@ -409,6 +408,24 @@ assert {'a': 1 } < { 'b': 1} assert {'a': 1, 'x': 2 } < { 'b': 1, 'x': 2} + def test_other_rich_cmp(self): + d1 = {1: 2, 3: 4} + d2 = {1: 2, 3: 4} + d3 = {1: 2, 3: 5} + d4 = {1: 2} + + assert d1 <= d2 + assert d1 <= d3 + assert not d1 <= d4 + + assert not d1 > d2 + assert not d1 > d3 + assert d1 > d4 + + assert d1 >= d2 + assert not d1 >= d3 + assert d1 >= d4 + def test_str_repr(self): assert '{}' == str({}) assert '{1: 2}' == str({1: 2}) @@ -604,6 +621,9 @@ assert d.values() == [] assert d.keys() == [] + def test_cmp_with_noncmp(self): + assert not {} > object() + class AppTest_DictMultiObject(AppTest_DictObject): def test_emptydict_unhashable(self): @@ -676,6 +696,7 @@ assert d.viewkeys() == e.viewkeys() del e["a"] assert d.viewkeys() != e.viewkeys() + assert not d.viewkeys() == 42 def test_dict_items(self): d = {1: 10, "a": "ABC"} @@ -700,6 +721,7 @@ assert d.viewitems() == e.viewitems() e["a"] = "def" assert d.viewitems() != e.viewitems() + assert not d.viewitems() == 42 def test_dict_mixed_keys_items(self): d = {(1, 1): 11, (2, 2): 22} @@ -712,6 +734,7 @@ values = d.viewvalues() assert set(values) == set([10, "ABC"]) assert len(values) == 2 + assert not values == 42 def test_dict_repr(self): d = {1: 10, "a": "ABC"} @@ -754,6 +777,13 @@ assert d1.viewkeys() ^ set(d2.viewkeys()) == set('ac') assert d1.viewkeys() ^ set(d3.viewkeys()) == set('abde') + assert d1.viewkeys() - d1.viewkeys() == set() + assert d1.viewkeys() - d2.viewkeys() == set('a') + assert d1.viewkeys() - d3.viewkeys() == set('ab') + assert d1.viewkeys() - set(d1.viewkeys()) == set() + assert d1.viewkeys() - set(d2.viewkeys()) == set('a') + assert d1.viewkeys() - set(d3.viewkeys()) == set('ab') + def test_items_set_operations(self): d1 = {'a': 1, 'b': 2} d2 = {'a': 2, 'b': 2} @@ -782,6 +812,113 @@ assert (d1.viewitems() ^ d3.viewitems() == set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) + assert d1.viewitems() - d1.viewitems() == set() + assert d1.viewitems() - d2.viewitems() == set([('a', 1)]) + assert d1.viewitems() - d3.viewitems() == set([('a', 1), ('b', 2)]) + + def test_keys_set_operations_any_type(self): + d = {1: u'a', 2: u'b', 3: u'c'} + assert d.viewkeys() & set([1]) == set([1]) + assert d.viewkeys() & {1: u'foo'} == set([1]) + assert d.viewkeys() & [1, 2] == set([1, 2]) + # + assert set([1]) & d.viewkeys() == set([1]) + assert {1: u'foo'} & d.viewkeys() == set([1]) + assert [1, 2] & d.viewkeys() == set([1, 2]) + # + assert d.viewkeys() - set([1]) == set([2, 3]) + assert set([1, 4]) - d.viewkeys() == set([4]) + # + assert d.viewkeys() == set([1, 2, 3]) + # XXX: The following 4 commented out are CPython 2.7 bugs + #assert set([1, 2, 3]) == d.viewkeys() + assert d.viewkeys() == frozenset(set([1, 2, 3])) + #assert frozenset(set([1, 2, 3])) == d.viewkeys() + assert not d.viewkeys() != set([1, 2, 3]) + #assert not set([1, 2, 3]) != d.viewkeys() + assert not d.viewkeys() != frozenset(set([1, 2, 3])) + #assert not frozenset(set([1, 2, 3])) != d.viewkeys() + + def test_items_set_operations_any_type(self): + d = {1: u'a', 2: u'b', 3: u'c'} + assert d.viewitems() & set([(1, u'a')]) == set([(1, u'a')]) + assert d.viewitems() & {(1, u'a'): u'foo'} == set([(1, u'a')]) + assert d.viewitems() & [(1, u'a'), (2, u'b')] == set([(1, u'a'), (2, u'b')]) + # + assert set([(1, u'a')]) & d.viewitems() == set([(1, u'a')]) + assert {(1, u'a'): u'foo'} & d.viewitems() == set([(1, u'a')]) + assert [(1, u'a'), (2, u'b')] & d.viewitems() == set([(1, u'a'), (2, u'b')]) + # + assert d.viewitems() - set([(1, u'a')]) == set([(2, u'b'), (3, u'c')]) + assert set([(1, u'a'), 4]) - d.viewitems() == set([4]) + # + assert d.viewitems() == set([(1, u'a'), (2, u'b'), (3, u'c')]) + # XXX: The following 4 commented out are CPython 2.7 bugs + #assert set([(1, u'a'), (2, u'b'), (3, u'c')]) == d.viewitems() + assert d.viewitems() == frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) + #assert frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) == d.viewitems() + assert not d.viewitems() != set([(1, u'a'), (2, u'b'), (3, u'c')]) + #assert not set([(1, u'a'), (2, u'b'), (3, u'c')]) != d.viewitems() + assert not d.viewitems() != frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) + #assert not frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) != d.viewitems() + + def test_dictviewset_unhashable_values(self): + class C: + def __eq__(self, other): + return True + d = {1: C()} + assert d.viewitems() <= d.viewitems() + + def test_compare_keys_and_items(self): + d1 = {1: 2} + d2 = {(1, 2): 'foo'} + assert d1.viewitems() == d2.viewkeys() + + def test_keys_items_contained(self): + def helper(fn): + empty = fn(dict()) + empty2 = fn(dict()) + smaller = fn({1:1, 2:2}) + larger = fn({1:1, 2:2, 3:3}) + larger2 = fn({1:1, 2:2, 3:3}) + larger3 = fn({4:1, 2:2, 3:3}) + + assert smaller < larger + assert smaller <= larger + assert larger > smaller + assert larger >= smaller + + assert not smaller >= larger + assert not smaller > larger + assert not larger <= smaller + assert not larger < smaller + + assert not smaller < larger3 + assert not smaller <= larger3 + assert not larger3 > smaller + assert not larger3 >= smaller + + # Inequality strictness + assert larger2 >= larger + assert larger2 <= larger + assert not larger2 > larger + assert not larger2 < larger + + assert larger == larger2 + assert smaller != larger + + # There is an optimization on the zero-element case. + assert empty == empty2 + assert not empty != empty2 + assert not empty == smaller + assert empty != smaller + + # With the same size, an elementwise compare happens + assert larger != larger3 + assert not larger == larger3 + + helper(lambda x: x.viewkeys()) + helper(lambda x: x.viewitems()) class AppTestStrategies(object): def setup_class(cls): @@ -971,10 +1108,10 @@ pydict = {} for i in range(N): x = randint(-N, N) - setitem__DictMulti_ANY_ANY(self.space, d, x, i) + d.descr_setitem(self.space, x, i) pydict[x] = i for key, value in pydict.iteritems(): - assert value == getitem__DictMulti_ANY(self.space, d, key) + assert value == d.descr_getitem(self.space, key) class BaseTestRDictImplementation: diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -1,9 +1,10 @@ """ Utilities to get environ variables and platform-specific memory-related values. """ -import os, sys +import os, sys, platform from rpython.rlib.rarithmetic import r_uint from rpython.rlib.debug import debug_print, debug_start, debug_stop +from rpython.rlib.rstring import assert_str0 from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.lltypesystem.lloperation import llop @@ -130,7 +131,22 @@ # ---------- Linux2 ---------- -def get_L2cache_linux2(filename="/proc/cpuinfo"): +def get_L2cache_linux2(): + arch = platform.machine() + if arch.endswith('86') or arch == 'x86_64': + return get_L2cache_linux2_cpuinfo() + if arch in ('alpha', 'ppc', 'ppc64'): + return get_L2cache_linux2_cpuinfo(label='L2 cache') + if arch == 'ia64': + return get_L2cache_linux2_ia64() + if arch in ('parisc', 'parisc64'): + return get_L2cache_linux2_cpuinfo(label='D-cache') + if arch in ('sparc', 'sparc64'): + return get_L2cache_linux2_sparc() + return -1 + + +def get_L2cache_linux2_cpuinfo(filename="/proc/cpuinfo", label='cache size'): debug_start("gc-hardware") L2cache = sys.maxint try: @@ -149,12 +165,8 @@ else: data = ''.join(data) linepos = 0 - # Currently on ARM-linux we won't find any information about caches in From noreply at buildbot.pypy.org Sun May 19 11:33:00 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 11:33:00 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: A branch to refactor _emit_call() and fix it for call_release_gil(). Message-ID: <20130519093300.5717B1C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64309:ba771143d971 Date: 2013-05-19 11:31 +0200 http://bitbucket.org/pypy/pypy/changeset/ba771143d971/ Log: A branch to refactor _emit_call() and fix it for call_release_gil(). The issue is that it's not ok to do any access to ebp when the gil has been released! From noreply at buildbot.pypy.org Sun May 19 11:33:01 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 11:33:01 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: In-progress. Message-ID: <20130519093301.A57791C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64310:575cd15c0384 Date: 2013-05-19 11:32 +0200 http://bitbucket.org/pypy/pypy/changeset/575cd15c0384/ Log: In-progress. diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -25,12 +25,11 @@ RegLoc, FrameLoc, ConstFloatLoc, ImmedLoc, AddressLoc, imm, imm0, imm1, FloatImmedLoc, RawEbpLoc, RawEspLoc) from rpython.rlib.objectmodel import we_are_translated -from rpython.jit.backend.x86 import rx86, codebuf +from rpython.jit.backend.x86 import rx86, codebuf, callbuilder from rpython.jit.metainterp.resoperation import rop from rpython.jit.backend.x86 import support from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib import rgc -from rpython.rlib.clibffi import FFI_DEFAULT_ABI from rpython.jit.backend.x86.jump import remap_frame_layout from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter import longlong @@ -38,15 +37,6 @@ from rpython.rlib.objectmodel import compute_unique_id -# darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0, -# better safe than sorry -CALL_ALIGN = 16 // WORD - - -def align_stack_words(words): - return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - - class Assembler386(BaseAssembler): _regalloc = None _output_loop_log = None @@ -131,10 +121,10 @@ mc.MOV_rs(esi.value, WORD*2) # push first arg mc.MOV_rr(edi.value, ebp.value) - align = align_stack_words(1) + align = callbuilder.align_stack_words(1) mc.SUB_ri(esp.value, (align - 1) * WORD) else: - align = align_stack_words(3) + align = callbuilder.align_stack_words(3) mc.MOV_rs(eax.value, WORD * 2) mc.SUB_ri(esp.value, (align - 1) * WORD) mc.MOV_sr(WORD, eax.value) @@ -1014,175 +1004,9 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def _emit_call(self, x, arglocs, start=0, tmp=eax, - argtypes=None, callconv=FFI_DEFAULT_ABI, - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True, - # max number of arguments we can pass on esp; if more, - # we need to decrease esp temporarily - stack_max=PASS_ON_MY_FRAME): - # - if IS_X86_64: - return self._emit_call_64(x, arglocs, start, argtypes, - can_collect, stack_max) - stack_depth = 0 - n = len(arglocs) - for i in range(start, n): - loc = arglocs[i] - stack_depth += loc.get_width() // WORD - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - self.mc.SUB_ri(esp.value, align * WORD) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) - else: - align = 0 - p = 0 - for i in range(start, n): - loc = arglocs[i] - if isinstance(loc, RegLoc): - if loc.is_xmm: - self.mc.MOVSD_sx(p, loc.value) - else: - self.mc.MOV_sr(p, loc.value) - p += loc.get_width() - p = 0 - for i in range(start, n): - loc = arglocs[i] - if not isinstance(loc, RegLoc): - if loc.get_width() == 8: - self.mc.MOVSD(xmm0, loc) - self.mc.MOVSD_sx(p, xmm0.value) - else: - self.mc.MOV(tmp, loc) - self.mc.MOV_sr(p, tmp.value) - p += loc.get_width() - # x is a location - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if callconv != FFI_DEFAULT_ABI: - self._fix_stdcall(callconv, p - align * WORD) - elif align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) - - def _fix_stdcall(self, callconv, p): - from rpython.rlib.clibffi import FFI_STDCALL - assert callconv == FFI_STDCALL - # it's a bit stupid, but we're just going to cancel the fact that - # the called function just added 'p' to ESP, by subtracting it again. - self.mc.SUB_ri(esp.value, p) - - def _emit_call_64(self, x, arglocs, start, argtypes, - can_collect, stack_max): - src_locs = [] - dst_locs = [] - xmm_src_locs = [] - xmm_dst_locs = [] - singlefloats = None - - # In reverse order for use with pop() - unused_gpr = [r9, r8, ecx, edx, esi, edi] - unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0] - - on_stack = 0 - # count the stack depth - floats = 0 - for i in range(start, len(arglocs)): - arg = arglocs[i] - if arg.is_float() or argtypes and argtypes[i - start] == 'S': - floats += 1 - all_args = len(arglocs) - start - stack_depth = (max(all_args - floats - len(unused_gpr), 0) + - max(floats - len(unused_xmm), 0)) - align = 0 - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) - self.mc.SUB_ri(esp.value, align * WORD) - for i in range(start, len(arglocs)): - loc = arglocs[i] - if loc.is_float(): - xmm_src_locs.append(loc) - if len(unused_xmm) > 0: - xmm_dst_locs.append(unused_xmm.pop()) - else: - xmm_dst_locs.append(RawEspLoc(on_stack * WORD, FLOAT)) - on_stack += 1 - elif argtypes is not None and argtypes[i-start] == 'S': - # Singlefloat argument - if singlefloats is None: - singlefloats = [] - if len(unused_xmm) > 0: - singlefloats.append((loc, unused_xmm.pop())) - else: - singlefloats.append((loc, RawEspLoc(on_stack * WORD, INT))) - on_stack += 1 - else: - src_locs.append(loc) - if len(unused_gpr) > 0: - dst_locs.append(unused_gpr.pop()) - else: - dst_locs.append(RawEspLoc(on_stack * WORD, INT)) - on_stack += 1 - - # Handle register arguments: first remap the xmm arguments - remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, - X86_64_XMM_SCRATCH_REG) - # Load the singlefloat arguments from main regs or stack to xmm regs - if singlefloats is not None: - for src, dst in singlefloats: - if isinstance(dst, RawEspLoc): - # XXX too much special logic - if isinstance(src, RawEbpLoc): - self.mc.MOV32(X86_64_SCRATCH_REG, src) - self.mc.MOV32(dst, X86_64_SCRATCH_REG) - else: - self.mc.MOV32(dst, src) - continue - if isinstance(src, ImmedLoc): - self.mc.MOV(X86_64_SCRATCH_REG, src) - src = X86_64_SCRATCH_REG - self.mc.MOVD(dst, src) - # Finally remap the arguments in the main regs - # If x is a register and is in dst_locs, then oups, it needs to - # be moved away: - if x in dst_locs: - src_locs.append(x) - dst_locs.append(r10) - x = r10 - remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + def simple_call(self, fnaddr, arglocs): + cb = callbuilder.CallBuilder(self, imm(fnaddr), arglocs) + cb.emit() def _reload_frame_if_necessary(self, mc, align_stack=False): gcrootmap = self.cpu.gc_ll_descr.gcrootmap @@ -1198,10 +1022,6 @@ self._write_barrier_fastpath(mc, wbdescr, [ebp], array=False, is_frame=True, align_stack=align_stack) - def call(self, addr, args, res): - self._emit_call(imm(addr), args) - assert res is eax - genop_int_neg = _unaryop("NEG") genop_int_invert = _unaryop("NOT") genop_int_add = _binaryop_or_lea("ADD", True) @@ -2003,29 +1823,20 @@ size = sizeloc.value signloc = arglocs[1] - x = arglocs[2] # the function address - if x is eax: - tmp = ecx - else: - tmp = eax + cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:]) descr = op.getdescr() assert isinstance(descr, CallDescr) + cb.argtypes = descr.get_arg_types() + cb.callconv = descr.get_call_conv() - stack_max = PASS_ON_MY_FRAME if is_call_release_gil: if self._is_asmgcc(): from rpython.memory.gctransform import asmgcroot stack_max -= asmgcroot.JIT_USE_WORDS - can_collect = False - else: - can_collect = True + XXXXXX - self._emit_call(x, arglocs, 3, tmp=tmp, - argtypes=descr.get_arg_types(), - callconv=descr.get_call_conv(), - can_collect=can_collect, - stack_max=stack_max) + cb.emit() if IS_X86_32 and isinstance(resloc, FrameLoc) and resloc.type == FLOAT: # a float or a long long return diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/x86/callbuilder.py @@ -0,0 +1,224 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32, + PASS_ON_MY_FRAME) +from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, + r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, + RegLoc) + + +# darwin requires the stack to be 16 bytes aligned on calls. +# Same for gcc 4.5.0, better safe than sorry +CALL_ALIGN = 16 // WORD + +def align_stack_words(words): + return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) + + + +class AbstractCallBuilder(object): + + # max number of words we have room in esp; if we need more for + # arguments, we need to decrease esp temporarily + stack_max = PASS_ON_MY_FRAME + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = None + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # if False, we also push the gcmap + is_call_release_gil = False + + + def __init__(self, assembler, fnloc, arglocs): + self.asm = assembler + self.mc = assembler.mc + self.fnloc = fnloc + self.arglocs = arglocs + self.current_esp = 0 + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.pop_gcmap() + self.restore_esp() + + def emit_raw_call(self): + self.mc.CALL(self.fnloc) + if self.callconv != FFI_DEFAULT_ABI: + self.current_esp += self._fix_stdcall(self.callconv) + + def restore_esp(self): + if self.current_esp != 0: + self.mc.SUB_ri(esp.value, self.current_esp) + self.current_esp = 0 + + def push_gcmap(self): + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + assert not self.is_call_release_gil + self.change_extra_stack_depth = (self.current_esp != 0) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, -self.current_esp) + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + assert not self.is_call_release_gil + self.asm._reload_frame_if_necessary(self.mc) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, 0) + self.asm.pop_gcmap(self.mc) + + +class CallBuilder32(AbstractCallBuilder): + + def prepare_arguments(self): + arglocs = self.arglocs + stack_depth = 0 + n = len(arglocs) + for i in range(n): + loc = arglocs[i] + stack_depth += loc.get_width() // WORD + if stack_depth > self.stack_max: + align = align_stack_words(stack_depth - self.stack_max) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) + # + p = 0 + for i in range(n): + loc = arglocs[i] + if isinstance(loc, RegLoc): + if loc.is_xmm: + self.mc.MOVSD_sx(p, loc.value) + else: + self.mc.MOV_sr(p, loc.value) + p += loc.get_width() + p = 0 + for i in range(n): + loc = arglocs[i] + if not isinstance(loc, RegLoc): + if loc.get_width() == 8: + self.mc.MOVSD(xmm0, loc) + self.mc.MOVSD_sx(p, xmm0.value) + else: + if self.fnloc is eax: + tmp = ecx + else: + tmp = eax + self.mc.MOV(tmp, loc) + self.mc.MOV_sr(p, tmp.value) + p += loc.get_width() + self.total_stack_used_by_arguments = p + + + def _fix_stdcall(self, callconv): + from rpython.rlib.clibffi import FFI_STDCALL + assert callconv == FFI_STDCALL + return self.total_stack_used_by_arguments + + + +class CallBuilder64(AbstractCallBuilder): + + # In reverse order for use with pop() + unused_gpr = [r9, r8, ecx, edx, esi, edi] + unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0] + + def prepare_arguments(self): + src_locs = [] + dst_locs = [] + xmm_src_locs = [] + xmm_dst_locs = [] + singlefloats = None + + unused_grp = self.unused_grp[:] + unused_xmm = self.unused_xmm[:] + + on_stack = 0 + for i in range(len(arglocs)): + loc = arglocs[i] + if loc.is_float(): + xmm_src_locs.append(loc) + if len(unused_xmm) > 0: + xmm_dst_locs.append(unused_xmm.pop()) + else: + xmm_dst_locs.append(RawEspLoc(on_stack * WORD, FLOAT)) + on_stack += 1 + elif argtypes is not None and argtypes[i] == 'S': + # Singlefloat argument + if singlefloats is None: + singlefloats = [] + if len(unused_xmm) > 0: + singlefloats.append((loc, unused_xmm.pop())) + else: + singlefloats.append((loc, RawEspLoc(on_stack * WORD, INT))) + on_stack += 1 + else: + src_locs.append(loc) + if len(unused_gpr) > 0: + dst_locs.append(unused_gpr.pop()) + else: + dst_locs.append(RawEspLoc(on_stack * WORD, INT)) + on_stack += 1 + + if not we_are_translated(): # assert that we got the right stack depth + floats = 0 + for i in range(len(arglocs)): + arg = arglocs[i] + if arg.is_float() or argtypes and argtypes[i] == 'S': + floats += 1 + all_args = len(arglocs) + stack_depth = (max(all_args - floats - len(unused_gpr), 0) + + max(floats - len(unused_xmm), 0)) + assert stack_depth == on_stack + + align = 0 + if on_stack > stack_max: + align = align_stack_words(on_stack - stack_max) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) + + # Handle register arguments: first remap the xmm arguments + remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, + X86_64_XMM_SCRATCH_REG) + # Load the singlefloat arguments from main regs or stack to xmm regs + if singlefloats is not None: + for src, dst in singlefloats: + if isinstance(dst, RawEspLoc): + # XXX too much special logic + if isinstance(src, RawEbpLoc): + self.mc.MOV32(X86_64_SCRATCH_REG, src) + self.mc.MOV32(dst, X86_64_SCRATCH_REG) + else: + self.mc.MOV32(dst, src) + continue + if isinstance(src, ImmedLoc): + self.mc.MOV(X86_64_SCRATCH_REG, src) + src = X86_64_SCRATCH_REG + self.mc.MOVD(dst, src) + # Finally remap the arguments in the main regs + # If x is a register and is in dst_locs, then oups, it needs to + # be moved away: + if self.fnloc in dst_locs: + src_locs.append(self.fnloc) + dst_locs.append(r10) + self.fnloc = r10 + remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) + + + def _fix_stdcall(self, callconv): + assert 0 # should not occur on 64-bit + + +if IS_X86_32: + CallBuilder = CallBuilder32 +if IS_X86_64: + CallBuilder = CallBuilder64 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -799,14 +799,6 @@ self._consider_call(op, guard_op) def consider_call_release_gil(self, op, guard_op): - # We spill the arguments to the stack, because we need to do 3 calls: - # call_release_gil(), the_real_c_function(), and call_reacquire_gil(). - # The arguments are used on the second call only. XXX we assume - # that the XMM arguments won't be modified by call_release_gil(). - for i in range(op.numargs()): - loc = self.loc(op.getarg(i)) - if loc in self.rm.save_around_call_regs: - self.rm.force_spill_var(op.getarg(i)) assert guard_op is not None self._consider_call(op, guard_op) From noreply at buildbot.pypy.org Sun May 19 11:37:58 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 11:37:58 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Fixes Message-ID: <20130519093758.92CFE1C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64311:01e5cd6f839f Date: 2013-05-19 11:37 +0200 http://bitbucket.org/pypy/pypy/changeset/01e5cd6f839f/ Log: Fixes diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -30,7 +30,6 @@ from rpython.jit.backend.x86 import support from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib import rgc -from rpython.jit.backend.x86.jump import remap_frame_layout from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter import longlong from rpython.rlib.rarithmetic import intmask, r_uint diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -1,10 +1,13 @@ from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32, PASS_ON_MY_FRAME) from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, - RegLoc) + RegLoc, RawEspLoc) +from rpython.jit.backend.x86.jump import remap_frame_layout # darwin requires the stack to be 16 bytes aligned on calls. @@ -29,7 +32,7 @@ # this is the calling convention (can be FFI_STDCALL on Windows) callconv = FFI_DEFAULT_ABI - # if False, we also push the gcmap + # is it for the main CALL of a call_release_gil? is_call_release_gil = False @@ -139,7 +142,9 @@ xmm_dst_locs = [] singlefloats = None - unused_grp = self.unused_grp[:] + arglocs = self.arglocs + argtypes = self.argtypes + unused_gpr = self.unused_gpr[:] unused_xmm = self.unused_xmm[:] on_stack = 0 @@ -176,18 +181,18 @@ if arg.is_float() or argtypes and argtypes[i] == 'S': floats += 1 all_args = len(arglocs) - stack_depth = (max(all_args - floats - len(unused_gpr), 0) + - max(floats - len(unused_xmm), 0)) + stack_depth = (max(all_args - floats - 6, 0) + + max(floats - 8, 0)) assert stack_depth == on_stack align = 0 - if on_stack > stack_max: - align = align_stack_words(on_stack - stack_max) + if on_stack > self.stack_max: + align = align_stack_words(on_stack - self.stack_max) self.current_esp -= align * WORD self.mc.SUB_ri(esp.value, align * WORD) # Handle register arguments: first remap the xmm arguments - remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, + remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, X86_64_XMM_SCRATCH_REG) # Load the singlefloat arguments from main regs or stack to xmm regs if singlefloats is not None: @@ -211,7 +216,7 @@ src_locs.append(self.fnloc) dst_locs.append(r10) self.fnloc = r10 - remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) + remap_frame_layout(self.asm, src_locs, dst_locs, X86_64_SCRATCH_REG) def _fix_stdcall(self, callconv): From noreply at buildbot.pypy.org Sun May 19 11:41:16 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 19 May 2013 11:41:16 +0200 (CEST) Subject: [pypy-commit] pypy default: change warning to error Message-ID: <20130519094116.672921C01CD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64312:af944c826862 Date: 2013-05-19 11:40 +0200 http://bitbucket.org/pypy/pypy/changeset/af944c826862/ Log: change warning to error diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -121,12 +121,10 @@ __import__(name) except (ImportError, CompilationError, py.test.skip.Exception), e: errcls = e.__class__.__name__ - config.add_warning( + raise Exception( "The module %r is disabled\n" % (modname,) + "because importing %s raised %s\n" % (name, errcls) + str(e)) - raise ConflictConfigError("--withmod-%s: %s" % (modname, - errcls)) return validator else: return None From noreply at buildbot.pypy.org Sun May 19 12:47:27 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sun, 19 May 2013 12:47:27 +0200 (CEST) Subject: [pypy-commit] pypy default: update calls to stacklet_switch Message-ID: <20130519104727.AF2A11C1024@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64313:ffdda647471b Date: 2013-05-19 12:46 +0200 http://bitbucket.org/pypy/pypy/changeset/ffdda647471b/ Log: update calls to stacklet_switch diff --git a/rpython/translator/c/src/stacklet/tests.c b/rpython/translator/c/src/stacklet/tests.c --- a/rpython/translator/c/src/stacklet/tests.c +++ b/rpython/translator/c/src/stacklet/tests.c @@ -31,7 +31,7 @@ assert(status == 0); status = 1; assert(h != EMPTY_STACKLET_HANDLE); - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); assert(status == 2); assert(h != EMPTY_STACKLET_HANDLE); status = 3; @@ -45,7 +45,7 @@ assert(h != EMPTY_STACKLET_HANDLE); assert(status == 1); status = 2; - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); assert(status == 3); assert(h == EMPTY_STACKLET_HANDLE); } @@ -148,7 +148,7 @@ //printf("switch to %d\n", n); h = handles[n]; handles[n] = NULL; - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); } //printf("back in self = %d, coming from %d\n", self, comefrom); assert(nextstep == status); From noreply at buildbot.pypy.org Sun May 19 13:56:35 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:35 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Organize imports. Message-ID: <20130519115635.2FEED1C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64314:97a0064d87d2 Date: 2013-05-18 13:40 +0200 http://bitbucket.org/pypy/pypy/changeset/97a0064d87d2/ Log: Organize imports. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,21 +1,21 @@ +from sys import maxint + +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import (WrappedDefault, unwrap_spec, applevel, + interp2app) from pypy.interpreter.generator import GeneratorIterator +from pypy.interpreter.signature import Signature +from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype +from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.util import negate -from pypy.interpreter.gateway import WrappedDefault, unwrap_spec, applevel,\ - interp2app -from pypy.interpreter import baseobjspace -from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.signature import Signature +from rpython.rlib import rerased, jit, debug +from rpython.rlib.listsort import make_timsort_class from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) -from rpython.rlib.listsort import make_timsort_class -from rpython.rlib import rerased, jit, debug + resizelist_hint) from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.stdtypedef import StdTypeDef -from sys import maxint UNROLL_CUTOFF = 5 @@ -1626,7 +1626,7 @@ StringBaseTimSort = make_timsort_class() UnicodeBaseTimSort = make_timsort_class() -class KeyContainer(baseobjspace.W_Root): +class KeyContainer(W_Root): def __init__(self, w_key, w_item): self.w_key = w_key self.w_item = w_item From noreply at buildbot.pypy.org Sun May 19 13:56:36 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:36 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Kill W_AbstractListObject. Message-ID: <20130519115636.684D91C10FA@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64315:edb290673899 Date: 2013-05-18 13:44 +0200 http://bitbucket.org/pypy/pypy/changeset/edb290673899/ Log: Kill W_AbstractListObject. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -21,9 +21,6 @@ UNROLL_CUTOFF = 5 -class W_AbstractListObject(W_Root): - __slots__ = () - def make_range_list(space, start, step, length): if length <= 0: strategy = space.fromcache(EmptyListStrategy) @@ -129,7 +126,7 @@ return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) -class W_ListObject(W_AbstractListObject): +class W_ListObject(W_Root): def __init__(w_self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) w_self.space = space From noreply at buildbot.pypy.org Sun May 19 13:56:37 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:37 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Add __all__ declaration. Message-ID: <20130519115637.991711C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64316:519a5386eae6 Date: 2013-05-18 13:54 +0200 http://bitbucket.org/pypy/pypy/changeset/519a5386eae6/ Log: Add __all__ declaration. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -17,6 +17,8 @@ resizelist_hint) from rpython.tool.sourcetools import func_with_new_name +__all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] + UNROLL_CUTOFF = 5 From noreply at buildbot.pypy.org Sun May 19 13:56:38 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:38 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Don't use get_list_index in bytearrayobject. Message-ID: <20130519115638.C8A331C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64317:4c29c508e415 Date: 2013-05-18 13:59 +0200 http://bitbucket.org/pypy/pypy/changeset/4c29c508e415/ Log: Don't use get_list_index in bytearrayobject. diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -8,7 +8,7 @@ getbytevalue, makebytearraydata_w, new_bytearray) from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.listobject import get_list_index, get_positive_index +from pypy.objspace.std.listobject import get_positive_index from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject @@ -587,7 +587,7 @@ _setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00') def delitem__Bytearray_ANY(space, w_bytearray, w_idx): - idx = get_list_index(space, w_idx) + idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray index") try: del w_bytearray.data[idx] except IndexError: From noreply at buildbot.pypy.org Sun May 19 13:56:40 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:40 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Inline and kill one-line function get_list_index(). Message-ID: <20130519115640.0DDF31C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64318:fe09a3a46053 Date: 2013-05-18 14:04 +0200 http://bitbucket.org/pypy/pypy/changeset/fe09a3a46053/ Log: Inline and kill one-line function get_list_index(). diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -480,7 +480,8 @@ return self.getslice(start, stop, step, slicelength) try: - return self.getitem(get_list_index(space, w_index)) + index = space.getindex_w(w_index, space.w_IndexError, "list index") + return self.getitem(index) except IndexError: raise OperationError(space.w_IndexError, space.wrap("list index out of range")) @@ -506,7 +507,7 @@ self.setslice(start, step, slicelength, w_other) return - idx = get_list_index(space, w_index) + idx = space.getindex_w(w_index, space.w_IndexError, "list index") try: self.setitem(idx, w_any) except IndexError: @@ -530,7 +531,7 @@ self.deleteslice(start, step, slicelength) return - idx = get_list_index(space, w_idx) + idx = space.getindex_w(w_idx, space.w_IndexError, "list index") if idx < 0: idx += self.length() try: @@ -1682,11 +1683,6 @@ assert isinstance(b, KeyContainer) return CustomCompareSort.lt(self, a.w_key, b.w_key) -# ____________________________________________________________ - -def get_list_index(space, w_index): - return space.getindex_w(w_index, space.w_IndexError, "list index") - W_ListObject.typedef = StdTypeDef("list", __doc__ = """list() -> new list From noreply at buildbot.pypy.org Sun May 19 13:56:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:41 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Move get_positive_index() into util.py. Message-ID: <20130519115641.45A0B1C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64319:394ccea84eb4 Date: 2013-05-18 14:05 +0200 http://bitbucket.org/pypy/pypy/changeset/394ccea84eb4/ Log: Move get_positive_index() into util.py. diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -8,7 +8,6 @@ getbytevalue, makebytearraydata_w, new_bytearray) from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.listobject import get_positive_index from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject @@ -17,6 +16,7 @@ from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -10,7 +10,7 @@ from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.objspace.std.util import negate +from pypy.objspace.std.util import negate, get_positive_index from rpython.rlib import rerased, jit, debug from rpython.rlib.listsort import make_timsort_class from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, @@ -1604,16 +1604,6 @@ listrepr = app.interphook("listrepr") -def get_positive_index(where, length): - if where < 0: - where += length - if where < 0: - where = 0 - elif where > length: - where = length - assert where >= 0 - return where - # ____________________________________________________________ # Sorting diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py --- a/pypy/objspace/std/util.py +++ b/pypy/objspace/std/util.py @@ -16,3 +16,12 @@ _negator.func_name = 'negate-%s' % f.func_name return _negator +def get_positive_index(where, length): + if where < 0: + where += length + if where < 0: + where = 0 + elif where > length: + where = length + assert where >= 0 + return where From noreply at buildbot.pypy.org Sun May 19 13:56:42 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:42 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Move in-function imports to the top of listobject.py. Message-ID: <20130519115642.83D871C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64320:1e5c1c66fef7 Date: 2013-05-18 14:13 +0200 http://bitbucket.org/pypy/pypy/changeset/1e5c1c66fef7/ Log: Move in-function imports to the top of listobject.py. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,3 +1,4 @@ +import operator from sys import maxint from pypy.interpreter.baseobjspace import W_Root @@ -7,9 +8,16 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.interpreter.signature import Signature from pypy.objspace.std import slicetype +from pypy.objspace.std.floatobject import W_FloatObject +from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.iterobject import (W_FastListIterObject, + W_ReverseSeqIterObject) from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject +from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import negate, get_positive_index from rpython.rlib import rerased, jit, debug from rpython.rlib.listsort import make_timsort_class @@ -109,19 +117,15 @@ return i def is_W_IntObject(w_object): - from pypy.objspace.std.intobject import W_IntObject return type(w_object) is W_IntObject def is_W_StringObject(w_object): - from pypy.objspace.std.stringobject import W_StringObject return type(w_object) is W_StringObject def is_W_UnicodeObject(w_object): - from pypy.objspace.std.unicodeobject import W_UnicodeObject return type(w_object) is W_UnicodeObject def is_W_FloatObject(w_object): - from pypy.objspace.std.floatobject import W_FloatObject return type(w_object) is W_FloatObject def list_unroll_condition(w_list1, space, w_list2): @@ -378,7 +382,6 @@ descr_ne = negate(descr_eq) def _make_list_comparison(name): - import operator op = getattr(operator, name) def compare_unwrappeditems(self, space, w_list2): @@ -414,8 +417,7 @@ return wrapint(space, result) def descr_iter(self, space): - from pypy.objspace.std import iterobject - return iterobject.W_FastListIterObject(self) + return W_FastListIterObject(self) def descr_contains(self, space, w_obj): try: @@ -548,7 +550,6 @@ def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject return W_ReverseSeqIterObject(space, self, -1) def descr_reverse(self, space): @@ -925,7 +926,6 @@ w_other.copy_into(w_list) def _extend_from_iterable(self, w_list, w_iterable): - from pypy.objspace.std.tupleobject import W_AbstractTupleObject space = self.space if isinstance(w_iterable, W_AbstractTupleObject): w_list.__init__(space, w_iterable.getitems_copy()) From noreply at buildbot.pypy.org Sun May 19 13:56:43 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:43 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Inline and kill is_W_IntObject() and friends. Message-ID: <20130519115643.BF7271C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64321:726ade497623 Date: 2013-05-18 14:16 +0200 http://bitbucket.org/pypy/pypy/changeset/726ade497623/ Log: Inline and kill is_W_IntObject() and friends. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -60,28 +60,28 @@ # check for ints for w_obj in list_w: - if not is_W_IntObject(w_obj): + if not type(w_obj) is W_IntObject: break else: return space.fromcache(IntegerListStrategy) # check for strings for w_obj in list_w: - if not is_W_StringObject(w_obj): + if not type(w_obj) is W_StringObject: break else: return space.fromcache(StringListStrategy) # check for unicode for w_obj in list_w: - if not is_W_UnicodeObject(w_obj): + if not type(w_obj) is W_UnicodeObject: break else: return space.fromcache(UnicodeListStrategy) # check for floats for w_obj in list_w: - if not is_W_FloatObject(w_obj): + if not type(w_obj) is W_FloatObject: break else: return space.fromcache(FloatListStrategy) @@ -116,18 +116,6 @@ i += 1 return i -def is_W_IntObject(w_object): - return type(w_object) is W_IntObject - -def is_W_StringObject(w_object): - return type(w_object) is W_StringObject - -def is_W_UnicodeObject(w_object): - return type(w_object) is W_UnicodeObject - -def is_W_FloatObject(w_object): - return type(w_object) is W_FloatObject - def list_unroll_condition(w_list1, space, w_list2): return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) @@ -876,13 +864,13 @@ return self.erase(None) def switch_to_correct_strategy(self, w_list, w_item): - if is_W_IntObject(w_item): + if type(w_item) is W_IntObject: strategy = self.space.fromcache(IntegerListStrategy) - elif is_W_StringObject(w_item): + elif type(w_item) is W_StringObject: strategy = self.space.fromcache(StringListStrategy) - elif is_W_UnicodeObject(w_item): + elif type(w_item) is W_UnicodeObject: strategy = self.space.fromcache(UnicodeListStrategy) - elif is_W_FloatObject(w_item): + elif type(w_item) is W_FloatObject: strategy = self.space.fromcache(FloatListStrategy) else: strategy = self.space.fromcache(ObjectListStrategy) @@ -1012,7 +1000,7 @@ w_other.lstorage = w_list.lstorage def find(self, w_list, w_obj, startindex, stopindex): - if is_W_IntObject(w_obj): + if type(w_obj) is W_IntObject: obj = self.unwrap(w_obj) start, step, length = self.unerase(w_list.lstorage) if ((step > 0 and start <= obj <= start + (length - 1) * step and (start - obj) % step == 0) or @@ -1088,7 +1076,7 @@ return w_list.getslice(start, stop, step, length) def append(self, w_list, w_item): - if is_W_IntObject(w_item): + if type(w_item) is W_IntObject: self.switch_to_integer_strategy(w_list) else: w_list.switch_to_object_strategy() @@ -1478,7 +1466,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_IntObject(w_obj) + return type(w_obj) is W_IntObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(IntegerListStrategy) @@ -1508,7 +1496,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_FloatObject(w_obj) + return type(w_obj) is W_FloatObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(FloatListStrategy) @@ -1535,7 +1523,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_StringObject(w_obj) + return type(w_obj) is W_StringObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(StringListStrategy) @@ -1566,7 +1554,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_UnicodeObject(w_obj) + return type(w_obj) is W_UnicodeObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(UnicodeListStrategy) From noreply at buildbot.pypy.org Sun May 19 13:56:45 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:45 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: PEP 8 Message-ID: <20130519115645.0B3511C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64322:44748b5adb12 Date: 2013-05-19 13:35 +0200 http://bitbucket.org/pypy/pypy/changeset/44748b5adb12/ Log: PEP 8 diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -40,16 +40,19 @@ storage = strategy.erase((start, step, length)) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list(space): strategy = space.fromcache(EmptyListStrategy) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list_with_size(space, hint): strategy = SizeListStrategy(space, hint) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + @jit.look_inside_iff(lambda space, list_w, sizehint: jit.loop_unrolling_heuristic(list_w, len(list_w), UNROLL_CUTOFF)) def get_strategy_from_list_objects(space, list_w, sizehint): @@ -88,10 +91,12 @@ return space.fromcache(ObjectListStrategy) + def _get_printable_location(w_type): return ('list__do_extend_from_iterable [w_type=%s]' % w_type.getname(w_type.space)) + _do_extend_jitdriver = jit.JitDriver( name='list__do_extend_from_iterable', greens=['w_type'], @@ -116,9 +121,13 @@ i += 1 return i + def list_unroll_condition(w_list1, space, w_list2): - return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) + return (jit.loop_unrolling_heuristic(w_list1, w_list1.length(), + UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(w_list2, w_list2.length(), + UNROLL_CUTOFF)) + class W_ListObject(W_Root): def __init__(w_self, space, wrappeditems, sizehint=-1): @@ -150,7 +159,8 @@ def __repr__(w_self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, w_self.lstorage._x) + return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, + w_self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -169,7 +179,8 @@ list_w = self.getitems() strategy = self.space.fromcache(ObjectListStrategy) storage = strategy.erase(list_w) - w_objectlist = W_ListObject.from_storage_and_strategy(self.space, storage, strategy) + w_objectlist = W_ListObject.from_storage_and_strategy( + self.space, storage, strategy) return w_objectlist # ___________________________________________________ @@ -205,13 +216,12 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) def append(self, w_item): - 'L.append(object) -- append object to end' + """L.append(object) -- append object to end""" self.strategy.append(self, w_item) def length(self): @@ -224,8 +234,8 @@ return self.strategy.getitem(self, index) def getslice(self, start, stop, step, length): - """Returns a slice of the list defined by the arguments. Arguments must be - normalized (i.e. using normalize_simple_slice or W_Slice.indices4). + """Returns a slice of the list defined by the arguments. Arguments must + be normalized (i.e. using normalize_simple_slice or W_Slice.indices4). May raise IndexError.""" return self.strategy.getslice(self, start, stop, step, length) @@ -242,7 +252,7 @@ def getitems_unroll(self): """Returns a fixed-size list of all items after wrapping them. The JIT - will fully unroll this function. """ + will fully unroll this function.""" l = self.strategy.getitems_unroll(self) debug.make_sure_not_resized(l) return l @@ -253,22 +263,21 @@ return self.strategy.getitems_copy(self) def getitems_str(self): - """ Return the items in the list as unwrapped strings. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped strings. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_str(self) def getitems_unicode(self): - """ Return the items in the list as unwrapped unicodes. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped unicodes. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_unicode(self) def getitems_int(self): - """ Return the items in the list as unwrapped ints. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped ints. If the list does not + use the list strategy, return None.""" return self.strategy.getitems_int(self) # ___________________________________________________ - def mul(self, times): """Returns a copy of the list, multiplied by times. Argument must be unwrapped.""" @@ -358,8 +367,8 @@ if self.length() != w_other.length(): return space.w_False - # XXX in theory, this can be implemented more efficiently as well. let's - # not care for now + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now i = 0 while i < self.length() and i < w_other.length(): if not space.eq_w(self.getitem(i), w_other.getitem(i)): @@ -379,7 +388,8 @@ @jit.look_inside_iff(list_unroll_condition) def _compare_unwrappeditems(self, space, w_list2): - # needs to be safe against eq_w() mutating the w_lists behind our back + # needs to be safe against eq_w() mutating the w_lists behind our + # back # Search for the first index where items are different i = 0 # XXX in theory, this can be implemented more efficiently as well. @@ -509,15 +519,16 @@ start, stop = normalize_simple_slice(space, length, w_start, w_stop) if isinstance(w_iterable, W_ListObject): - self.setslice(start, 1, stop-start, w_iterable) + self.setslice(start, 1, stop - start, w_iterable) else: sequence_w = space.listview(w_iterable) w_other = W_ListObject(space, sequence_w) - self.setslice(start, 1, stop-start, w_other) + self.setslice(start, 1, stop - start, w_other) def descr_delitem(self, space, w_idx): if isinstance(w_idx, W_SliceObject): - start, stop, step, slicelength = w_idx.indices4(space, self.length()) + start, stop, step, slicelength = w_idx.indices4( + space, self.length()) self.deleteslice(start, step, slicelength) return @@ -530,11 +541,10 @@ raise OperationError(space.w_IndexError, space.wrap("list index out of range")) - def descr_delslice(self, space, w_start, w_stop): length = self.length() start, stop = normalize_simple_slice(space, length, w_start, w_stop) - self.deleteslice(start, 1, stop-start) + self.deleteslice(start, 1, stop - start) def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' @@ -575,7 +585,7 @@ space.wrap("pop from empty list")) # clearly differentiate between list.pop() and list.pop(index) if index == -1: - return self.pop_end() # cannot raise because list is not empty + return self.pop_end() # cannot raise because list is not empty if index < 0: index += length try: @@ -592,7 +602,7 @@ except ValueError: raise OperationError(space.w_ValueError, space.wrap("list.remove(x): x not in list")) - if i < self.length(): # otherwise list was mutated + if i < self.length(): # otherwise list was mutated self.pop(i) return space.w_None @@ -809,7 +819,8 @@ The storage is None. When items are added to the W_List a new RPython list is created and the strategy and storage of the W_List are changed depending to the added item. - W_Lists do not switch back to EmptyListStrategy when becoming empty again.""" + W_Lists do not switch back to EmptyListStrategy when becoming empty again. + """ _applevel_repr = "empty" @@ -828,7 +839,8 @@ unerase = staticmethod(unerase) def clone(self, w_list): - return W_ListObject.from_storage_and_strategy(self.space, w_list.lstorage, self) + return W_ListObject.from_storage_and_strategy( + self.space, w_list.lstorage, self) def copy_into(self, w_list, w_other): pass @@ -857,7 +869,8 @@ def getitems_copy(self, w_list): return [] - getitems_fixedsize = func_with_new_name(getitems_copy, "getitems_fixedsize") + getitems_fixedsize = func_with_new_name(getitems_copy, + "getitems_fixedsize") getitems_unroll = getitems_fixedsize def getstorage_copy(self, w_list): @@ -948,9 +961,9 @@ def is_empty_strategy(self): return True + class SizeListStrategy(EmptyListStrategy): - """ Like empty, but when modified it'll preallocate the size to sizehint - """ + """Like empty, but when modified it'll preallocate the size to sizehint.""" def __init__(self, space, sizehint): self.sizehint = sizehint ListStrategy.__init__(self, space) @@ -959,12 +972,13 @@ assert hint >= 0 self.sizehint = hint + class RangeListStrategy(ListStrategy): """RangeListStrategy is used when a list is created using the range method. - The storage is a tuple containing only three integers start, step and length - and elements are calculated based on these values. - On any operation destroying the range (inserting, appending non-ints) - the strategy is switched to IntegerListStrategy.""" + The storage is a tuple containing only three integers start, step and + length and elements are calculated based on these values. On any operation + destroying the range (inserting, appending non-ints) the strategy is + switched to IntegerListStrategy.""" _applevel_repr = "range" @@ -987,8 +1001,9 @@ unerase = staticmethod(unerase) def clone(self, w_list): - storage = w_list.lstorage # lstorage is tuple, no need to clone - w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self) + storage = w_list.lstorage # lstorage is tuple, no need to clone + w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, + self) return w_clone def _resize_hint(self, w_list, hint): @@ -1003,8 +1018,10 @@ if type(w_obj) is W_IntObject: obj = self.unwrap(w_obj) start, step, length = self.unerase(w_list.lstorage) - if ((step > 0 and start <= obj <= start + (length - 1) * step and (start - obj) % step == 0) or - (step < 0 and start + (length - 1) * step <= obj <= start and (start - obj) % step == 0)): + if ((step > 0 and start <= obj <= start + (length - 1) * step and + (start - obj) % step == 0) or + (step < 0 and start + (length - 1) * step <= obj <= start and + (start - obj) % step == 0)): index = (obj - start) // step else: raise ValueError @@ -1067,9 +1084,11 @@ @jit.dont_look_inside def getitems_fixedsize(self, w_list): return self._getitems_range_unroll(w_list, True) + def getitems_unroll(self, w_list): return self._getitems_range_unroll(w_list, True) - _getitems_range_unroll = jit.unroll_safe(func_with_new_name(_getitems_range, "_getitems_range_unroll")) + _getitems_range_unroll = jit.unroll_safe( + func_with_new_name(_getitems_range, "_getitems_range_unroll")) def getslice(self, w_list, start, stop, step, length): self.switch_to_integer_strategy(w_list) @@ -1139,6 +1158,7 @@ self.switch_to_integer_strategy(w_list) w_list.reverse() + class AbstractUnwrappedStrategy(object): _mixin_ = True @@ -1176,7 +1196,8 @@ def clone(self, w_list): l = self.unerase(w_list.lstorage) storage = self.erase(l[:]) - w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self) + w_clone = W_ListObject.from_storage_and_strategy( + self.space, storage, self) return w_clone def _resize_hint(self, w_list, hint): @@ -1207,12 +1228,13 @@ l = self.unerase(w_list.lstorage) try: r = l[index] - except IndexError: # make RPython raise the exception + except IndexError: # make RPython raise the exception raise return self.wrap(r) @jit.look_inside_iff(lambda self, w_list: - jit.loop_unrolling_heuristic(w_list, w_list.length(), UNROLL_CUTOFF)) + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF)) def getitems_copy(self, w_list): return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @@ -1221,7 +1243,8 @@ return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @jit.look_inside_iff(lambda self, w_list: - jit.loop_unrolling_heuristic(w_list, w_list.length(), UNROLL_CUTOFF)) + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF)) def getitems_fixedsize(self, w_list): return self.getitems_unroll(w_list) @@ -1236,7 +1259,8 @@ assert stop >= 0 sublist = l[start:stop] storage = self.erase(sublist) - return W_ListObject.from_storage_and_strategy(self.space, storage, self) + return W_ListObject.from_storage_and_strategy( + self.space, storage, self) else: subitems_w = [self._none_value] * length l = self.unerase(w_list.lstorage) @@ -1247,9 +1271,10 @@ except IndexError: raise storage = self.erase(subitems_w) - return W_ListObject.from_storage_and_strategy(self.space, storage, self) + return W_ListObject.from_storage_and_strategy( + self.space, storage, self) - def append(self, w_list, w_item): + def append(self, w_list, w_item): if self.is_correct_type(w_item): self.unerase(w_list.lstorage).append(self.unwrap(w_item)) return @@ -1298,11 +1323,11 @@ if self is self.space.fromcache(ObjectListStrategy): w_other = w_other._temporarily_as_objects() - elif (not self.list_is_correct_type(w_other) and - w_other.length() != 0): + elif not self.list_is_correct_type(w_other) and w_other.length() != 0: w_list.switch_to_object_strategy() w_other_as_object = w_other._temporarily_as_objects() - assert w_other_as_object.strategy is self.space.fromcache(ObjectListStrategy) + assert (w_other_as_object.strategy is + self.space.fromcache(ObjectListStrategy)) w_list.setslice(start, step, slicelength, w_other_as_object) return @@ -1318,13 +1343,14 @@ lim = start + len2 i = newsize - 1 while i >= lim: - items[i] = items[i-delta] + items[i] = items[i - delta] i -= 1 elif delta == 0: pass else: - assert start >= 0 # start<0 is only possible with slicelength==0 - del items[start:start+delta] + # start < 0 is only possible with slicelength == 0 + assert start >= 0 + del items[start:start + delta] elif len2 != slicelength: # No resize for extended slices raise operationerrfmt(self.space.w_ValueError, "attempt to " "assign sequence of size %d to extended slice of size %d", @@ -1369,7 +1395,7 @@ if step == 1: assert start >= 0 if slicelength > 0: - del items[start:start+slicelength] + del items[start:start + slicelength] else: n = len(items) i = start @@ -1378,15 +1404,15 @@ j = i + 1 i += step while j < i: - items[j-discard] = items[j] + items[j - discard] = items[j] j += 1 j = i + 1 while j < n: - items[j-slicelength] = items[j] + items[j - slicelength] = items[j] j += 1 start = n - slicelength - assert start >= 0 # annotator hint + assert start >= 0 # annotator hint del items[start:] def pop_end(self, w_list): @@ -1419,6 +1445,7 @@ def reverse(self, w_list): self.unerase(w_list.lstorage).reverse() + class ObjectListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "object" @@ -1451,6 +1478,7 @@ def getitems(self, w_list): return self.unerase(w_list.lstorage) + class IntegerListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = 0 _applevel_repr = "int" @@ -1481,6 +1509,7 @@ def getitems_int(self, w_list): return self.unerase(w_list.lstorage) + class FloatListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = 0.0 _applevel_repr = "float" @@ -1508,6 +1537,7 @@ if reverse: l.reverse() + class StringListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "str" @@ -1604,11 +1634,13 @@ StringBaseTimSort = make_timsort_class() UnicodeBaseTimSort = make_timsort_class() + class KeyContainer(W_Root): def __init__(self, w_key, w_item): self.w_key = w_key self.w_item = w_item + # NOTE: all the subclasses of TimSort should inherit from a common subclass, # so make sure that only SimpleSort inherits directly from TimSort. # This is necessary to hide the parent method TimSort.lt() from the @@ -1618,22 +1650,27 @@ space = self.space return space.is_true(space.lt(a, b)) + class IntSort(IntBaseTimSort): def lt(self, a, b): return a < b + class FloatSort(FloatBaseTimSort): def lt(self, a, b): return a < b + class StringSort(StringBaseTimSort): def lt(self, a, b): return a < b + class UnicodeSort(UnicodeBaseTimSort): def lt(self, a, b): return a < b + class CustomCompareSort(SimpleSort): def lt(self, a, b): space = self.space @@ -1648,6 +1685,7 @@ raise return result < 0 + class CustomKeySort(SimpleSort): def lt(self, a, b): assert isinstance(a, KeyContainer) @@ -1655,6 +1693,7 @@ space = self.space return space.is_true(space.lt(a.w_key, b.w_key)) + class CustomKeyCompareSort(CustomCompareSort): def lt(self, a, b): assert isinstance(a, KeyContainer) @@ -1704,4 +1743,4 @@ extend = interp2app(W_ListObject.extend), insert = interp2app(W_ListObject.descr_insert), remove = interp2app(W_ListObject.descr_remove), - ) +) From noreply at buildbot.pypy.org Sun May 19 13:56:46 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 13:56:46 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: hg merge default Message-ID: <20130519115646.5B7871C1024@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64323:79cd4b4f08fc Date: 2013-05-19 13:54 +0200 http://bitbucket.org/pypy/pypy/changeset/79cd4b4f08fc/ Log: hg merge default diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -121,12 +121,10 @@ __import__(name) except (ImportError, CompilationError, py.test.skip.Exception), e: errcls = e.__class__.__name__ - config.add_warning( + raise Exception( "The module %r is disabled\n" % (modname,) + "because importing %s raised %s\n" % (name, errcls) + str(e)) - raise ConflictConfigError("--withmod-%s: %s" % (modname, - errcls)) return validator else: return None diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -10,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -120,6 +122,15 @@ source = rffi.charp2str(ll_source) return _pypy_execute_source(source) + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + rthread.gc_thread_start() + w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), space.builtin_modules['__builtin__']) @@ -137,6 +148,8 @@ return 0 return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, 'pypy_setup_home': pypy_setup_home} def call_finish(space): diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -853,9 +853,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -864,6 +865,37 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists/sets of constants in the context of "in"/"not in". + + lists are folded into tuples, sets into frozensets, otherwise + returns False + """ + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -973,3 +973,30 @@ counts = self.count_instructions(source3) assert counts[ops.BUILD_LIST] == 1 assert ops.BUILD_LIST_FROM_ARG not in counts + + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts 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 @@ -903,24 +903,35 @@ expected_path = [str(prefix.join(subdir).ensure(dir=1)) for subdir in ('lib_pypy', 'lib-python/%s' % cpy_ver)] + # an empty directory from where we can't find the stdlib + tmp_dir = str(udir.join('tmp').ensure(dir=1)) self.w_goal_dir = self.space.wrap(goal_dir) self.w_fake_exe = self.space.wrap(str(fake_exe)) self.w_expected_path = self.space.wrap(expected_path) self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir)) + self.w_tmp_dir = self.space.wrap(tmp_dir) + foo_py = prefix.join('foo.py').write("pass") self.w_foo_py = self.space.wrap(str(foo_py)) def test_setup_bootstrap_path(self): - import sys + # Check how sys.path is handled depending on if we can find a copy of + # the stdlib in setup_bootstrap_path. + import sys, os old_sys_path = sys.path[:] + old_cwd = os.getcwd() + sys.path.append(self.goal_dir) + # make sure cwd does not contain a stdlib + os.chdir(self.tmp_dir) + tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c') try: import app_main - app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found + app_main.setup_bootstrap_path(tmp_pypy_c) # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + assert sys.path == old_sys_path + [self.goal_dir] app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe @@ -933,6 +944,7 @@ assert newpath[:len(self.expected_path)] == self.expected_path finally: sys.path[:] = old_sys_path + os.chdir(old_cwd) def test_trunk_can_be_prefix(self): import sys diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -936,6 +936,21 @@ output = s.getvalue() assert "LOAD_GLOBAL" not in output + def test_folding_of_list_constants(self): + source = 'a in [1, 2, 3]' + co = compile(source, '', 'exec') + i = co.co_consts.index((1, 2, 3)) + assert i > -1 + assert isinstance(co.co_consts[i], tuple) + + def test_folding_of_set_constants(self): + source = 'a in {1, 2, 3}' + co = compile(source, '', 'exec') + i = co.co_consts.index(set([1, 2, 3])) + assert i > -1 + assert isinstance(co.co_consts[i], frozenset) + + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,15 +1,16 @@ -from pypy.interpreter import gateway from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import ( + WrappedDefault, applevel, interp2app, unwrap_spec) from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.util import negate -from rpython.rlib import rerased, jit +from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null -from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint -from rpython.tool.sourcetools import func_with_new_name +from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize +from rpython.tool.sourcetools import func_renamer, func_with_new_name UNROLL_CUTOFF = 5 @@ -19,7 +20,7 @@ return space.is_w(space.type(w_key), space.w_str) def _never_equal_to_string(space, w_lookup_type): - """ Handles the case of a non string key lookup. + """Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. XXX The types should provide such a flag. """ @@ -33,7 +34,7 @@ @specialize.call_location() def w_dict_unrolling_heuristic(w_dct): - """ In which cases iterating over dict items can be unrolled. + """In which cases iterating over dict items can be unrolled. Note that w_dct is an instance of W_DictMultiObject, not necesarilly an actual dict """ @@ -44,8 +45,8 @@ class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, - instance=False, strdict=False, kwargs=False): - + instance=False, strdict=False, + kwargs=False): if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None @@ -55,11 +56,9 @@ elif space.config.objspace.std.withmapdict and instance: from pypy.objspace.std.mapdict import MapDictStrategy strategy = space.fromcache(MapDictStrategy) - elif instance or strdict or module: assert w_type is None strategy = space.fromcache(StringDictStrategy) - elif kwargs: assert w_type is None from pypy.objspace.std.kwargsdict import EmptyKwargsDictStrategy @@ -80,7 +79,7 @@ self.dstorage = storage def __repr__(w_self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): @@ -93,12 +92,10 @@ def missing_method(w_dict, space, w_key): if not space.is_w(space.type(w_dict), space.w_dict): - w_missing = space.lookup(w_dict, "__missing__") - if w_missing is None: - return None - return space.get_and_call_function(w_missing, w_dict, w_key) - else: - return None + w_missing = space.lookup(w_dict, '__missing__') + if w_missing is not None: + return space.get_and_call_function(w_missing, w_dict, w_key) + return None def initialize_content(w_self, list_pairs_w): for w_k, w_v in list_pairs_w: @@ -151,7 +148,7 @@ if self.length() != w_other.length(): return space.w_False iteratorimplementation = self.iteritems() - while 1: + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break @@ -228,7 +225,8 @@ space.raise_key_error(w_key) def descr_reversed(self, space): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + raise OperationError(space.w_TypeError, space.wrap( + 'argument to reversed() must be a sequence')) def descr_copy(self, space): """D.copy() -> a shallow copy of D""" @@ -280,16 +278,13 @@ """D.clear() -> None. Remove all items from D.""" self.clear() - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_get(self, space, w_key, w_default): """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" w_value = self.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default + return w_value if w_value is not None else w_default - @gateway.unwrap_spec(defaults_w='args_w') + @unwrap_spec(defaults_w='args_w') def descr_pop(self, space, w_key, defaults_w): """D.pop(k[,d]) -> v, remove specified key and return the corresponding value\nIf key is not found, d is returned if given, @@ -320,7 +315,7 @@ space.wrap("popitem(): dictionary is empty")) return space.newtuple([w_key, w_value]) - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_setdefault(self, space, w_key, w_default): """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" return self.setdefault(w_key, w_default) @@ -352,7 +347,7 @@ _add_indirections() -app = gateway.applevel(''' +app = applevel(''' def dictrepr(currently_in_repr, d): if len(d) == 0: return "{}" @@ -388,46 +383,46 @@ d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(W_DictMultiObject.descr_new), - fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, - as_classmethod=True), + __new__ = interp2app(W_DictMultiObject.descr_new), + fromkeys = interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), __hash__ = None, - __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), - __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + __repr__ = interp2app(W_DictMultiObject.descr_repr), + __init__ = interp2app(W_DictMultiObject.descr_init), - __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), - __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), - __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), - __le__ = gateway.interp2app(W_DictMultiObject.descr_le), - __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), - __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), + __eq__ = interp2app(W_DictMultiObject.descr_eq), + __ne__ = interp2app(W_DictMultiObject.descr_ne), + __lt__ = interp2app(W_DictMultiObject.descr_lt), + __le__ = interp2app(W_DictMultiObject.descr_le), + __gt__ = interp2app(W_DictMultiObject.descr_gt), + __ge__ = interp2app(W_DictMultiObject.descr_ge), - __len__ = gateway.interp2app(W_DictMultiObject.descr_len), - __iter__ = gateway.interp2app(W_DictMultiObject.descr_iter), - __contains__ = gateway.interp2app(W_DictMultiObject.descr_contains), + __len__ = interp2app(W_DictMultiObject.descr_len), + __iter__ = interp2app(W_DictMultiObject.descr_iter), + __contains__ = interp2app(W_DictMultiObject.descr_contains), - __getitem__ = gateway.interp2app(W_DictMultiObject.descr_getitem), - __setitem__ = gateway.interp2app(W_DictMultiObject.descr_setitem), - __delitem__ = gateway.interp2app(W_DictMultiObject.descr_delitem), + __getitem__ = interp2app(W_DictMultiObject.descr_getitem), + __setitem__ = interp2app(W_DictMultiObject.descr_setitem), + __delitem__ = interp2app(W_DictMultiObject.descr_delitem), - __reversed__ = gateway.interp2app(W_DictMultiObject.descr_reversed), - copy = gateway.interp2app(W_DictMultiObject.descr_copy), - items = gateway.interp2app(W_DictMultiObject.descr_items), - keys = gateway.interp2app(W_DictMultiObject.descr_keys), - values = gateway.interp2app(W_DictMultiObject.descr_values), - iteritems = gateway.interp2app(W_DictMultiObject.descr_iteritems), - iterkeys = gateway.interp2app(W_DictMultiObject.descr_iterkeys), - itervalues = gateway.interp2app(W_DictMultiObject.descr_itervalues), - viewkeys = gateway.interp2app(W_DictMultiObject.descr_viewkeys), - viewitems = gateway.interp2app(W_DictMultiObject.descr_viewitems), - viewvalues = gateway.interp2app(W_DictMultiObject.descr_viewvalues), - has_key = gateway.interp2app(W_DictMultiObject.descr_has_key), - clear = gateway.interp2app(W_DictMultiObject.descr_clear), - get = gateway.interp2app(W_DictMultiObject.descr_get), - pop = gateway.interp2app(W_DictMultiObject.descr_pop), - popitem = gateway.interp2app(W_DictMultiObject.descr_popitem), - setdefault = gateway.interp2app(W_DictMultiObject.descr_setdefault), - update = gateway.interp2app(W_DictMultiObject.descr_update), + __reversed__ = interp2app(W_DictMultiObject.descr_reversed), + copy = interp2app(W_DictMultiObject.descr_copy), + items = interp2app(W_DictMultiObject.descr_items), + keys = interp2app(W_DictMultiObject.descr_keys), + values = interp2app(W_DictMultiObject.descr_values), + iteritems = interp2app(W_DictMultiObject.descr_iteritems), + iterkeys = interp2app(W_DictMultiObject.descr_iterkeys), + itervalues = interp2app(W_DictMultiObject.descr_itervalues), + viewkeys = interp2app(W_DictMultiObject.descr_viewkeys), + viewitems = interp2app(W_DictMultiObject.descr_viewitems), + viewvalues = interp2app(W_DictMultiObject.descr_viewvalues), + has_key = interp2app(W_DictMultiObject.descr_has_key), + clear = interp2app(W_DictMultiObject.descr_clear), + get = interp2app(W_DictMultiObject.descr_get), + pop = interp2app(W_DictMultiObject.descr_pop), + popitem = interp2app(W_DictMultiObject.descr_popitem), + setdefault = interp2app(W_DictMultiObject.descr_setdefault), + update = interp2app(W_DictMultiObject.descr_update), ) @@ -441,7 +436,7 @@ def w_keys(self, w_dict): iterator = self.iterkeys(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key = iterator.next_key() if w_key is not None: result.append(w_key) @@ -451,7 +446,7 @@ def values(self, w_dict): iterator = self.itervalues(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_value = iterator.next_value() if w_value is not None: result.append(w_value) @@ -461,7 +456,7 @@ def items(self, w_dict): iterator = self.iteritems(w_dict) result = newlist_hint(self.length(w_dict)) - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is not None: result.append(self.space.newtuple([w_key, w_value])) @@ -503,7 +498,7 @@ unerase = staticmethod(unerase) def get_empty_storage(self): - return self.erase(None) + return self.erase(None) def switch_to_correct_strategy(self, w_dict, w_key): withidentitydict = self.space.config.objspace.std.withidentitydict @@ -606,7 +601,7 @@ # Iterator Implementation base classes def _new_next(TP): - if TP == 'key' or TP == 'value': + if TP in ('key', 'value'): EMPTY = None else: EMPTY = None, None @@ -614,10 +609,12 @@ def next(self): if self.dictimplementation is None: return EMPTY + space = self.space if self.len != self.dictimplementation.length(): self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed size during iteration")) + msg = "dictionary changed size during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) + # look for the next entry if self.pos < self.len: result = getattr(self, 'next_' + TP + '_entry')() @@ -635,8 +632,8 @@ w_value = self.dictimplementation.getitem(w_key) if w_value is None: self.len = -1 # Make this error state sticky - raise OperationError(self.space.w_RuntimeError, - self.space.wrap("dictionary changed during iteration")) + msg = "dictionary changed during iteration" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) return (w_key, w_value) # no more entries self.dictimplementation = None @@ -769,7 +766,8 @@ def setdefault(self, w_dict, w_key, w_default): if self.is_correct_type(w_key): - return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), w_default) + return self.unerase(w_dict.dstorage).setdefault(self.unwrap(w_key), + w_default) else: self.switch_to_object_strategy(w_dict) return w_dict.setdefault(w_key, w_default) @@ -809,7 +807,7 @@ space = self.space dict_w = self.unerase(w_dict.dstorage) return [space.newtuple([self.wrap(key), w_value]) - for (key, w_value) in dict_w.iteritems()] + for (key, w_value) in dict_w.iteritems()] def popitem(self, w_dict): key, value = self.unerase(w_dict.dstorage).popitem() @@ -854,9 +852,9 @@ return True def get_empty_storage(self): - new_dict = r_dict(self.space.eq_w, self.space.hash_w, - force_non_null=True) - return self.erase(new_dict) + new_dict = r_dict(self.space.eq_w, self.space.hash_w, + force_non_null=True) + return self.erase(new_dict) def _never_equal_to(self, w_lookup_type): return False @@ -1056,7 +1054,7 @@ w_dict_unrolling_heuristic(w_data)) def update1_dict_dict(space, w_dict, w_data): iterator = w_data.iteritems() - while 1: + while True: w_key, w_value = iterator.next_item() if w_key is None: break @@ -1094,16 +1092,18 @@ update1(space, w_dict, w_kwds) def characterize(space, w_a, w_b): - """ (similar to CPython) - returns the smallest key in acontent for which b's value is different or absent and this value """ + """(similar to CPython) + returns the smallest key in acontent for which b's value is + different or absent and this value""" w_smallest_diff_a_key = None w_its_value = None iteratorimplementation = w_a.iteritems() - while 1: + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break - if w_smallest_diff_a_key is None or space.is_true(space.lt(w_key, w_smallest_diff_a_key)): + if w_smallest_diff_a_key is None or space.is_true(space.lt( + w_key, w_smallest_diff_a_key)): w_bvalue = w_b.getitem(w_key) if w_bvalue is None: w_its_value = w_val @@ -1151,7 +1151,7 @@ w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('dictiter_surrogate_new') - w_typeobj = space.gettypeobject(W_BaseDictMultiIterObject.typedef) + w_typeobj = space.type(self) raise OperationError( space.w_TypeError, @@ -1159,12 +1159,15 @@ # XXXXXX get that working again # we cannot call __init__ since we don't have the original dict - if isinstance(self, W_DictIter_Keys): - w_clone = space.allocate_instance(W_DictIter_Keys, w_typeobj) - elif isinstance(self, W_DictIter_Values): - w_clone = space.allocate_instance(W_DictIter_Values, w_typeobj) - elif isinstance(self, W_DictIter_Items): - w_clone = space.allocate_instance(W_DictIter_Items, w_typeobj) + if isinstance(self, W_DictMultiIterKeysObject): + w_clone = space.allocate_instance(W_DictMultiIterKeysObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterValuesObject): + w_clone = space.allocate_instance(W_DictMultiIterValuesObject, + w_typeobj) + elif isinstance(self, W_DictMultiIterItemsObject): + w_clone = space.allocate_instance(W_DictMultiIterItemsObject, + w_typeobj) else: msg = "unsupported dictiter type '%s' during pickling" % (self,) raise OperationError(space.w_TypeError, space.wrap(msg)) @@ -1179,10 +1182,7 @@ w_clone.pos += 1 stuff = [w_clone.next_entry() for i in range(w_clone.pos, w_clone.len)] w_res = space.newlist(stuff) - tup = [ - w_res - ] - w_ret = space.newtuple([new_inst, space.newtuple(tup)]) + w_ret = space.newtuple([new_inst, space.newtuple([w_res])]) return w_ret @@ -1212,23 +1212,26 @@ W_DictMultiIterItemsObject.typedef = StdTypeDef( "dict_iteritems", - __iter__ = gateway.interp2app(W_DictMultiIterItemsObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterItemsObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterItemsObject.descr_iter), + next = interp2app(W_DictMultiIterItemsObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) W_DictMultiIterKeysObject.typedef = StdTypeDef( "dict_iterkeys", - __iter__ = gateway.interp2app(W_DictMultiIterKeysObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterKeysObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterKeysObject.descr_iter), + next = interp2app(W_DictMultiIterKeysObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) W_DictMultiIterValuesObject.typedef = StdTypeDef( "dict_itervalues", - __iter__ = gateway.interp2app(W_DictMultiIterValuesObject.descr_iter), - next = gateway.interp2app(W_DictMultiIterValuesObject.descr_next), - __length_hint__ = gateway.interp2app(W_BaseDictMultiIterObject.descr_length_hint) + __iter__ = interp2app(W_DictMultiIterValuesObject.descr_iter), + next = interp2app(W_DictMultiIterValuesObject.descr_next), + __length_hint__ = interp2app(W_BaseDictMultiIterObject.descr_length_hint), + __reduce__ = interp2app(W_BaseDictMultiIterObject.descr_reduce), ) @@ -1245,45 +1248,88 @@ return space.wrap("%s(%s)" % (space.type(self).getname(space), space.str_w(w_repr))) - def descr_eq(self, space, w_otherview): - if not space.eq_w(space.len(self), space.len(w_otherview)): - return space.w_False - - w_iter = space.iter(self) - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - if not space.is_true(space.contains(w_otherview, w_item)): - return space.w_False - return space.w_True - def descr_len(self, space): return space.len(self.w_dict) - def descr_and(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "intersection_update", w_otherview) - return w_set +def _all_contained_in(space, w_dictview, w_other): + w_iter = space.iter(w_dictview) + for w_item in space.iteriterable(w_iter): + if not space.is_true(space.contains(w_other, w_item)): + return space.w_False + return space.w_True - def descr_or(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "update", w_otherview) - return w_set +def _is_set_like(w_other): + from pypy.objspace.std.setobject import W_BaseSetObject + return (isinstance(w_other, W_BaseSetObject) or + isinstance(w_other, W_DictViewKeysObject) or + isinstance(w_other, W_DictViewItemsObject)) - def descr_xor(self, space, w_otherview): - w_set = space.call_function(space.w_set, self) - space.call_method(w_set, "symmetric_difference_update", w_otherview) - return w_set +class SetLikeDictView(object): + _mixin_ = True -class W_DictViewItemsObject(W_DictViewObject): + def descr_eq(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) == space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_ne(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + return space.not_(space.eq(self, w_other)) + + def descr_lt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) < space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_le(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) <= space.len_w(w_other): + return _all_contained_in(space, self, w_other) + return space.w_False + + def descr_gt(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) > space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def descr_ge(self, space, w_other): + if not _is_set_like(w_other): + return space.w_NotImplemented + if space.len_w(self) >= space.len_w(w_other): + return _all_contained_in(space, w_other, self) + return space.w_False + + def _as_set_op(name, methname): + @func_renamer('descr_' + name) + def op(self, space, w_other): + w_set = space.call_function(space.w_set, self) + space.call_method(w_set, methname, w_other) + return w_set + @func_renamer('descr_r' + name) + def rop(self, space, w_other): + w_set = space.call_function(space.w_set, w_other) + space.call_method(w_set, methname, self) + return w_set + return op, rop + + descr_sub, descr_rsub = _as_set_op('sub', 'difference_update') + descr_and, descr_rand = _as_set_op('and', 'intersection_update') + descr_or, descr_ror = _as_set_op('or', 'update') + descr_xor, descr_rxor = _as_set_op('xor', 'symmetric_difference_update') + +class W_DictViewItemsObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterItemsObject(space, self.w_dict.iteritems()) -class W_DictViewKeysObject(W_DictViewObject): +class W_DictViewKeysObject(W_DictViewObject, SetLikeDictView): def descr_iter(self, space): return W_DictMultiIterKeysObject(space, self.w_dict.iterkeys()) @@ -1293,33 +1339,53 @@ W_DictViewItemsObject.typedef = StdTypeDef( "dict_items", - __repr__ = gateway.interp2app(W_DictViewItemsObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewItemsObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewItemsObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewItemsObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewItemsObject.descr_and), - __or__ = gateway.interp2app(W_DictViewItemsObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewItemsObject.descr_xor) + __repr__ = interp2app(W_DictViewItemsObject.descr_repr), + __len__ = interp2app(W_DictViewItemsObject.descr_len), + __iter__ = interp2app(W_DictViewItemsObject.descr_iter), + + __eq__ = interp2app(W_DictViewItemsObject.descr_eq), + __ne__ = interp2app(W_DictViewItemsObject.descr_ne), + __lt__ = interp2app(W_DictViewItemsObject.descr_lt), + __le__ = interp2app(W_DictViewItemsObject.descr_le), + __gt__ = interp2app(W_DictViewItemsObject.descr_gt), + __ge__ = interp2app(W_DictViewItemsObject.descr_ge), + + __sub__ = interp2app(W_DictViewItemsObject.descr_sub), + __rsub__ = interp2app(W_DictViewItemsObject.descr_rsub), + __and__ = interp2app(W_DictViewItemsObject.descr_and), + __rand__ = interp2app(W_DictViewItemsObject.descr_rand), + __or__ = interp2app(W_DictViewItemsObject.descr_or), + __ror__ = interp2app(W_DictViewItemsObject.descr_ror), + __xor__ = interp2app(W_DictViewItemsObject.descr_xor), + __rxor__ = interp2app(W_DictViewItemsObject.descr_rxor), ) W_DictViewKeysObject.typedef = StdTypeDef( "dict_keys", - __repr__ = gateway.interp2app(W_DictViewKeysObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewKeysObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewKeysObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewKeysObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewKeysObject.descr_and), - __or__ = gateway.interp2app(W_DictViewKeysObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewKeysObject.descr_xor) + __repr__ = interp2app(W_DictViewKeysObject.descr_repr), + __len__ = interp2app(W_DictViewKeysObject.descr_len), + __iter__ = interp2app(W_DictViewKeysObject.descr_iter), + + __eq__ = interp2app(W_DictViewKeysObject.descr_eq), + __ne__ = interp2app(W_DictViewKeysObject.descr_ne), + __lt__ = interp2app(W_DictViewKeysObject.descr_lt), + __le__ = interp2app(W_DictViewKeysObject.descr_le), + __gt__ = interp2app(W_DictViewKeysObject.descr_gt), + __ge__ = interp2app(W_DictViewKeysObject.descr_ge), + + __sub__ = interp2app(W_DictViewKeysObject.descr_sub), + __rsub__ = interp2app(W_DictViewKeysObject.descr_rsub), + __and__ = interp2app(W_DictViewKeysObject.descr_and), + __rand__ = interp2app(W_DictViewKeysObject.descr_rand), + __or__ = interp2app(W_DictViewKeysObject.descr_or), + __ror__ = interp2app(W_DictViewKeysObject.descr_ror), + __xor__ = interp2app(W_DictViewKeysObject.descr_xor), + __rxor__ = interp2app(W_DictViewKeysObject.descr_rxor), ) W_DictViewValuesObject.typedef = StdTypeDef( "dict_values", - __repr__ = gateway.interp2app(W_DictViewValuesObject.descr_repr), - __eq__ = gateway.interp2app(W_DictViewValuesObject.descr_eq), - __len__ = gateway.interp2app(W_DictViewValuesObject.descr_len), - __iter__ = gateway.interp2app(W_DictViewValuesObject.descr_iter), - __and__ = gateway.interp2app(W_DictViewValuesObject.descr_and), - __or__ = gateway.interp2app(W_DictViewValuesObject.descr_or), - __xor__ = gateway.interp2app(W_DictViewValuesObject.descr_xor) + __repr__ = interp2app(W_DictViewValuesObject.descr_repr), + __len__ = interp2app(W_DictViewValuesObject.descr_len), + __iter__ = interp2app(W_DictViewValuesObject.descr_iter), ) diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py --- a/pypy/objspace/std/test/test_dictmultiobject.py +++ b/pypy/objspace/std/test/test_dictmultiobject.py @@ -696,6 +696,7 @@ assert d.viewkeys() == e.viewkeys() del e["a"] assert d.viewkeys() != e.viewkeys() + assert not d.viewkeys() == 42 def test_dict_items(self): d = {1: 10, "a": "ABC"} @@ -720,6 +721,7 @@ assert d.viewitems() == e.viewitems() e["a"] = "def" assert d.viewitems() != e.viewitems() + assert not d.viewitems() == 42 def test_dict_mixed_keys_items(self): d = {(1, 1): 11, (2, 2): 22} @@ -732,6 +734,7 @@ values = d.viewvalues() assert set(values) == set([10, "ABC"]) assert len(values) == 2 + assert not values == 42 def test_dict_repr(self): d = {1: 10, "a": "ABC"} @@ -774,6 +777,13 @@ assert d1.viewkeys() ^ set(d2.viewkeys()) == set('ac') assert d1.viewkeys() ^ set(d3.viewkeys()) == set('abde') + assert d1.viewkeys() - d1.viewkeys() == set() + assert d1.viewkeys() - d2.viewkeys() == set('a') + assert d1.viewkeys() - d3.viewkeys() == set('ab') + assert d1.viewkeys() - set(d1.viewkeys()) == set() + assert d1.viewkeys() - set(d2.viewkeys()) == set('a') + assert d1.viewkeys() - set(d3.viewkeys()) == set('ab') + def test_items_set_operations(self): d1 = {'a': 1, 'b': 2} d2 = {'a': 2, 'b': 2} @@ -802,6 +812,113 @@ assert (d1.viewitems() ^ d3.viewitems() == set([('a', 1), ('b', 2), ('d', 4), ('e', 5)])) + assert d1.viewitems() - d1.viewitems() == set() + assert d1.viewitems() - d2.viewitems() == set([('a', 1)]) + assert d1.viewitems() - d3.viewitems() == set([('a', 1), ('b', 2)]) + + def test_keys_set_operations_any_type(self): + d = {1: u'a', 2: u'b', 3: u'c'} + assert d.viewkeys() & set([1]) == set([1]) + assert d.viewkeys() & {1: u'foo'} == set([1]) + assert d.viewkeys() & [1, 2] == set([1, 2]) + # + assert set([1]) & d.viewkeys() == set([1]) + assert {1: u'foo'} & d.viewkeys() == set([1]) + assert [1, 2] & d.viewkeys() == set([1, 2]) + # + assert d.viewkeys() - set([1]) == set([2, 3]) + assert set([1, 4]) - d.viewkeys() == set([4]) + # + assert d.viewkeys() == set([1, 2, 3]) + # XXX: The following 4 commented out are CPython 2.7 bugs + #assert set([1, 2, 3]) == d.viewkeys() + assert d.viewkeys() == frozenset(set([1, 2, 3])) + #assert frozenset(set([1, 2, 3])) == d.viewkeys() + assert not d.viewkeys() != set([1, 2, 3]) + #assert not set([1, 2, 3]) != d.viewkeys() + assert not d.viewkeys() != frozenset(set([1, 2, 3])) + #assert not frozenset(set([1, 2, 3])) != d.viewkeys() + + def test_items_set_operations_any_type(self): + d = {1: u'a', 2: u'b', 3: u'c'} + assert d.viewitems() & set([(1, u'a')]) == set([(1, u'a')]) + assert d.viewitems() & {(1, u'a'): u'foo'} == set([(1, u'a')]) + assert d.viewitems() & [(1, u'a'), (2, u'b')] == set([(1, u'a'), (2, u'b')]) + # + assert set([(1, u'a')]) & d.viewitems() == set([(1, u'a')]) + assert {(1, u'a'): u'foo'} & d.viewitems() == set([(1, u'a')]) + assert [(1, u'a'), (2, u'b')] & d.viewitems() == set([(1, u'a'), (2, u'b')]) + # + assert d.viewitems() - set([(1, u'a')]) == set([(2, u'b'), (3, u'c')]) + assert set([(1, u'a'), 4]) - d.viewitems() == set([4]) + # + assert d.viewitems() == set([(1, u'a'), (2, u'b'), (3, u'c')]) + # XXX: The following 4 commented out are CPython 2.7 bugs + #assert set([(1, u'a'), (2, u'b'), (3, u'c')]) == d.viewitems() + assert d.viewitems() == frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) + #assert frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) == d.viewitems() + assert not d.viewitems() != set([(1, u'a'), (2, u'b'), (3, u'c')]) + #assert not set([(1, u'a'), (2, u'b'), (3, u'c')]) != d.viewitems() + assert not d.viewitems() != frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) + #assert not frozenset(set([(1, u'a'), (2, u'b'), (3, u'c')])) != d.viewitems() + + def test_dictviewset_unhashable_values(self): + class C: + def __eq__(self, other): + return True + d = {1: C()} + assert d.viewitems() <= d.viewitems() + + def test_compare_keys_and_items(self): + d1 = {1: 2} + d2 = {(1, 2): 'foo'} + assert d1.viewitems() == d2.viewkeys() + + def test_keys_items_contained(self): + def helper(fn): + empty = fn(dict()) + empty2 = fn(dict()) + smaller = fn({1:1, 2:2}) + larger = fn({1:1, 2:2, 3:3}) + larger2 = fn({1:1, 2:2, 3:3}) + larger3 = fn({4:1, 2:2, 3:3}) + + assert smaller < larger + assert smaller <= larger + assert larger > smaller + assert larger >= smaller + + assert not smaller >= larger + assert not smaller > larger + assert not larger <= smaller + assert not larger < smaller + + assert not smaller < larger3 + assert not smaller <= larger3 + assert not larger3 > smaller + assert not larger3 >= smaller + + # Inequality strictness + assert larger2 >= larger + assert larger2 <= larger + assert not larger2 > larger + assert not larger2 < larger + + assert larger == larger2 + assert smaller != larger + + # There is an optimization on the zero-element case. + assert empty == empty2 + assert not empty != empty2 + assert not empty == smaller + assert empty != smaller + + # With the same size, an elementwise compare happens + assert larger != larger3 + assert not larger == larger3 + + helper(lambda x: x.viewkeys()) + helper(lambda x: x.viewitems()) class AppTestStrategies(object): def setup_class(cls): diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -1,9 +1,10 @@ """ Utilities to get environ variables and platform-specific memory-related values. """ -import os, sys +import os, sys, platform from rpython.rlib.rarithmetic import r_uint from rpython.rlib.debug import debug_print, debug_start, debug_stop +from rpython.rlib.rstring import assert_str0 from rpython.rtyper.lltypesystem import lltype, rffi from rpython.rtyper.lltypesystem.lloperation import llop @@ -130,7 +131,22 @@ # ---------- Linux2 ---------- -def get_L2cache_linux2(filename="/proc/cpuinfo"): +def get_L2cache_linux2(): + arch = platform.machine() + if arch.endswith('86') or arch == 'x86_64': + return get_L2cache_linux2_cpuinfo() + if arch in ('alpha', 'ppc', 'ppc64'): + return get_L2cache_linux2_cpuinfo(label='L2 cache') + if arch == 'ia64': + return get_L2cache_linux2_ia64() + if arch in ('parisc', 'parisc64'): + return get_L2cache_linux2_cpuinfo(label='D-cache') + if arch in ('sparc', 'sparc64'): + return get_L2cache_linux2_sparc() + return -1 + + +def get_L2cache_linux2_cpuinfo(filename="/proc/cpuinfo", label='cache size'): debug_start("gc-hardware") L2cache = sys.maxint try: @@ -149,12 +165,8 @@ else: data = ''.join(data) linepos = 0 - # Currently on ARM-linux we won't find any information about caches in - # cpuinfo - if _detect_arm_cpu(data): - return -1 while True: - start = _findend(data, '\ncache size', linepos) + start = _findend(data, '\n' + label, linepos) if start < 0: break # done linepos = _findend(data, '\n', start) @@ -194,6 +206,104 @@ "Warning: cannot find your CPU L2 cache size in /proc/cpuinfo") return -1 +def get_L2cache_linux2_sparc(): + debug_start("gc-hardware") + cpu = 0 + L2cache = sys.maxint + while True: + try: + fd = os.open('/sys/devices/system/cpu/cpu' + assert_str0(str(cpu)) + + '/l2_cache_size', os.O_RDONLY, 0644) + try: + number = int(os.read(fd, 4096)) + finally: + os.close(fd) + except OSError: + break + if number < L2cache: + L2cache = number + cpu += 1 + + debug_print("L2cache =", L2cache) + debug_stop("gc-hardware") + if L2cache < sys.maxint: + return L2cache + else: + # Print a top-level warning even in non-debug builds + llop.debug_print(lltype.Void, + "Warning: cannot find your CPU L2 cache size in " + "/sys/devices/system/cpu/cpuX/l2_cache_size") + return -1 + +def get_L2cache_linux2_ia64(): + debug_start("gc-hardware") + cpu = 0 + L2cache = sys.maxint + L3cache = sys.maxint + while True: + cpudir = '/sys/devices/system/cpu/cpu' + assert_str0(str(cpu)) + index = 0 + while True: + cachedir = cpudir + '/cache/index' + assert_str0(str(index)) + try: + fd = os.open(cachedir + '/level', os.O_RDONLY, 0644) + try: + level = int(os.read(fd, 4096)[:-1]) + finally: + os.close(fd) + except OSError: + break + if level not in (2, 3): + index += 1 + continue + try: + fd = os.open(cachedir + '/size', os.O_RDONLY, 0644) + try: + data = os.read(fd, 4096) + finally: + os.close(fd) + except OSError: + break + + end = 0 + while '0' <= data[end] <= '9': + end += 1 + if end == 0: + index += 1 + continue + if data[end] not in ('K', 'k'): # assume kilobytes for now + index += 1 + continue + + number = int(data[:end]) + number *= 1024 + + if level == 2: + if number < L2cache: + L2cache = number + if level == 3: + if number < L3cache: + L3cache = number + + index += 1 + + if index == 0: + break + cpu += 1 + + mangled = L2cache + L3cache + debug_print("L2cache =", mangled) + debug_stop("gc-hardware") + if mangled > 0: + return mangled + else: + # Print a top-level warning even in non-debug builds + llop.debug_print(lltype.Void, + "Warning: cannot find your CPU L2 & L3 cache size in " + "/sys/devices/system/cpu/cpuX/cache") + return -1 + + def _findend(data, pattern, pos): pos = data.find(pattern, pos) if pos < 0: @@ -205,11 +315,6 @@ pos += 1 return pos -def _detect_arm_cpu(data): - # check for the presence of a 'Processor' entry - p = _findend(data, 'Processor', 0) - return p >= 0 and _findend(data, 'ARMv', p) > 0 - # ---------- Darwin ---------- sysctlbyname = rffi.llexternal('sysctlbyname', diff --git a/rpython/memory/gc/test/test_env.py b/rpython/memory/gc/test/test_env.py --- a/rpython/memory/gc/test/test_env.py +++ b/rpython/memory/gc/test/test_env.py @@ -159,25 +159,5 @@ fpu : yes etc. """) - result = env.get_L2cache_linux2(str(filepath)) + result = env.get_L2cache_linux2_cpuinfo(str(filepath)) assert result == 3072 * 1024 - -def test_estimate_best_nursery_size_linux2_arm(): - filepath = udir.join('estimate_best_nursery_size_linux2') - filepath.write("""\ -Processor : ARMv6-compatible processor rev 7 (v6l) -# this is not actually from cpuinfo, but here for the test -cache size : 3072 KB -... -""") - result = env.get_L2cache_linux2(str(filepath)) - assert result == -1 - -def test__detect_arm(): - assert env._detect_arm_cpu("Processor : ARMv6-compatible processor rev 7 (v6l)") - assert not env._detect_arm_cpu("""\ -processor : 0 -vendor_id : GenuineIntel -cpu family : 6 -model : 37 -""") diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -447,11 +447,11 @@ @jit.elidable def repr(self): - return _format(self, BASE10, '', 'L') + return _format_decimal(self, addL=True) @jit.elidable def str(self): - return _format(self, BASE10) + return _format_decimal(self) @jit.elidable def eq(self, other): @@ -2101,6 +2101,101 @@ return ''.join(s[p:]) +DECIMAL_SHIFT = 0 # computed as max(E such that 10**E fits in a digit) +while 10 ** (DECIMAL_SHIFT + 1) <= 2 ** SHIFT: + DECIMAL_SHIFT += 1 +DECIMAL_BASE = 10 ** DECIMAL_SHIFT + +# an RPython trick: this creates a nested sequence of calls that are +# all inlined into each other, making an unrolled loop. Moreover the +# calls are done in the "wrong" order to be written as a regular loop: +# the first digit that is append-ed to the builder is the most +# significant one (corresponding to the innermost call). +_succ = specialize.memo()(lambda n: n + 1) + at specialize.arg(3) +def _add_decimal_digits(builder, value, ndigits, digit_index=1): + assert value >= 0 + if digit_index < ndigits: + assert digit_index < DECIMAL_SHIFT + _add_decimal_digits(builder, value // 10, ndigits, _succ(digit_index)) + builder.append(chr(ord('0') + value % 10)) + else: + assert value < 10 + builder.append(chr(ord('0') + value)) +_add_decimal_digits._always_inline_ = True + + +def _format_decimal(a, addL=False): + """ Optimized version of _format(a, BASE10, '', 'L' if addL else ''). """ + if a.sign == 0: + if addL: + return "0L" + else: + return "0" + + size_a = a.numdigits() + negative = a.sign < 0 + + # quick and dirty upper bound for the number of digits + # required to express a in base DECIMAL_BASE: + # + # #digits = 1 + floor(log2(a) / log2(DECIMAL_BASE)) + # + # But log2(a) < size_a * PyLong_SHIFT, and + # log2(DECIMAL_BASE) = log2(10) * DECIMAL_SHIFT + # > 3 * DECIMAL_SHIFT + + size = 1 + size_a * SHIFT // (3 * DECIMAL_SHIFT) + pout = [NULLDIGIT] * size + + # convert array of base _PyLong_BASE digits in pin to an array of + # base _PyLong_DECIMAL_BASE digits in pout, following Knuth (TAOCP, + # Volume 2 (3rd edn), section 4.4, Method 1b). + size = 0 + for i in range(size_a-1, -1, -1): + hi = a.digit(i) + for j in range(size): + z = (_widen_digit(pout[j]) << SHIFT) | hi + hi = _store_digit(z // DECIMAL_BASE) + pout[j] = _store_digit(z - _widen_digit(hi) * DECIMAL_BASE) + assert hi >= 0 + while hi: + pout[size] = hi % DECIMAL_BASE + hi //= DECIMAL_BASE + size += 1 + sizem1 = size - 1 + assert sizem1 >= 0 + + # calculate exact length of output string, and allocate + decimal_digits_in_last_part = 1 + rem = pout[sizem1] + tenpow = 10 + while rem >= tenpow: + tenpow *= 10 + decimal_digits_in_last_part += 1 + strlen = (addL + negative + + decimal_digits_in_last_part + (sizem1) * DECIMAL_SHIFT) + + builder = StringBuilder(strlen) + + # start with the negative sign, if needed + if negative: + builder.append('-') + + # pout[size-1] produces 'decimal_digits_in_last_part' digits. + # Then the remaining pout[size-2] through pout[0] contribute exactly + # DECIMAL_SHIFT digits each. + decimal_digits = decimal_digits_in_last_part + for i in range(sizem1, -1, -1): + _add_decimal_digits(builder, pout[i], decimal_digits) + decimal_digits = DECIMAL_SHIFT + + # done + if addL: + builder.append('L') + return builder.build() + + def _bitwise(a, op, b): # '&', '|', '^' """ Bitwise and/or/xor operations """ diff --git a/rpython/translator/c/src/stacklet/tests.c b/rpython/translator/c/src/stacklet/tests.c --- a/rpython/translator/c/src/stacklet/tests.c +++ b/rpython/translator/c/src/stacklet/tests.c @@ -31,7 +31,7 @@ assert(status == 0); status = 1; assert(h != EMPTY_STACKLET_HANDLE); - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); assert(status == 2); assert(h != EMPTY_STACKLET_HANDLE); status = 3; @@ -45,7 +45,7 @@ assert(h != EMPTY_STACKLET_HANDLE); assert(status == 1); status = 2; - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); assert(status == 3); assert(h == EMPTY_STACKLET_HANDLE); } @@ -148,7 +148,7 @@ //printf("switch to %d\n", n); h = handles[n]; handles[n] = NULL; - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); } //printf("back in self = %d, coming from %d\n", self, comefrom); assert(nextstep == status); diff --git a/rpython/translator/platform/freebsd.py b/rpython/translator/platform/freebsd.py --- a/rpython/translator/platform/freebsd.py +++ b/rpython/translator/platform/freebsd.py @@ -12,3 +12,11 @@ class Freebsd_64(Freebsd): shared_only = ('-fPIC',) + +class GNUkFreebsd(Freebsd): + DEFAULT_CC = 'cc' + extra_libs = ('-lrt',) + +class GNUkFreebsd_64(Freebsd_64): + DEFAULT_CC = 'cc' + extra_libs = ('-lrt',) From noreply at buildbot.pypy.org Sun May 19 14:14:38 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 14:14:38 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Move load_result() into callbuilder too. Message-ID: <20130519121438.555561C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64324:7dbd98504eff Date: 2013-05-19 14:09 +0200 http://bitbucket.org/pypy/pypy/changeset/7dbd98504eff/ Log: Move load_result() into callbuilder too. diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1003,8 +1003,8 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def simple_call(self, fnaddr, arglocs): - cb = callbuilder.CallBuilder(self, imm(fnaddr), arglocs) + def simple_call(self, fnloc, arglocs): + cb = callbuilder.CallBuilder(self, fnloc, arglocs) cb.emit() def _reload_frame_if_necessary(self, mc, align_stack=False): @@ -1814,65 +1814,25 @@ def genop_call(self, op, arglocs, resloc): return self._genop_call(op, arglocs, resloc) - def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False): + def _genop_call(self, op, arglocs, resloc): from rpython.jit.backend.llsupport.descr import CallDescr - sizeloc = arglocs[0] - assert isinstance(sizeloc, ImmedLoc) - size = sizeloc.value - signloc = arglocs[1] - - cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:]) + cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:], resloc) descr = op.getdescr() assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() cb.argtypes = descr.get_arg_types() - cb.callconv = descr.get_call_conv() - - if is_call_release_gil: - if self._is_asmgcc(): - from rpython.memory.gctransform import asmgcroot - stack_max -= asmgcroot.JIT_USE_WORDS - XXXXXX + cb.restype = descr.get_result_type() + sizeloc = arglocs[0] + assert isinstance(sizeloc, ImmedLoc) + cb.ressize = sizeloc.value + signloc = arglocs[1] + assert isinstance(signloc, ImmedLoc) + cb.ressign = signloc.value cb.emit() - if IS_X86_32 and isinstance(resloc, FrameLoc) and resloc.type == FLOAT: - # a float or a long long return - if descr.get_result_type() == 'L': - self.mc.MOV_br(resloc.value, eax.value) # long long - self.mc.MOV_br(resloc.value + 4, edx.value) - # XXX should ideally not move the result on the stack, - # but it's a mess to load eax/edx into a xmm register - # and this way is simpler also because the result loc - # can just be always a stack location - else: - self.mc.FSTPL_b(resloc.value) # float return - elif descr.get_result_type() == 'S': - # singlefloat return - assert resloc is eax - if IS_X86_32: - # must convert ST(0) to a 32-bit singlefloat and load it into EAX - # mess mess mess - self.mc.SUB_ri(esp.value, 4) - self.mc.FSTPS_s(0) - self.mc.POP_r(eax.value) - elif IS_X86_64: - # must copy from the lower 32 bits of XMM0 into eax - self.mc.MOVD_rx(eax.value, xmm0.value) - elif size == WORD: - assert resloc is eax or resloc is xmm0 # a full word - elif size == 0: - pass # void return - else: - # use the code in load_from_mem to do the zero- or sign-extension - assert resloc is eax - if size == 1: - srcloc = eax.lowest8bits() - else: - srcloc = eax - self.load_from_mem(eax, srcloc, sizeloc, signloc) - def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') @@ -1996,11 +1956,11 @@ self.call_assembler(op, guard_op, argloc, vloc, result_loc, eax) self._emit_guard_not_forced(guard_token) - def _call_assembler_emit_call(self, addr, argloc, tmploc): - self._emit_call(addr, [argloc], 0, tmp=tmploc) + def _call_assembler_emit_call(self, addr, argloc, _): + self.simple_call(addr, [argloc]) def _call_assembler_emit_helper_call(self, addr, arglocs, _): - self._emit_call(addr, arglocs, 0, tmp=self._second_tmp_reg) + self.simple_call(addr, arglocs) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -6,7 +6,7 @@ from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, - RegLoc, RawEspLoc) + RegLoc, RawEspLoc, FrameLoc) from rpython.jit.backend.x86.jump import remap_frame_layout @@ -28,6 +28,9 @@ # this can be set to guide more complex calls: gives the detailed # type of the arguments argtypes = None + restype = INT + ressize = WORD + ressign = False # this is the calling convention (can be FFI_STDCALL on Windows) callconv = FFI_DEFAULT_ABI @@ -36,11 +39,12 @@ is_call_release_gil = False - def __init__(self, assembler, fnloc, arglocs): + def __init__(self, assembler, fnloc, arglocs, resloc=eax): self.asm = assembler self.mc = assembler.mc self.fnloc = fnloc self.arglocs = arglocs + self.resloc = resloc self.current_esp = 0 def emit(self): @@ -49,6 +53,7 @@ self.push_gcmap() self.emit_raw_call() self.pop_gcmap() + self.load_result() self.restore_esp() def emit_raw_call(self): @@ -61,6 +66,22 @@ self.mc.SUB_ri(esp.value, self.current_esp) self.current_esp = 0 + def load_result(self): + """Overridden in CallBuilder32 and CallBuilder64""" + if self.ressize == 0: + return # void result + # use the code in load_from_mem to do the zero- or sign-extension + if self.restype == FLOAT: + srcloc = xmm0 + elif self.ressize == 1: + srcloc = eax.lowest8bits() + else: + srcloc = eax + if self.ressize >= WORD and self.resloc is srcloc: + return # no need for any move + self.asm.load_from_mem(self.resloc, srcloc, + imm(self.ressize), imm(self.ressign)) + def push_gcmap(self): # we push *now* the gcmap, describing the status of GC registers # after the rearrangements done just above, ignoring the return @@ -127,6 +148,27 @@ assert callconv == FFI_STDCALL return self.total_stack_used_by_arguments + def load_result(self): + resloc = self.resloc + if isinstance(resloc, FrameLoc) and resloc.type == FLOAT: + # a float or a long long return + if self.restype == 'L': + self.mc.MOV_br(resloc.value, eax.value) # long long + self.mc.MOV_br(resloc.value + 4, edx.value) + # XXX should ideally not move the result on the stack, + # but it's a mess to load eax/edx into a xmm register + # and this way is simpler also because the result loc + # can just be always a stack location + else: + self.mc.FSTPL_b(resloc.value) # float return + elif self.restype == 'S': + # singlefloat return: must convert ST(0) to a 32-bit singlefloat + # and load it into self.resloc. mess mess mess + self.mc.SUB_ri(esp.value, 4) + self.mc.FSTPS_s(0) + self.mc.POP(self.resloc) + else: + AbstractCallBuilder.load_result(self) class CallBuilder64(AbstractCallBuilder): @@ -222,6 +264,16 @@ def _fix_stdcall(self, callconv): assert 0 # should not occur on 64-bit + def load_result(self): + if self.restype == 'S': + # singlefloat return: use MOVD to load the target register + # with the lower 32 bits of XMM0 + resloc = self.resloc + assert isinstance(resloc, RegLoc) + self.mc.MOVD_rx(resloc.value, xmm0.value) + else: + AbstractCallBuilder.load_result(self) + if IS_X86_32: CallBuilder = CallBuilder32 From noreply at buildbot.pypy.org Sun May 19 16:06:54 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 16:06:54 +0200 (CEST) Subject: [pypy-commit] pypy default: Skip test_get_config_h_filename() when cpyext is not available. Message-ID: <20130519140654.B6A341C13FB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64325:0a007a299a9b Date: 2013-05-19 15:38 +0200 http://bitbucket.org/pypy/pypy/changeset/0a007a299a9b/ Log: Skip test_get_config_h_filename() when cpyext is not available. diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -7,7 +7,8 @@ import subprocess from copy import copy, deepcopy -from test.test_support import run_unittest, TESTFN, unlink, get_attribute +from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, + check_impl_detail) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -235,6 +236,11 @@ # XXX more platforms to tests here def test_get_config_h_filename(self): + if check_impl_detail(pypy=True): + try: + import cpyext + except ImportError: + self.skipTest("This test depends on cpyext.") config_h = sysconfig.get_config_h_filename() self.assertTrue(os.path.isfile(config_h), config_h) From noreply at buildbot.pypy.org Sun May 19 16:06:55 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 16:06:55 +0200 (CEST) Subject: [pypy-commit] pypy default: Make test_libload_None() independent from cpyext. Message-ID: <20130519140655.E1C341C14F7@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64326:4f71319354fa Date: 2013-05-19 16:00 +0200 http://bitbucket.org/pypy/pypy/changeset/4f71319354fa/ Log: Make test_libload_None() independent from cpyext. diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -232,9 +232,9 @@ import _rawffi # this should return *all* loaded libs, dlopen(NULL) dll = _rawffi.CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.ptr('Py_IsInitialized', [], 'l')() - assert res[0] == 1 + func = dll.ptr('rand', [], 'i') + res = func() + assert res[0] != 0 def test_libc_load(self): import _rawffi From noreply at buildbot.pypy.org Sun May 19 16:26:05 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 16:26:05 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix test_pickle(). Message-ID: <20130519142605.B808B1C14F7@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64327:91ab382c7062 Date: 2013-05-19 16:23 +0200 http://bitbucket.org/pypy/pypy/changeset/91ab382c7062/ Log: Fix test_pickle(). diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,10 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + if self.ptr_size == 8: + assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + else: + assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype def test_pickle_record(self): From noreply at buildbot.pypy.org Sun May 19 17:04:42 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 17:04:42 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: in-progress Message-ID: <20130519150442.23ED51C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64328:fb8653a29037 Date: 2013-05-19 17:04 +0200 http://bitbucket.org/pypy/pypy/changeset/fb8653a29037/ Log: in-progress 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 @@ -108,8 +108,7 @@ self.malloc_slowpath_unicode = None self._build_stack_check_slowpath() - if gc_ll_descr.gcrootmap: - self._build_release_gil(gc_ll_descr.gcrootmap) + self._build_release_gil(gc_ll_descr.gcrootmap) if not self._debug: # if self._debug is already set it means that someone called # set_debug by hand before initializing the assembler. Leave it @@ -348,12 +347,19 @@ if after: after() + @staticmethod + def _no_op(): + pass + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], lltype.Void)) def _build_release_gil(self, gcrootmap): - if gcrootmap.is_shadow_stack: + if gcrootmap is None: + releasegil_func = llhelper(self._NOARG_FUNC, self._no_op) + reacqgil_func = llhelper(self._NOARG_FUNC, self._no_op) + elif gcrootmap.is_shadow_stack: releasegil_func = llhelper(self._NOARG_FUNC, self._release_gil_shadowstack) reacqgil_func = llhelper(self._NOARG_FUNC, diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py --- a/rpython/jit/backend/x86/arch.py +++ b/rpython/jit/backend/x86/arch.py @@ -40,4 +40,4 @@ PASS_ON_MY_FRAME = 12 JITFRAME_FIXED_SIZE = 28 # 13 GPR + 15 XMM -assert PASS_ON_MY_FRAME >= 11 # asmgcc needs at least JIT_USE_WORDS + 2 +assert PASS_ON_MY_FRAME >= 12 # asmgcc needs at least JIT_USE_WORDS + 3 diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1265,7 +1265,7 @@ # ---------- def genop_call_malloc_gc(self, op, arglocs, result_loc): - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self.propagate_memoryerror_if_eax_is_null() def propagate_memoryerror_if_eax_is_null(self): @@ -1812,9 +1812,9 @@ self.pending_guard_tokens.append(guard_token) def genop_call(self, op, arglocs, resloc): - return self._genop_call(op, arglocs, resloc) + self._genop_call(op, arglocs, resloc) - def _genop_call(self, op, arglocs, resloc): + def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False): from rpython.jit.backend.llsupport.descr import CallDescr cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:], resloc) @@ -1831,7 +1831,10 @@ assert isinstance(signloc, ImmedLoc) cb.ressign = signloc.value - cb.emit() + if is_call_release_gil: + cb.emit_call_release_gil() + else: + cb.emit() def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() @@ -1847,64 +1850,15 @@ def genop_guard_call_may_force(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self._emit_guard_not_forced(guard_token) def genop_guard_call_release_gil(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs) - # do the call self._genop_call(op, arglocs, result_loc, is_call_release_gil=True) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, result_loc) - self.pop_gcmap(self.mc) # remove the gcmap saved above - # finally, the guard_not_forced self._emit_guard_not_forced(guard_token) - def call_release_gil(self, gcrootmap, save_registers): - if gcrootmap.is_shadow_stack: - args = [] - else: - from rpython.memory.gctransform import asmgcroot - # build a 'css' structure on the stack: 2 words for the linkage, - # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a - # total size of JIT_USE_WORDS. This structure is found at - # [ESP+css]. - css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) - assert css >= 2 - # Save ebp - index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) - self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP - # Save the "return address": we pretend that it's css - if IS_X86_32: - reg = eax - elif IS_X86_64: - reg = edi - self.mc.LEA_rs(reg.value, css) # LEA reg, [css] - frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) - self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg - # Set up jf_extra_stack_depth to pretend that the return address - # was at css, and so our stack frame is supposedly shorter by - # (css+WORD) bytes - self.set_extra_stack_depth(self.mc, -css-WORD) - # Call the closestack() function (also releasing the GIL) - args = [reg] - # - self._emit_call(imm(self.releasegil_addr), args, can_collect=False) - def call_reacquire_gil(self, gcrootmap, save_loc): # save the previous result (eax/xmm0) into the stack temporarily. # XXX like with call_release_gil(), we assume that we don't need diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -6,7 +6,7 @@ from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, - RegLoc, RawEspLoc, FrameLoc) + RegLoc, RawEspLoc, imm) from rpython.jit.backend.x86.jump import remap_frame_layout @@ -38,6 +38,9 @@ # is it for the main CALL of a call_release_gil? is_call_release_gil = False + # set by save_result_value() + tmpresloc = None + def __init__(self, assembler, fnloc, arglocs, resloc=eax): self.asm = assembler @@ -52,39 +55,67 @@ self.prepare_arguments() self.push_gcmap() self.emit_raw_call() + self.restore_esp() self.pop_gcmap() self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() self.restore_esp() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + if self.asm._is_asmgcc(): + from rpython.memory.gctransform import asmgcroot + self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + assert self.stack_max >= 3 def emit_raw_call(self): self.mc.CALL(self.fnloc) if self.callconv != FFI_DEFAULT_ABI: self.current_esp += self._fix_stdcall(self.callconv) - def restore_esp(self): - if self.current_esp != 0: - self.mc.SUB_ri(esp.value, self.current_esp) - self.current_esp = 0 + def subtract_esp_aligned(self, count): + align = align_stack_words(count) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) + + def restore_esp(self, target_esp=0): + if self.current_esp != target_esp: + self.mc.SUB_ri(esp.value, self.current_esp - target_esp) + self.current_esp = target_esp def load_result(self): """Overridden in CallBuilder32 and CallBuilder64""" if self.ressize == 0: return # void result # use the code in load_from_mem to do the zero- or sign-extension - if self.restype == FLOAT: - srcloc = xmm0 - elif self.ressize == 1: - srcloc = eax.lowest8bits() - else: - srcloc = eax + srcloc = self.tmpresloc + if srcloc is None: + if self.restype == FLOAT: + srcloc = xmm0 + elif self.ressize == 1: + srcloc = eax.lowest8bits() + else: + srcloc = eax if self.ressize >= WORD and self.resloc is srcloc: - return # no need for any move + return # no need for any MOV self.asm.load_from_mem(self.resloc, srcloc, imm(self.ressize), imm(self.ressign)) def push_gcmap(self): # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return + # after the rearrangements done just before, ignoring the return # value eax, if necessary assert not self.is_call_release_gil self.change_extra_stack_depth = (self.current_esp != 0) @@ -94,13 +125,112 @@ gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) self.asm.push_gcmap(self.mc, gcmap, store=True) + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + def pop_gcmap(self): - assert not self.is_call_release_gil self.asm._reload_frame_if_necessary(self.mc) if self.change_extra_stack_depth: self.asm.set_extra_stack_depth(self.mc, 0) self.asm.pop_gcmap(self.mc) + def call_releasegil_addr_and_move_real_arguments(self): + if IS_X86_32 and self.asm._is_asmgcc(): + needs_extra_esp = 1 # only for asmgcc on x86_32 + else: + needs_extra_esp = 0 + initial_esp = self.current_esp + self.save_register_arguments(needs_extra_esp) + # + if not self.asm._is_asmgcc(): + # the helper takes no argument + self.change_extra_stack_depth = False + else: + from rpython.memory.gctransform import asmgcroot + # build a 'css' structure on the stack: 2 words for the linkage, + # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a + # total size of JIT_USE_WORDS. This structure is found at + # [ESP+css]. + css = WORD * (self.current_esp + + PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) + assert css >= 2 + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Save the "return address": we pretend that it's css + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) # LEA reg, [css] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg + # Set up jf_extra_stack_depth to pretend that the return address + # was at css, and so our stack frame is supposedly shorter by + # (PASS_ON_MY_FRAME-JIT_USE_WORDS+1) words + delta = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + 1 + self.change_extra_stack_depth = True + self.set_extra_stack_depth(self.mc, -delta * WORD) + # Call the closestack() function (also releasing the GIL) + # with 'reg' as argument + if IS_X86_32: + self.mc.MOV_sr(0, reg.value) + #else: + # on x86_64, reg is edi so that it is already correct + # + self.mc.CALL(imm(self.asm.releasegil_addr)) + # + self.restore_register_arguments() + self.restore_esp(initial_esp) + + def save_register_arguments(self, needs_extra_esp): + """Overridden in CallBuilder64""" + if needs_extra_esp: + self.subtract_esp_aligned(needs_extra_esp) + + def restore_register_arguments(self): + """Overridden in CallBuilder64""" + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got (in eax/eax+edx/st(0)/xmm0) + self.save_result_value() + # call the reopenstack() function (also reacquiring the GIL) + if not self.asm._is_asmgcc(): + css = 0 # the helper takes no argument + else: + from rpython.memory.gctransform import asmgcroot + css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) + if IS_X86_32: + self.mc.MOV_sr(0, reg.value) + # + self.mc.CALL(imm(self.asm.reacqgil_addr)) + # + # Now that we required the GIL, we can reload a possibly modified ebp + if self.asm._is_asmgcc(): + # special-case: reload ebp from the css + from rpython.memory.gctransform import asmgcroot + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_rs(ebp.value, index_of_ebp) # MOV EBP, [css.ebp] + #else: + # for shadowstack, done for us by _reload_frame_if_necessary() + + def save_result_value(self): + """Overridden in CallBuilder32 and CallBuilder64""" + raise NotImplementedError + class CallBuilder32(AbstractCallBuilder): @@ -112,9 +242,7 @@ loc = arglocs[i] stack_depth += loc.get_width() // WORD if stack_depth > self.stack_max: - align = align_stack_words(stack_depth - self.stack_max) - self.current_esp -= align * WORD - self.mc.SUB_ri(esp.value, align * WORD) + self.subtract_esp_aligned(stack_depth - self.stack_max) # p = 0 for i in range(n): @@ -149,33 +277,109 @@ return self.total_stack_used_by_arguments def load_result(self): + if self.ressize == 0: + return # void result resloc = self.resloc - if isinstance(resloc, FrameLoc) and resloc.type == FLOAT: + if resloc.is_float(): # a float or a long long return - if self.restype == 'L': - self.mc.MOV_br(resloc.value, eax.value) # long long - self.mc.MOV_br(resloc.value + 4, edx.value) - # XXX should ideally not move the result on the stack, - # but it's a mess to load eax/edx into a xmm register - # and this way is simpler also because the result loc - # can just be always a stack location + if self.tmpresloc is None: + if self.restype == 'L': # long long + # move eax/edx -> xmm0 + self.mc.MOVD_xr(resloc.value^1, edx.value) + self.mc.MOVD_xr(resloc.value, eax.value) + self.mc.PUNPCKLDQ_xx(resloc.value, resloc.value^1) + else: + # float: we have to go via the stack + self.mc.FSTPL_s(0) + self.mc.MOVSD_xs(resloc.value, 0) else: - self.mc.FSTPL_b(resloc.value) # float return + self.mc.MOVSD(resloc, self.tmpresloc) + # elif self.restype == 'S': # singlefloat return: must convert ST(0) to a 32-bit singlefloat # and load it into self.resloc. mess mess mess - self.mc.SUB_ri(esp.value, 4) - self.mc.FSTPS_s(0) - self.mc.POP(self.resloc) + if self.tmpresloc is None: + self.mc.FSTPS_s(0) + self.mc.MOV_rs(resloc.value, 0) + else: + self.mc.MOV(resloc, self.tmpresloc) else: AbstractCallBuilder.load_result(self) + def save_result_value(self): + # Temporarily save the result value into [ESP+4]. We use "+4" + # in order to leave the word at [ESP+0] free, in case it's needed + if self.ressize == 0: # void return + return + if self.resloc.is_float(): + # a float or a long long return + self.tmpresloc = RawEspLoc(4, FLOAT) + if self.restype == 'L': + self.mc.MOV_sr(4, eax.value) # long long + self.mc.MOV_sr(8, edx.value) + else: + self.mc.FSTPL_s(4) # float return + else: + self.tmpresloc = RawEspLoc(4, INT) + if self.restype == 'S': + self.mc.FSTPS_s(4) + else: + assert self.restype == INT + assert self.ressize <= WORD + self.mc.MOV_sr(4, eax.value) + class CallBuilder64(AbstractCallBuilder): - # In reverse order for use with pop() - unused_gpr = [r9, r8, ecx, edx, esi, edi] - unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0] + ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] + ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + + next_arg_gpr = 0 + next_arg_xmm = 0 + + def _unused_gpr(self): + i = self.next_arg_gpr + self.next_arg_gpr = i + 1 + try: + return self.ARGUMENTS_GPR[i] + except IndexError: + return None + + def _unused_xmm(self): + i = self.next_arg_xmm + self.next_arg_xmm = i + 1 + try: + return self.ARGUMENTS_XMM[i] + except IndexError: + return None + + def _permute_to_prefer_unused_registers(self, lst): + N = len(lst) + for i in range(N - 1): + reg = lst[i] + if reg in self.already_used: + for j in range(i, N - 1): # move reg to the end + lst[j] = lst[j + 1] + lst[N - 1] = reg + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + # We have to copy the arguments around a bit more in this mode, + # but on the other hand we don't need prepare_arguments() moving + # them in precisely the final registers. Here we look around for + # unused registers that may be more likely usable. + from rpython.jit.backend.x86.regalloc import X86_64_RegisterManager + self.already_used = {} + for loc in self.arglocs: + self.already_used[loc] = None + # + lst = X86_64_RegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] + # + lst = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + self._permute_to_prefer_unused_registers(lst) + self.ARGUMENTS_XMM = lst def prepare_arguments(self): src_locs = [] @@ -186,35 +390,33 @@ arglocs = self.arglocs argtypes = self.argtypes - unused_gpr = self.unused_gpr[:] - unused_xmm = self.unused_xmm[:] on_stack = 0 for i in range(len(arglocs)): loc = arglocs[i] if loc.is_float(): + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, FLOAT) + on_stack += 1 xmm_src_locs.append(loc) - if len(unused_xmm) > 0: - xmm_dst_locs.append(unused_xmm.pop()) - else: - xmm_dst_locs.append(RawEspLoc(on_stack * WORD, FLOAT)) - on_stack += 1 + xmm_dst_locs.append(tgt) elif argtypes is not None and argtypes[i] == 'S': # Singlefloat argument if singlefloats is None: singlefloats = [] - if len(unused_xmm) > 0: - singlefloats.append((loc, unused_xmm.pop())) - else: - singlefloats.append((loc, RawEspLoc(on_stack * WORD, INT))) + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) on_stack += 1 + singlefloats.append((loc, tgt)) else: + tgt = self._unused_gpr() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 src_locs.append(loc) - if len(unused_gpr) > 0: - dst_locs.append(unused_gpr.pop()) - else: - dst_locs.append(RawEspLoc(on_stack * WORD, INT)) - on_stack += 1 + dst_locs.append(tgt) if not we_are_translated(): # assert that we got the right stack depth floats = 0 @@ -223,15 +425,12 @@ if arg.is_float() or argtypes and argtypes[i] == 'S': floats += 1 all_args = len(arglocs) - stack_depth = (max(all_args - floats - 6, 0) + - max(floats - 8, 0)) + stack_depth = (max(all_args - floats - len(self.ARGUMENTS_GPR), 0) + + max(floats - len(self.ARGUMENTS_XMM), 0)) assert stack_depth == on_stack - align = 0 if on_stack > self.stack_max: - align = align_stack_words(on_stack - self.stack_max) - self.current_esp -= align * WORD - self.mc.SUB_ri(esp.value, align * WORD) + self.subtract_esp_aligned(on_stack - self.stack_max) # Handle register arguments: first remap the xmm arguments remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, @@ -265,15 +464,38 @@ assert 0 # should not occur on 64-bit def load_result(self): - if self.restype == 'S': + if self.restype == 'S' and self.tmpresloc is None: # singlefloat return: use MOVD to load the target register - # with the lower 32 bits of XMM0 - resloc = self.resloc - assert isinstance(resloc, RegLoc) - self.mc.MOVD_rx(resloc.value, xmm0.value) + # from the lower 32 bits of XMM0 + self.mc.MOVD(self.resloc, xmm0) else: AbstractCallBuilder.load_result(self) + def save_result_value(self): + # Temporarily save the result value into [ESP]. + if self.ressize == 0: # void return + return + # + if self.restype == 'S': + # singlefloat return: use MOVD to store the lower 32 bits + # of XMM0 into [ESP] + self.mc.MOVD_sx(0, xmm0.value) + type = INT + elif self.restype == FLOAT: + self.mc.MOVSD_sx(0, xmm0.value) + type = FLOAT + else: + assert self.restype == INT + self.mc.MOV_sr(0, eax.value) + type = INT + self.tmpresloc = RawEspLoc(0, type) + + def save_register_arguments(self, needs_extra_esp): + xxx + + def restore_register_arguments(self): + xxx + if IS_X86_32: CallBuilder = CallBuilder32 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -79,26 +79,14 @@ rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), adr)[1] = y return ConstFloatLoc(adr) - def after_call(self, v): - # the result is stored in st0, but we don't have this around, - # so genop_call will move it to some frame location immediately - # after the call - return self.frame_manager.loc(v) + def call_result_location(self, v): + return xmm0 class X86_64_XMMRegisterManager(X86XMMRegisterManager): # xmm15 reserved for scratch use all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14] save_around_call_regs = all_regs - def call_result_location(self, v): - return xmm0 - - def after_call(self, v): - # We use RegisterManager's implementation, since X86XMMRegisterManager - # places the result on the stack, which we don't need to do when the - # calling convention places the result in xmm0 - return RegisterManager.after_call(self, v) - class X86FrameManager(FrameManager): def __init__(self, base_ofs): FrameManager.__init__(self) diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -583,6 +583,7 @@ # x87 instructions FSTPL_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) # rffi.DOUBLE ('as' wants L??) + FSTPL_s = insn('\xDD', orbyte(3<<3), stack_sp(1)) # rffi.DOUBLE ('as' wants L??) FSTPS_s = insn('\xD9', orbyte(3<<3), stack_sp(1)) # lltype.SingleFloat # ------------------------------ Random mess ----------------------- From noreply at buildbot.pypy.org Sun May 19 17:43:56 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 17:43:56 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: A first version of the code specifically for call_release_gil on x86-64. Message-ID: <20130519154356.8AFCF1C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64329:5b914c5dd93e Date: 2013-05-19 17:43 +0200 http://bitbucket.org/pypy/pypy/changeset/5b914c5dd93e/ Log: A first version of the code specifically for call_release_gil on x86-64. diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -86,9 +86,10 @@ self.current_esp += self._fix_stdcall(self.callconv) def subtract_esp_aligned(self, count): - align = align_stack_words(count) - self.current_esp -= align * WORD - self.mc.SUB_ri(esp.value, align * WORD) + if count > 0: + align = align_stack_words(count) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) def restore_esp(self, target_esp=0): if self.current_esp != target_esp: @@ -143,12 +144,8 @@ self.asm.pop_gcmap(self.mc) def call_releasegil_addr_and_move_real_arguments(self): - if IS_X86_32 and self.asm._is_asmgcc(): - needs_extra_esp = 1 # only for asmgcc on x86_32 - else: - needs_extra_esp = 0 initial_esp = self.current_esp - self.save_register_arguments(needs_extra_esp) + self.save_register_arguments() # if not self.asm._is_asmgcc(): # the helper takes no argument @@ -182,6 +179,7 @@ # Call the closestack() function (also releasing the GIL) # with 'reg' as argument if IS_X86_32: + self.subtract_esp_aligned(1) self.mc.MOV_sr(0, reg.value) #else: # on x86_64, reg is edi so that it is already correct @@ -191,10 +189,8 @@ self.restore_register_arguments() self.restore_esp(initial_esp) - def save_register_arguments(self, needs_extra_esp): + def save_register_arguments(self): """Overridden in CallBuilder64""" - if needs_extra_esp: - self.subtract_esp_aligned(needs_extra_esp) def restore_register_arguments(self): """Overridden in CallBuilder64""" @@ -241,8 +237,7 @@ for i in range(n): loc = arglocs[i] stack_depth += loc.get_width() // WORD - if stack_depth > self.stack_max: - self.subtract_esp_aligned(stack_depth - self.stack_max) + self.subtract_esp_aligned(stack_depth - self.stack_max) # p = 0 for i in range(n): @@ -333,13 +328,17 @@ ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + DONT_MOVE_GPR = [] + _ALL_CALLEE_SAVE_GPR = [ebx, r12, r13, r14, r15] next_arg_gpr = 0 next_arg_xmm = 0 - def _unused_gpr(self): + def _unused_gpr(self, hint): i = self.next_arg_gpr self.next_arg_gpr = i + 1 + if hint in self.DONT_MOVE_GPR: + return hint try: return self.ARGUMENTS_GPR[i] except IndexError: @@ -354,13 +353,19 @@ return None def _permute_to_prefer_unused_registers(self, lst): + # permute 'lst' so that it starts with registers that are not + # in 'self.already_used', and ends with registers that are. N = len(lst) - for i in range(N - 1): + i = 0 + while i < N: reg = lst[i] if reg in self.already_used: - for j in range(i, N - 1): # move reg to the end - lst[j] = lst[j + 1] - lst[N - 1] = reg + # move this reg to the end, and decrement N + N -= 1 + assert N >= i + lst[N], lst[i] = lst[i], lst[N] + else: + i += 1 def select_call_release_gil_mode(self): AbstractCallBuilder.select_call_release_gil_mode(self) @@ -376,9 +381,11 @@ lst = X86_64_RegisterManager.save_around_call_regs[:] self._permute_to_prefer_unused_registers(lst) self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] + self.DONT_MOVE_GPR = self._ALL_CALLEE_SAVE_GPR # lst = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] self._permute_to_prefer_unused_registers(lst) + assert len(lst) == len(self.ARGUMENTS_XMM) self.ARGUMENTS_XMM = lst def prepare_arguments(self): @@ -411,7 +418,7 @@ on_stack += 1 singlefloats.append((loc, tgt)) else: - tgt = self._unused_gpr() + tgt = self._unused_gpr(hint=loc) if tgt is None: tgt = RawEspLoc(on_stack * WORD, INT) on_stack += 1 @@ -429,8 +436,7 @@ + max(floats - len(self.ARGUMENTS_XMM), 0)) assert stack_depth == on_stack - if on_stack > self.stack_max: - self.subtract_esp_aligned(on_stack - self.stack_max) + self.subtract_esp_aligned(on_stack - self.stack_max) # Handle register arguments: first remap the xmm arguments remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, @@ -490,11 +496,45 @@ type = INT self.tmpresloc = RawEspLoc(0, type) - def save_register_arguments(self, needs_extra_esp): - xxx + def save_register_arguments(self): + # Save the argument registers, which are given by self.ARGUMENTS_xxx. + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + n_saved_regs = n_gpr + n_xmm + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] in self._ALL_CALLEE_SAVE_GPR: + n_saved_regs -= 1 # don't need to save it + self.subtract_esp_aligned(n_saved_regs) + # + n = 0 + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_sr(n * WORD, self.ARGUMENTS_GPR[i].value) + n += 1 + for i in range(n_xmm): + self.mc.MOVSD_sx(n * WORD, self.ARGUMENTS_XMM[i].value) + n += 1 + assert n == n_saved_regs + self.n_saved_regs = n_saved_regs def restore_register_arguments(self): - xxx + # Restore the saved values into the *real* registers used for calls + # --- which are not self.ARGUMENTS_xxx! + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + # + n = 0 + for i in range(n_gpr): + tgtvalue = CallBuilder64.ARGUMENTS_GPR[i].value + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_rs(tgtvalue, n * WORD) + n += 1 + else: + self.mc.MOV_rr(tgtvalue, self.ARGUMENTS_GPR[i].value) + for i in range(n_xmm): + self.mc.MOVSD_xs(CallBuilder64.ARGUMENTS_XMM[i].value, n * WORD) + n += 1 + assert n == self.n_saved_regs if IS_X86_32: From noreply at buildbot.pypy.org Sun May 19 17:48:42 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 17:48:42 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: __mul__ and __rmul__ do the same. Message-ID: <20130519154842.A7E631C01CD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64330:f9da31e273e3 Date: 2013-05-19 17:12 +0200 http://bitbucket.org/pypy/pypy/changeset/f9da31e273e3/ Log: __mul__ and __rmul__ do the same. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -444,7 +444,7 @@ raise return self - def mul_list_times(self, space, w_times): + def descr_mul(self, space, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) except OperationError, e: @@ -453,12 +453,6 @@ raise return self.mul(times) - def descr_mul(self, space, w_times): - return self.mul_list_times(space, w_times) - - def descr_rmul(self, space, w_times): - return self.mul_list_times(self.space, w_times) - def descr_inplace_mul(self, space, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) @@ -1723,7 +1717,7 @@ __add__ = interp2app(W_ListObject.descr_add), __iadd__ = interp2app(W_ListObject.descr_inplace_add), __mul__ = interp2app(W_ListObject.descr_mul), - __rmul__ = interp2app(W_ListObject.descr_rmul), + __rmul__ = interp2app(W_ListObject.descr_mul), __imul__ = interp2app(W_ListObject.descr_inplace_mul), __getitem__ = interp2app(W_ListObject.descr_getitem), From noreply at buildbot.pypy.org Sun May 19 17:48:44 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Sun, 19 May 2013 17:48:44 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: No need to return space.w_None. Message-ID: <20130519154844.04E9D1C01CD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64331:042f9a29ef0b Date: 2013-05-19 17:35 +0200 http://bitbucket.org/pypy/pypy/changeset/042f9a29ef0b/ Log: No need to return space.w_None. diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -547,7 +547,6 @@ def descr_reverse(self, space): 'L.reverse() -- reverse *IN PLACE*' self.reverse() - return space.w_None def descr_count(self, space, w_value): '''L.count(value) -> integer -- return number of @@ -567,7 +566,6 @@ length = self.length() index = get_positive_index(index, length) self.insert(index, w_value) - return space.w_None @unwrap_spec(index=int) def descr_pop(self, space, index=-1): @@ -598,7 +596,6 @@ space.wrap("list.remove(x): x not in list")) if i < self.length(): # otherwise list was mutated self.pop(i) - return space.w_None @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(maxint)) def descr_index(self, space, w_value, w_start, w_stop): @@ -637,7 +634,7 @@ sorterclass = SimpleSort else: self.sort(reverse) - return space.w_None + return sorter = sorterclass(self.getitems(), self.length()) sorter.space = space @@ -687,8 +684,6 @@ raise OperationError(space.w_ValueError, space.wrap("list modified during sort")) - return space.w_None - class ListStrategy(object): sizehint = -1 From noreply at buildbot.pypy.org Sun May 19 18:21:30 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 18:21:30 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Attempt to fix issues with a call_release_gil with a non-immediate Message-ID: <20130519162130.047531C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64332:4508172468aa Date: 2013-05-19 18:20 +0200 http://bitbucket.org/pypy/pypy/changeset/4508172468aa/ Log: Attempt to fix issues with a call_release_gil with a non-immediate function. Add some other optimizations. diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -6,7 +6,7 @@ from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, - RegLoc, RawEspLoc, imm) + RegLoc, RawEspLoc, imm, ImmedLoc) from rpython.jit.backend.x86.jump import remap_frame_layout @@ -43,10 +43,16 @@ def __init__(self, assembler, fnloc, arglocs, resloc=eax): + # Avoid tons of issues with a non-immediate fnloc by sticking it + # as an extra argument if needed + self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) + if self.fnloc_is_immediate: + self.fnloc = fnloc + self.arglocs = arglocs + else: + self.arglocs = arglocs + [fnloc] self.asm = assembler self.mc = assembler.mc - self.fnloc = fnloc - self.arglocs = arglocs self.resloc = resloc self.current_esp = 0 @@ -256,14 +262,13 @@ self.mc.MOVSD(xmm0, loc) self.mc.MOVSD_sx(p, xmm0.value) else: - if self.fnloc is eax: - tmp = ecx - else: - tmp = eax - self.mc.MOV(tmp, loc) - self.mc.MOV_sr(p, tmp.value) + self.mc.MOV(eax, loc) + self.mc.MOV_sr(p, eax.value) p += loc.get_width() self.total_stack_used_by_arguments = p + # + if not self.fnloc_is_immediate: # the last "argument" pushed above + self.fnloc = RawEspLoc(p - WORD, INT) def _fix_stdcall(self, callconv): @@ -374,19 +379,27 @@ # them in precisely the final registers. Here we look around for # unused registers that may be more likely usable. from rpython.jit.backend.x86.regalloc import X86_64_RegisterManager + from rpython.jit.backend.x86.regalloc import X86_64_XMMRegisterManager self.already_used = {} for loc in self.arglocs: self.already_used[loc] = None # lst = X86_64_RegisterManager.save_around_call_regs[:] self._permute_to_prefer_unused_registers(lst) + # + extra = [] + for reg in self.asm._regalloc.rm.free_regs: + if (reg not in self.already_used and + reg in self._ALL_CALLEE_SAVE_GPR): + extra.append(reg) + lst = extra + lst + # self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] self.DONT_MOVE_GPR = self._ALL_CALLEE_SAVE_GPR # - lst = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + lst = X86_64_XMMRegisterManager.save_around_call_regs[:] self._permute_to_prefer_unused_registers(lst) - assert len(lst) == len(self.ARGUMENTS_XMM) - self.ARGUMENTS_XMM = lst + self.ARGUMENTS_XMM = lst[:len(self.ARGUMENTS_XMM)] def prepare_arguments(self): src_locs = [] @@ -425,6 +438,9 @@ src_locs.append(loc) dst_locs.append(tgt) + if not self.fnloc_is_immediate: + self.fnloc = dst_locs[-1] # the last "argument" prepared above + if not we_are_translated(): # assert that we got the right stack depth floats = 0 for i in range(len(arglocs)): @@ -457,12 +473,6 @@ src = X86_64_SCRATCH_REG self.mc.MOVD(dst, src) # Finally remap the arguments in the main regs - # If x is a register and is in dst_locs, then oups, it needs to - # be moved away: - if self.fnloc in dst_locs: - src_locs.append(self.fnloc) - dst_locs.append(r10) - self.fnloc = r10 remap_frame_layout(self.asm, src_locs, dst_locs, X86_64_SCRATCH_REG) @@ -535,6 +545,9 @@ self.mc.MOVSD_xs(CallBuilder64.ARGUMENTS_XMM[i].value, n * WORD) n += 1 assert n == self.n_saved_regs + # + if isinstance(self.fnloc, RegLoc): # fix this register + self.fnloc = CallBuilder64.ARGUMENTS_GPR[n_gpr - 1] if IS_X86_32: From noreply at buildbot.pypy.org Sun May 19 18:37:25 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 18:37:25 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: fixes Message-ID: <20130519163725.B4F451C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64333:6f8665556925 Date: 2013-05-19 18:23 +0200 http://bitbucket.org/pypy/pypy/changeset/6f8665556925/ Log: fixes diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -27,7 +27,7 @@ # this can be set to guide more complex calls: gives the detailed # type of the arguments - argtypes = None + argtypes = [] restype = INT ressize = WORD ressign = False @@ -421,7 +421,7 @@ on_stack += 1 xmm_src_locs.append(loc) xmm_dst_locs.append(tgt) - elif argtypes is not None and argtypes[i] == 'S': + elif i < len(argtypes) and argtypes[i] == 'S': # Singlefloat argument if singlefloats is None: singlefloats = [] @@ -445,7 +445,7 @@ floats = 0 for i in range(len(arglocs)): arg = arglocs[i] - if arg.is_float() or argtypes and argtypes[i] == 'S': + if arg.is_float() or (i < len(argtypes) and argtypes[i]=='S'): floats += 1 all_args = len(arglocs) stack_depth = (max(all_args - floats - len(self.ARGUMENTS_GPR), 0) diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -553,6 +553,7 @@ CALL_l = insn('\xE8', relative(1)) CALL_r = insn(rex_nw, '\xFF', register(1), chr(0xC0 | (2<<3))) CALL_b = insn('\xFF', orbyte(2<<3), stack_bp(1)) + CALL_s = insn('\xFF', orbyte(2<<3), stack_sp(1)) # XXX: Only here for testing purposes..."as" happens the encode the # registers in the opposite order that we would otherwise do in a From noreply at buildbot.pypy.org Sun May 19 18:37:26 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 18:37:26 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Improve Message-ID: <20130519163726.EE6D81C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64334:429b32de05ed Date: 2013-05-19 18:30 +0200 http://bitbucket.org/pypy/pypy/changeset/429b32de05ed/ Log: Improve diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -261,6 +261,8 @@ if loc.get_width() == 8: self.mc.MOVSD(xmm0, loc) self.mc.MOVSD_sx(p, xmm0.value) + elif isinstance(loc, ImmedLoc): + self.mc.MOV_si(p, loc.value) else: self.mc.MOV(eax, loc) self.mc.MOV_sr(p, eax.value) From noreply at buildbot.pypy.org Sun May 19 18:37:28 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 18:37:28 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Fix Message-ID: <20130519163728.44CC11C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64335:b721a7cda30a Date: 2013-05-19 18:36 +0200 http://bitbucket.org/pypy/pypy/changeset/b721a7cda30a/ Log: Fix diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1003,8 +1003,8 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def simple_call(self, fnloc, arglocs): - cb = callbuilder.CallBuilder(self, fnloc, arglocs) + def simple_call(self, fnloc, arglocs, result_loc=eax): + cb = callbuilder.CallBuilder(self, fnloc, arglocs, result_loc) cb.emit() def _reload_frame_if_necessary(self, mc, align_stack=False): @@ -1913,8 +1913,8 @@ def _call_assembler_emit_call(self, addr, argloc, _): self.simple_call(addr, [argloc]) - def _call_assembler_emit_helper_call(self, addr, arglocs, _): - self.simple_call(addr, arglocs) + def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc): + self.simple_call(addr, arglocs, result_loc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -279,10 +279,8 @@ return self.total_stack_used_by_arguments def load_result(self): - if self.ressize == 0: - return # void result resloc = self.resloc - if resloc.is_float(): + if resloc is not None and resloc.is_float(): # a float or a long long return if self.tmpresloc is None: if self.restype == 'L': # long long From noreply at buildbot.pypy.org Sun May 19 19:51:40 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 19:51:40 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Preliminary version of a test checking the various result types Message-ID: <20130519175140.8351C1C13E5@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64337:9da176ff588f Date: 2013-05-19 19:39 +0200 http://bitbucket.org/pypy/pypy/changeset/9da176ff588f/ Log: Preliminary version of a test checking the various result types diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2532,6 +2532,77 @@ assert rffi.charp2strn(buffer, buflen) == cwd lltype.free(buffer, flavor='raw') + def test_call_release_gil_return_types(self): + from rpython.rlib.libffi import CDLL, types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + cpu = self.cpu + + for ffitype, result, TP in [ + (types.ulong, r_uint(sys.maxint + 10), lltype.Unsigned), + (types.slong, -4321, lltype.Signed), + (types.uint8, 200, rffi.UCHAR), + (types.sint8, -42, rffi.SIGNEDCHAR), + (types.uint16, 50000, rffi.USHORT), + (types.sint16, -20000, rffi.SHORT), + (types.uint32, r_uint(3000000000), rffi.UINT), + (types.sint32, -2000000000, rffi.INT), + (types.uint64, r_ulonglong(9999999999999999999), + lltype.UnsignedLongLong), + (types.sint64, r_longlong(-999999999999999999), + lltype.SignedLongLong), + (types.double, 12.3475226, rffi.DOUBLE), + (types.float, r_singlefloat(-592.75), rffi.FLOAT), + ]: + if sys.maxint < 2**32 and TP in (lltype.SignedLongLong, + lltype.UnsignedLongLong): + if not cpu.supports_longlong: + continue + if TP == rffi.DOUBLE: + if not cpu.supports_floats: + continue + if TP == rffi.FLOAT: + if not cpu.supports_singlefloats: + continue + # + result = rffi.cast(TP, result) + # + def pseudo_c_function(): + return result + # + FPTR = self.Ptr(self.FuncType([], TP)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests([], ffitype) + faildescr = BasicFailDescr(1) + kind = types.getkind(ffitype) + if kind in 'uis': + b3 = BoxInt() + elif kind in 'fUI': + b3 = BoxFloat() + else: + assert 0, kind + # + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox], b3, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [b3], None, descr=BasicFinalDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = JitCellToken() + self.cpu.compile_loop([], ops, looptoken) + + deadframe = self.cpu.execute_token(looptoken) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + if isinstance(b3, BoxInt): + r = self.cpu.get_int_value(deadframe, 0) + assert rffi.cast(TP, r) == result + elif isinstance(b3, BoxFloat): + r = self.cpu.get_float_value(deadframe, 0) + assert r == result # xxx + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() From noreply at buildbot.pypy.org Sun May 19 19:51:42 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 19:51:42 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: fix Message-ID: <20130519175142.2AFFD1C13F9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64338:5d96085a18f3 Date: 2013-05-19 19:43 +0200 http://bitbucket.org/pypy/pypy/changeset/5d96085a18f3/ Log: fix diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2601,7 +2601,11 @@ assert rffi.cast(TP, r) == result elif isinstance(b3, BoxFloat): r = self.cpu.get_float_value(deadframe, 0) - assert r == result # xxx + if isinstance(result, float): + r = longlong.getrealfloat(r) + else: + r = rffi.cast(TP, r) + assert r == result def test_guard_not_invalidated(self): cpu = self.cpu From noreply at buildbot.pypy.org Sun May 19 19:51:39 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 19:51:39 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Tweaks Message-ID: <20130519175139.3114E1C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64336:67f739475067 Date: 2013-05-19 19:39 +0200 http://bitbucket.org/pypy/pypy/changeset/67f739475067/ Log: Tweaks diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1004,7 +1004,12 @@ return bool(gcrootmap) and not gcrootmap.is_shadow_stack def simple_call(self, fnloc, arglocs, result_loc=eax): - cb = callbuilder.CallBuilder(self, fnloc, arglocs, result_loc) + if result_loc is xmm0: + result_type = FLOAT + else: + result_type = INT + cb = callbuilder.CallBuilder(self, fnloc, arglocs, + result_loc, result_type) cb.emit() def _reload_frame_if_necessary(self, mc, align_stack=False): diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -6,7 +6,7 @@ from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, - RegLoc, RawEspLoc, imm, ImmedLoc) + RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) from rpython.jit.backend.x86.jump import remap_frame_layout @@ -28,7 +28,6 @@ # this can be set to guide more complex calls: gives the detailed # type of the arguments argtypes = [] - restype = INT ressize = WORD ressign = False @@ -42,7 +41,7 @@ tmpresloc = None - def __init__(self, assembler, fnloc, arglocs, resloc=eax): + def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT): # Avoid tons of issues with a non-immediate fnloc by sticking it # as an extra argument if needed self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) @@ -54,6 +53,7 @@ self.asm = assembler self.mc = assembler.mc self.resloc = resloc + self.restype = restype self.current_esp = 0 def emit(self): @@ -392,6 +392,7 @@ if (reg not in self.already_used and reg in self._ALL_CALLEE_SAVE_GPR): extra.append(reg) + self.free_callee_save_gprs = extra lst = extra + lst # self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] @@ -492,19 +493,23 @@ if self.ressize == 0: # void return return # + if self.restype == FLOAT: # and not 'S' + self.mc.MOVSD_sx(0, xmm0.value) + self.tmpresloc = RawEspLoc(0, FLOAT) + return + # + if len(self.free_callee_save_gprs) == 0: + self.tmpresloc = RawEspLoc(0, INT) + else: + self.tmpresloc = self.free_callee_save_gprs[0] + # if self.restype == 'S': # singlefloat return: use MOVD to store the lower 32 bits - # of XMM0 into [ESP] - self.mc.MOVD_sx(0, xmm0.value) - type = INT - elif self.restype == FLOAT: - self.mc.MOVSD_sx(0, xmm0.value) - type = FLOAT + # of XMM0 into the tmpresloc (register or [ESP]) + self.mc.MOVD(self.tmpresloc, xmm0) else: assert self.restype == INT - self.mc.MOV_sr(0, eax.value) - type = INT - self.tmpresloc = RawEspLoc(0, type) + self.mc.MOV(self.tmpresloc, eax) def save_register_arguments(self): # Save the argument registers, which are given by self.ARGUMENTS_xxx. From noreply at buildbot.pypy.org Sun May 19 19:51:43 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 19:51:43 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: fix Message-ID: <20130519175143.555201C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64339:75c58f0cd85b Date: 2013-05-19 19:46 +0200 http://bitbucket.org/pypy/pypy/changeset/75c58f0cd85b/ Log: fix diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2598,7 +2598,12 @@ assert fail.identifier == 0 if isinstance(b3, BoxInt): r = self.cpu.get_int_value(deadframe, 0) - assert rffi.cast(TP, r) == result + if isinstance(result, r_singlefloat): + r, = struct.unpack("f", struct.pack("i", r)) + result = float(result) + else: + r = rffi.cast(TP, r) + assert r == result elif isinstance(b3, BoxFloat): r = self.cpu.get_float_value(deadframe, 0) if isinstance(result, float): From noreply at buildbot.pypy.org Sun May 19 19:51:44 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 19:51:44 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: fixes Message-ID: <20130519175144.A48F81C10FA@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64340:757e2f4aedcf Date: 2013-05-19 19:50 +0200 http://bitbucket.org/pypy/pypy/changeset/757e2f4aedcf/ Log: fixes diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2599,7 +2599,8 @@ if isinstance(b3, BoxInt): r = self.cpu.get_int_value(deadframe, 0) if isinstance(result, r_singlefloat): - r, = struct.unpack("f", struct.pack("i", r)) + assert -sys.maxint-1 <= r <= 0xFFFFFFFF + r, = struct.unpack("f", struct.pack("I", r & 0xFFFFFFFF)) result = float(result) else: r = rffi.cast(TP, r) diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -111,12 +111,12 @@ if srcloc is None: if self.restype == FLOAT: srcloc = xmm0 - elif self.ressize == 1: - srcloc = eax.lowest8bits() else: srcloc = eax if self.ressize >= WORD and self.resloc is srcloc: return # no need for any MOV + if self.ressize == 1 and isinstance(srcloc, RegLoc): + srcloc = srcloc.lowest8bits() self.asm.load_from_mem(self.resloc, srcloc, imm(self.ressize), imm(self.ressign)) From noreply at buildbot.pypy.org Sun May 19 20:42:52 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 20:42:52 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Add a test about call_release_gil and all kinds of combinations thereof Message-ID: <20130519184252.AE2971C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64341:11308c51c9a5 Date: 2013-05-19 20:37 +0200 http://bitbucket.org/pypy/pypy/changeset/11308c51c9a5/ Log: Add a test about call_release_gil and all kinds of combinations thereof diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2533,7 +2533,7 @@ lltype.free(buffer, flavor='raw') def test_call_release_gil_return_types(self): - from rpython.rlib.libffi import CDLL, types + from rpython.rlib.libffi import types from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong from rpython.rlib.rarithmetic import r_singlefloat cpu = self.cpu @@ -2613,6 +2613,130 @@ r = rffi.cast(TP, r) assert r == result + def test_call_release_gil_variable_function_and_arguments(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + + cpu = self.cpu + rnd = random.Random(525) + + ALL_TYPES = [ + (types.ulong, lltype.Unsigned), + (types.slong, lltype.Signed), + (types.uint8, rffi.UCHAR), + (types.sint8, rffi.SIGNEDCHAR), + (types.uint16, rffi.USHORT), + (types.sint16, rffi.SHORT), + (types.uint32, rffi.UINT), + (types.sint32, rffi.INT), + ] + if sys.maxint < 2**32 and cpu.supports_longlong: + ALL_TYPES += [ + (types.uint64, lltype.UnsignedLongLong), + (types.sint64, lltype.SignedLongLong), + ] * 2 + if cpu.supports_floats: + ALL_TYPES += [ + (types.double, rffi.DOUBLE), + ] * 4 + if cpu.supports_singlefloats: + ALL_TYPES += [ + (types.float, rffi.FLOAT), + ] * 4 + + for k in range(1000): + # + def pseudo_c_function(*args): + seen.append(list(args)) + # + ffitypes = [] + ARGTYPES = [] + for i in range(rnd.randrange(4, 20)): + ffitype, TP = rnd.choice(ALL_TYPES) + ffitypes.append(ffitype) + ARGTYPES.append(TP) + # + FPTR = self.Ptr(self.FuncType(ARGTYPES, lltype.Void)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void) + faildescr = BasicFailDescr(1) + # + argboxes = [BoxInt()] # for the function to call + codes = ['X'] + for ffitype in ffitypes: + kind = types.getkind(ffitype) + codes.append(kind) + if kind in 'uis': + b1 = BoxInt() + elif kind in 'fUI': + b1 = BoxFloat() + else: + assert 0, kind + argboxes.append(b1) + codes = ''.join(codes) # useful for pdb + print + print codes + # + argvalues = [funcbox.getint()] + for TP in ARGTYPES: + r = (rnd.random() - 0.5) * 999999999999.9 + r = rffi.cast(TP, r) + argvalues.append(r) + # + argvalues_normal = argvalues[:1] + for ffitype, r in zip(ffitypes, argvalues[1:]): + kind = types.getkind(ffitype) + if kind in 'ui': + r = rffi.cast(lltype.Signed, r) + elif kind in 's': + r, = struct.unpack("i", struct.pack("f", float(r))) + elif kind in 'f': + r = longlong.getfloatstorage(r) + elif kind in 'UI': # 32-bit only + r = rffi.cast(lltype.SignedLongLong, r) + else: + assert 0 + argvalues_normal.append(r) + # + ops = [] + loadcodes = [] + insideboxes = [] + for b1 in argboxes: + load = rnd.random() < 0.75 + loadcodes.append(' ^'[load]) + if load: + b2 = b1.clonebox() + ops += [ + ResOperation(rop.SAME_AS, [b1], b2) + ] + b1 = b2 + insideboxes.append(b1) + loadcodes = ''.join(loadcodes) + print loadcodes + ops += [ + ResOperation(rop.CALL_RELEASE_GIL, insideboxes, None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0)) + ] + ops[-2].setfailargs([]) + looptoken = JitCellToken() + self.cpu.compile_loop(argboxes, ops, looptoken) + # + seen = [] + deadframe = self.cpu.execute_token(looptoken, *argvalues_normal) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + expected = argvalues[1:] + [got] = seen + different_values = ['%r != %r' % (a, b) + for a, b in zip(got, expected) + if a != b] + assert got == expected, ', '.join(different_values) + + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() From noreply at buildbot.pypy.org Sun May 19 20:42:53 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 20:42:53 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Improve testing: any access to ebp between the GIL release and require will give nonsense results Message-ID: <20130519184253.DE6EF1C13E5@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64342:81c1063efbe4 Date: 2013-05-19 20:42 +0200 http://bitbucket.org/pypy/pypy/changeset/81c1063efbe4/ Log: Improve testing: any access to ebp between the GIL release and require will give nonsense results diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -192,6 +192,9 @@ # self.mc.CALL(imm(self.asm.releasegil_addr)) # + if not we_are_translated(): # for testing: we should not access + self.mc.ADD(ebp, imm(1)) # ebp any more + # self.restore_register_arguments() self.restore_esp(initial_esp) @@ -220,6 +223,9 @@ # self.mc.CALL(imm(self.asm.reacqgil_addr)) # + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB(ebp, imm(1)) # ebp again + # # Now that we required the GIL, we can reload a possibly modified ebp if self.asm._is_asmgcc(): # special-case: reload ebp from the css From noreply at buildbot.pypy.org Sun May 19 20:47:11 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 20:47:11 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: fix Message-ID: <20130519184711.0617A1C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64343:272efc3772c8 Date: 2013-05-19 20:46 +0200 http://bitbucket.org/pypy/pypy/changeset/272efc3772c8/ Log: fix diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -348,12 +348,13 @@ def _unused_gpr(self, hint): i = self.next_arg_gpr self.next_arg_gpr = i + 1 - if hint in self.DONT_MOVE_GPR: - return hint try: - return self.ARGUMENTS_GPR[i] + res = self.ARGUMENTS_GPR[i] except IndexError: return None + if hint in self.DONT_MOVE_GPR: + res = hint + return res def _unused_xmm(self): i = self.next_arg_xmm From noreply at buildbot.pypy.org Sun May 19 21:03:17 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 21:03:17 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: fix Message-ID: <20130519190317.2E25C1C13FB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64344:6e03d53e6d6f Date: 2013-05-19 20:57 +0200 http://bitbucket.org/pypy/pypy/changeset/6e03d53e6d6f/ Log: fix diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -353,6 +353,7 @@ except IndexError: return None if hint in self.DONT_MOVE_GPR: + self.ARGUMENTS_GPR[i] = hint res = hint return res From noreply at buildbot.pypy.org Sun May 19 21:03:18 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 21:03:18 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Improve the test Message-ID: <20130519190318.B3E291C13FB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64345:ac2bd751b3c4 Date: 2013-05-19 21:02 +0200 http://bitbucket.org/pypy/pypy/changeset/ac2bd751b3c4/ Log: Improve the test diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2708,9 +2708,8 @@ loadcodes.append(' ^'[load]) if load: b2 = b1.clonebox() - ops += [ - ResOperation(rop.SAME_AS, [b1], b2) - ] + ops.insert(rnd.randrange(0, len(ops)+1), + ResOperation(rop.SAME_AS, [b1], b2)) b1 = b2 insideboxes.append(b1) loadcodes = ''.join(loadcodes) @@ -2722,6 +2721,11 @@ ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0)) ] ops[-2].setfailargs([]) + # keep alive a random subset of the insideboxes + for b1 in insideboxes: + if rnd.random() < 0.333: + ops.insert(-1, ResOperation(rop.SAME_AS, [b1], + b1.clonebox())) looptoken = JitCellToken() self.cpu.compile_loop(argboxes, ops, looptoken) # From noreply at buildbot.pypy.org Sun May 19 21:16:08 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 21:16:08 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: done, seems to work Message-ID: <20130519191608.9B1491C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64346:eae2a91c2dd3 Date: 2013-05-19 21:15 +0200 http://bitbucket.org/pypy/pypy/changeset/eae2a91c2dd3/ Log: done, seems to work diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2645,7 +2645,7 @@ (types.float, rffi.FLOAT), ] * 4 - for k in range(1000): + for k in range(100): # def pseudo_c_function(*args): seen.append(list(args)) From noreply at buildbot.pypy.org Sun May 19 22:15:04 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 22:15:04 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: just skip this test on top of the llgraph backend Message-ID: <20130519201504.E2DF11C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64347:ae2989f5a6bc Date: 2013-05-19 22:01 +0200 http://bitbucket.org/pypy/pypy/changeset/ae2989f5a6bc/ Log: just skip this test on top of the llgraph backend diff --git a/rpython/jit/backend/llgraph/test/test_llgraph.py b/rpython/jit/backend/llgraph/test/test_llgraph.py --- a/rpython/jit/backend/llgraph/test/test_llgraph.py +++ b/rpython/jit/backend/llgraph/test/test_llgraph.py @@ -15,6 +15,9 @@ def test_memoryerror(self): py.test.skip("does not make much sense on the llgraph backend") + def test_call_release_gil_variable_function_and_arguments(self): + py.test.skip("the arguments seem not correctly casted") + def test_cast_adr_to_int_and_back(): X = lltype.Struct('X', ('foo', lltype.Signed)) From noreply at buildbot.pypy.org Sun May 19 22:15:06 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 22:15:06 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Introduce and use emit_no_collect(). Message-ID: <20130519201506.30E351C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64348:5bf566262645 Date: 2013-05-19 22:08 +0200 http://bitbucket.org/pypy/pypy/changeset/5bf566262645/ Log: Introduce and use emit_no_collect(). diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1012,6 +1012,10 @@ result_loc, result_type) cb.emit() + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.CallBuilder(self, fnloc, arglocs) + cb.emit_no_collect() + def _reload_frame_if_necessary(self, mc, align_stack=False): gcrootmap = self.cpu.gc_ll_descr.gcrootmap if gcrootmap: diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -56,6 +56,13 @@ self.restype = restype self.current_esp = 0 + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_esp() + self.load_result() + def emit(self): """Emit a regular call; not for CALL_RELEASE_GIL.""" self.prepare_arguments() diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1131,9 +1131,8 @@ # call memcpy() self.rm.before_call() self.xrm.before_call() - self.assembler._emit_call(imm(self.assembler.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.assembler.simple_call_no_collect(imm(self.assembler.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) self.rm.possibly_free_var(length_box) self.rm.possibly_free_var(dstaddr_box) self.rm.possibly_free_var(srcaddr_box) From noreply at buildbot.pypy.org Sun May 19 22:15:07 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 22:15:07 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: fix Message-ID: <20130519201507.7C4AD1C01CD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64349:8f33f01f56c5 Date: 2013-05-19 22:12 +0200 http://bitbucket.org/pypy/pypy/changeset/8f33f01f56c5/ Log: fix diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -6,7 +6,7 @@ DEBUG_COUNTER, debug_bridge) from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.llsupport.gcmap import allocate_gcmap -from rpython.jit.metainterp.history import Const, Box +from rpython.jit.metainterp.history import Const, Box, VOID from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory from rpython.rtyper.lltypesystem.lloperation import llop @@ -1006,10 +1006,16 @@ def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: result_type = FLOAT + result_size = 8 + elif result_loc is None: + result_type = VOID + result_size = 0 else: result_type = INT + result_size = WORD cb = callbuilder.CallBuilder(self, fnloc, arglocs, - result_loc, result_type) + result_loc, result_type, + result_size) cb.emit() def simple_call_no_collect(self, fnloc, arglocs): diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -28,7 +28,6 @@ # this can be set to guide more complex calls: gives the detailed # type of the arguments argtypes = [] - ressize = WORD ressign = False # this is the calling convention (can be FFI_STDCALL on Windows) @@ -41,7 +40,8 @@ tmpresloc = None - def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT): + def __init__(self, assembler, fnloc, arglocs, + resloc=eax, restype=INT, ressize=WORD): # Avoid tons of issues with a non-immediate fnloc by sticking it # as an extra argument if needed self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) @@ -54,6 +54,7 @@ self.mc = assembler.mc self.resloc = resloc self.restype = restype + self.ressize = ressize self.current_esp = 0 def emit_no_collect(self): From noreply at buildbot.pypy.org Sun May 19 22:20:31 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 22:20:31 +0200 (CEST) Subject: [pypy-commit] pypy default: skip when _testcapi ImportErrors (like the other cpyext skips) which is less Message-ID: <20130519202031.537661C0698@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64350:2b05ce699b09 Date: 2013-05-19 13:17 -0700 http://bitbucket.org/pypy/pypy/changeset/2b05ce699b09/ Log: skip when _testcapi ImportErrors (like the other cpyext skips) which is less pypy-specific diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -8,7 +8,7 @@ from copy import copy, deepcopy from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, - check_impl_detail) + import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -236,13 +236,11 @@ # XXX more platforms to tests here def test_get_config_h_filename(self): - if check_impl_detail(pypy=True): - try: - import cpyext - except ImportError: - self.skipTest("This test depends on cpyext.") config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', From noreply at buildbot.pypy.org Sun May 19 22:20:32 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 22:20:32 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130519202032.957C61C0698@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64351:5cfb4173e757 Date: 2013-05-19 13:18 -0700 http://bitbucket.org/pypy/pypy/changeset/5cfb4173e757/ Log: merge default diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -7,7 +7,8 @@ import subprocess from copy import copy, deepcopy -from test.test_support import run_unittest, TESTFN, unlink, get_attribute +from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, + import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -236,7 +237,10 @@ def test_get_config_h_filename(self): config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -124,12 +124,10 @@ __import__(name) except (ImportError, CompilationError, py.test.skip.Exception), e: errcls = e.__class__.__name__ - config.add_warning( + raise Exception( "The module %r is disabled\n" % (modname,) + "because importing %s raised %s\n" % (name, errcls) + str(e)) - raise ConflictConfigError("--withmod-%s: %s" % (modname, - errcls)) return validator else: return None 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 @@ -1022,24 +1022,35 @@ expected_path = [str(prefix.join(subdir).ensure(dir=1)) for subdir in ('lib_pypy', 'lib-python/%s' % cpy_ver)] + # an empty directory from where we can't find the stdlib + tmp_dir = str(udir.join('tmp').ensure(dir=1)) self.w_goal_dir = self.space.wrap(goal_dir) self.w_fake_exe = self.space.wrap(str(fake_exe)) self.w_expected_path = self.space.wrap(expected_path) self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir)) + self.w_tmp_dir = self.space.wrap(tmp_dir) + foo_py = prefix.join('foo.py').write("pass") self.w_foo_py = self.space.wrap(str(foo_py)) def test_setup_bootstrap_path(self): - import sys + # Check how sys.path is handled depending on if we can find a copy of + # the stdlib in setup_bootstrap_path. + import sys, os old_sys_path = sys.path[:] + old_cwd = os.getcwd() + sys.path.append(self.goal_dir) + # make sure cwd does not contain a stdlib + os.chdir(self.tmp_dir) + tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c') try: import app_main - app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found + app_main.setup_bootstrap_path(tmp_pypy_c) # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + assert sys.path == old_sys_path + [self.goal_dir] app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe @@ -1052,6 +1063,7 @@ assert newpath[:len(self.expected_path)] == self.expected_path finally: sys.path[:] = old_sys_path + os.chdir(old_cwd) def test_trunk_can_be_prefix(self): import sys diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -232,9 +232,9 @@ import _rawffi # this should return *all* loaded libs, dlopen(NULL) dll = _rawffi.CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.ptr('Py_IsInitialized', [], 'l')() - assert res[0] == 1 + func = dll.ptr('rand', [], 'i') + res = func() + assert res[0] != 0 def test_libc_load(self): import _rawffi diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -274,7 +274,10 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + if self.ptr_size == 8: + assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + else: + assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype def test_pickle_record(self): diff --git a/rpython/translator/c/src/stacklet/tests.c b/rpython/translator/c/src/stacklet/tests.c --- a/rpython/translator/c/src/stacklet/tests.c +++ b/rpython/translator/c/src/stacklet/tests.c @@ -31,7 +31,7 @@ assert(status == 0); status = 1; assert(h != EMPTY_STACKLET_HANDLE); - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); assert(status == 2); assert(h != EMPTY_STACKLET_HANDLE); status = 3; @@ -45,7 +45,7 @@ assert(h != EMPTY_STACKLET_HANDLE); assert(status == 1); status = 2; - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); assert(status == 3); assert(h == EMPTY_STACKLET_HANDLE); } @@ -148,7 +148,7 @@ //printf("switch to %d\n", n); h = handles[n]; handles[n] = NULL; - h = stacklet_switch(thrd, h); + h = stacklet_switch(h); } //printf("back in self = %d, coming from %d\n", self, comefrom); assert(nextstep == status); From noreply at buildbot.pypy.org Sun May 19 22:20:33 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 19 May 2013 22:20:33 +0200 (CEST) Subject: [pypy-commit] pypy py3k: reapply 2b05ce699b09 from default Message-ID: <20130519202033.C4F231C0698@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64352:bb0df4cbd219 Date: 2013-05-19 13:19 -0700 http://bitbucket.org/pypy/pypy/changeset/bb0df4cbd219/ Log: reapply 2b05ce699b09 from default diff --git a/lib-python/3/test/test_sysconfig.py b/lib-python/3/test/test_sysconfig.py --- a/lib-python/3/test/test_sysconfig.py +++ b/lib-python/3/test/test_sysconfig.py @@ -13,7 +13,7 @@ from test.support import (run_unittest, TESTFN, unlink, get_attribute, captured_stdout, skip_unless_symlink, - impl_detail) + impl_detail, import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -232,7 +232,10 @@ def test_get_config_h_filename(self): config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', From noreply at buildbot.pypy.org Sun May 19 22:21:55 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 22:21:55 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: translation fix Message-ID: <20130519202155.8330A1C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64353:6b712fc72723 Date: 2013-05-19 22:20 +0200 http://bitbucket.org/pypy/pypy/changeset/6b712fc72723/ Log: translation fix diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -27,7 +27,7 @@ # this can be set to guide more complex calls: gives the detailed # type of the arguments - argtypes = [] + argtypes = "" ressign = False # this is the calling convention (can be FFI_STDCALL on Windows) From noreply at buildbot.pypy.org Sun May 19 23:10:00 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 19 May 2013 23:10:00 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: translation fix Message-ID: <20130519211000.933821C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64354:e9deb3c80b86 Date: 2013-05-19 23:02 +0200 http://bitbucket.org/pypy/pypy/changeset/e9deb3c80b86/ Log: translation fix diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -189,7 +189,7 @@ # (PASS_ON_MY_FRAME-JIT_USE_WORDS+1) words delta = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + 1 self.change_extra_stack_depth = True - self.set_extra_stack_depth(self.mc, -delta * WORD) + self.asm.set_extra_stack_depth(self.mc, -delta * WORD) # Call the closestack() function (also releasing the GIL) # with 'reg' as argument if IS_X86_32: From noreply at buildbot.pypy.org Mon May 20 02:03:34 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Mon, 20 May 2013 02:03:34 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: hg merge default Message-ID: <20130520000334.764EF1C0698@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64355:eaf13558acc7 Date: 2013-05-20 01:45 +0200 http://bitbucket.org/pypy/pypy/changeset/eaf13558acc7/ Log: hg merge default diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -7,7 +7,8 @@ import subprocess from copy import copy, deepcopy -from test.test_support import run_unittest, TESTFN, unlink, get_attribute +from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, + import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -236,7 +237,10 @@ def test_get_config_h_filename(self): config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -232,9 +232,9 @@ import _rawffi # this should return *all* loaded libs, dlopen(NULL) dll = _rawffi.CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.ptr('Py_IsInitialized', [], 'l')() - assert res[0] == 1 + func = dll.ptr('rand', [], 'i') + res = func() + assert res[0] != 0 def test_libc_load(self): import _rawffi diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,10 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + if self.ptr_size == 8: + assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + else: + assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype def test_pickle_record(self): From noreply at buildbot.pypy.org Mon May 20 10:50:19 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 10:50:19 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Improve the test: this will test more corner cases and less Message-ID: <20130520085019.892D01C1027@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64356:5a2787d656d2 Date: 2013-05-20 10:44 +0200 http://bitbucket.org/pypy/pypy/changeset/5a2787d656d2/ Log: Improve the test: this will test more corner cases and less "a common mixture of stuff in each test". diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2646,6 +2646,10 @@ ] * 4 for k in range(100): + POSSIBLE_TYPES = [rnd.choice(ALL_TYPES) + for i in range(random.randrange(2, 5))] + load_factor = rnd.random() + keepalive_factor = rnd.random() # def pseudo_c_function(*args): seen.append(list(args)) @@ -2653,7 +2657,7 @@ ffitypes = [] ARGTYPES = [] for i in range(rnd.randrange(4, 20)): - ffitype, TP = rnd.choice(ALL_TYPES) + ffitype, TP = rnd.choice(POSSIBLE_TYPES) ffitypes.append(ffitype) ARGTYPES.append(TP) # @@ -2704,7 +2708,7 @@ loadcodes = [] insideboxes = [] for b1 in argboxes: - load = rnd.random() < 0.75 + load = rnd.random() < load_factor loadcodes.append(' ^'[load]) if load: b2 = b1.clonebox() @@ -2723,7 +2727,7 @@ ops[-2].setfailargs([]) # keep alive a random subset of the insideboxes for b1 in insideboxes: - if rnd.random() < 0.333: + if rnd.random() < keepalive_factor: ops.insert(-1, ResOperation(rop.SAME_AS, [b1], b1.clonebox())) looptoken = JitCellToken() From noreply at buildbot.pypy.org Mon May 20 11:52:59 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 20 May 2013 11:52:59 +0200 (CEST) Subject: [pypy-commit] pypy default: disable continuation on ARM for now Message-ID: <20130520095259.DF58F1C0698@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64357:d9f8a3ea2a44 Date: 2013-05-20 11:52 +0200 http://bitbucket.org/pypy/pypy/changeset/d9f8a3ea2a44/ Log: disable continuation on ARM for now diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -363,6 +363,9 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + + if config.translation.platform == 'arm' and '_continuation' in modules: + del modules[modules.find('_continuation')] config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): From noreply at buildbot.pypy.org Mon May 20 12:06:27 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 20 May 2013 12:06:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Fxi a bit too-precise tests in test_pypy_c Message-ID: <20130520100627.922BC1C0698@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64358:9dc46f55f9fd Date: 2013-05-20 12:05 +0200 http://bitbucket.org/pypy/pypy/changeset/9dc46f55f9fd/ Log: Fxi a bit too-precise tests in test_pypy_c diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -487,6 +487,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -586,7 +587,6 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=<.*>) i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -44,6 +44,7 @@ # gc_id call is hoisted out of the loop, the id of a value obviously # can't change ;) assert loop.match_by_id("getitem", """ + ... i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...) ... p33 = getinteriorfield_gc(p31, i26, descr=>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -36,7 +36,7 @@ assert loop0.match(expected) # XXX: The retracing fails to form a loop since j # becomes constant 0 after the bridge and constant 1 at the end of the - # loop. A bridge back to the peramble is produced instead. + # loop. A bridge back to the peramble is produced instead. #assert loop1.match(expected) def test_factorial(self): @@ -242,6 +242,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) + guard_not_invalidated(descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) From noreply at buildbot.pypy.org Mon May 20 12:28:58 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 12:28:58 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Add a test, which passes on CPython but crashes on pypy (tested with 2.0.0). Message-ID: <20130520102858.B5C331C0217@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64359:ec3557234635 Date: 2013-05-20 12:28 +0200 http://bitbucket.org/pypy/pypy/changeset/ec3557234635/ Log: Add a test, which passes on CPython but crashes on pypy (tested with 2.0.0). diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 From noreply at buildbot.pypy.org Mon May 20 13:13:13 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 13:13:13 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Fix :-/ It doesn't fail any test in jit/, but at least it fails the Message-ID: <20130520111313.13FDC1C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64360:03c66c06d7bd Date: 2013-05-20 12:51 +0200 http://bitbucket.org/pypy/pypy/changeset/03c66c06d7bd/ Log: Fix :-/ It doesn't fail any test in jit/, but at least it fails the test_bug.py just added diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -170,7 +170,7 @@ # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a # total size of JIT_USE_WORDS. This structure is found at # [ESP+css]. - css = WORD * (self.current_esp + + css = WORD * (-self.current_esp + PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) assert css >= 2 # Save ebp From noreply at buildbot.pypy.org Mon May 20 13:13:14 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 13:13:14 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Comments Message-ID: <20130520111314.64AE61C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64361:434a90ebaa43 Date: 2013-05-20 12:51 +0200 http://bitbucket.org/pypy/pypy/changeset/434a90ebaa43/ Log: Comments diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -55,7 +55,7 @@ self.resloc = resloc self.restype = restype self.ressize = ressize - self.current_esp = 0 + self.current_esp = 0 # 0 or (usually) negative, counted in bytes def emit_no_collect(self): """Emit a call that cannot collect.""" @@ -107,7 +107,7 @@ def restore_esp(self, target_esp=0): if self.current_esp != target_esp: - self.mc.SUB_ri(esp.value, self.current_esp - target_esp) + self.mc.ADD_ri(esp.value, target_esp - self.current_esp) self.current_esp = target_esp def load_result(self): From noreply at buildbot.pypy.org Mon May 20 13:13:15 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 13:13:15 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Aaargh. Some counters are in WORDs and others are in bytes. Confusion. Message-ID: <20130520111315.A658A1C1027@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64362:ef081fd53379 Date: 2013-05-20 13:09 +0200 http://bitbucket.org/pypy/pypy/changeset/ef081fd53379/ Log: Aaargh. Some counters are in WORDs and others are in bytes. Confusion. diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -170,9 +170,9 @@ # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a # total size of JIT_USE_WORDS. This structure is found at # [ESP+css]. - css = WORD * (-self.current_esp + - PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) - assert css >= 2 + css = -self.current_esp + ( + WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS)) + assert css >= 2 * WORD # Save ebp index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP From noreply at buildbot.pypy.org Mon May 20 13:22:41 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 13:22:41 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-x86: Close branch, ready to be merged Message-ID: <20130520112241.0A87E1C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: emit-call-x86 Changeset: r64363:5332115ec8dd Date: 2013-05-20 13:17 +0200 http://bitbucket.org/pypy/pypy/changeset/5332115ec8dd/ Log: Close branch, ready to be merged From noreply at buildbot.pypy.org Mon May 20 13:22:42 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 13:22:42 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge emit-call-x86: fix for multithreaded programs, particularly Message-ID: <20130520112242.D2A621C1024@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64364:7c80121abbf4 Date: 2013-05-20 13:22 +0200 http://bitbucket.org/pypy/pypy/changeset/7c80121abbf4/ Log: hg merge emit-call-x86: fix for multithreaded programs, particularly those that run more threads than cores. The issue was that a call_release_gil instruction compiles to code that still accesses ebp/rsp after it released the GIL. diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 diff --git a/rpython/jit/backend/llgraph/test/test_llgraph.py b/rpython/jit/backend/llgraph/test/test_llgraph.py --- a/rpython/jit/backend/llgraph/test/test_llgraph.py +++ b/rpython/jit/backend/llgraph/test/test_llgraph.py @@ -15,6 +15,9 @@ def test_memoryerror(self): py.test.skip("does not make much sense on the llgraph backend") + def test_call_release_gil_variable_function_and_arguments(self): + py.test.skip("the arguments seem not correctly casted") + def test_cast_adr_to_int_and_back(): X = lltype.Struct('X', ('foo', lltype.Signed)) 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 @@ -108,8 +108,7 @@ self.malloc_slowpath_unicode = None self._build_stack_check_slowpath() - if gc_ll_descr.gcrootmap: - self._build_release_gil(gc_ll_descr.gcrootmap) + self._build_release_gil(gc_ll_descr.gcrootmap) if not self._debug: # if self._debug is already set it means that someone called # set_debug by hand before initializing the assembler. Leave it @@ -348,12 +347,19 @@ if after: after() + @staticmethod + def _no_op(): + pass + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], lltype.Void)) def _build_release_gil(self, gcrootmap): - if gcrootmap.is_shadow_stack: + if gcrootmap is None: + releasegil_func = llhelper(self._NOARG_FUNC, self._no_op) + reacqgil_func = llhelper(self._NOARG_FUNC, self._no_op) + elif gcrootmap.is_shadow_stack: releasegil_func = llhelper(self._NOARG_FUNC, self._release_gil_shadowstack) reacqgil_func = llhelper(self._NOARG_FUNC, diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2532,6 +2532,219 @@ assert rffi.charp2strn(buffer, buflen) == cwd lltype.free(buffer, flavor='raw') + def test_call_release_gil_return_types(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + cpu = self.cpu + + for ffitype, result, TP in [ + (types.ulong, r_uint(sys.maxint + 10), lltype.Unsigned), + (types.slong, -4321, lltype.Signed), + (types.uint8, 200, rffi.UCHAR), + (types.sint8, -42, rffi.SIGNEDCHAR), + (types.uint16, 50000, rffi.USHORT), + (types.sint16, -20000, rffi.SHORT), + (types.uint32, r_uint(3000000000), rffi.UINT), + (types.sint32, -2000000000, rffi.INT), + (types.uint64, r_ulonglong(9999999999999999999), + lltype.UnsignedLongLong), + (types.sint64, r_longlong(-999999999999999999), + lltype.SignedLongLong), + (types.double, 12.3475226, rffi.DOUBLE), + (types.float, r_singlefloat(-592.75), rffi.FLOAT), + ]: + if sys.maxint < 2**32 and TP in (lltype.SignedLongLong, + lltype.UnsignedLongLong): + if not cpu.supports_longlong: + continue + if TP == rffi.DOUBLE: + if not cpu.supports_floats: + continue + if TP == rffi.FLOAT: + if not cpu.supports_singlefloats: + continue + # + result = rffi.cast(TP, result) + # + def pseudo_c_function(): + return result + # + FPTR = self.Ptr(self.FuncType([], TP)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests([], ffitype) + faildescr = BasicFailDescr(1) + kind = types.getkind(ffitype) + if kind in 'uis': + b3 = BoxInt() + elif kind in 'fUI': + b3 = BoxFloat() + else: + assert 0, kind + # + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox], b3, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [b3], None, descr=BasicFinalDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = JitCellToken() + self.cpu.compile_loop([], ops, looptoken) + + deadframe = self.cpu.execute_token(looptoken) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + if isinstance(b3, BoxInt): + r = self.cpu.get_int_value(deadframe, 0) + if isinstance(result, r_singlefloat): + assert -sys.maxint-1 <= r <= 0xFFFFFFFF + r, = struct.unpack("f", struct.pack("I", r & 0xFFFFFFFF)) + result = float(result) + else: + r = rffi.cast(TP, r) + assert r == result + elif isinstance(b3, BoxFloat): + r = self.cpu.get_float_value(deadframe, 0) + if isinstance(result, float): + r = longlong.getrealfloat(r) + else: + r = rffi.cast(TP, r) + assert r == result + + def test_call_release_gil_variable_function_and_arguments(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + + cpu = self.cpu + rnd = random.Random(525) + + ALL_TYPES = [ + (types.ulong, lltype.Unsigned), + (types.slong, lltype.Signed), + (types.uint8, rffi.UCHAR), + (types.sint8, rffi.SIGNEDCHAR), + (types.uint16, rffi.USHORT), + (types.sint16, rffi.SHORT), + (types.uint32, rffi.UINT), + (types.sint32, rffi.INT), + ] + if sys.maxint < 2**32 and cpu.supports_longlong: + ALL_TYPES += [ + (types.uint64, lltype.UnsignedLongLong), + (types.sint64, lltype.SignedLongLong), + ] * 2 + if cpu.supports_floats: + ALL_TYPES += [ + (types.double, rffi.DOUBLE), + ] * 4 + if cpu.supports_singlefloats: + ALL_TYPES += [ + (types.float, rffi.FLOAT), + ] * 4 + + for k in range(100): + POSSIBLE_TYPES = [rnd.choice(ALL_TYPES) + for i in range(random.randrange(2, 5))] + load_factor = rnd.random() + keepalive_factor = rnd.random() + # + def pseudo_c_function(*args): + seen.append(list(args)) + # + ffitypes = [] + ARGTYPES = [] + for i in range(rnd.randrange(4, 20)): + ffitype, TP = rnd.choice(POSSIBLE_TYPES) + ffitypes.append(ffitype) + ARGTYPES.append(TP) + # + FPTR = self.Ptr(self.FuncType(ARGTYPES, lltype.Void)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void) + faildescr = BasicFailDescr(1) + # + argboxes = [BoxInt()] # for the function to call + codes = ['X'] + for ffitype in ffitypes: + kind = types.getkind(ffitype) + codes.append(kind) + if kind in 'uis': + b1 = BoxInt() + elif kind in 'fUI': + b1 = BoxFloat() + else: + assert 0, kind + argboxes.append(b1) + codes = ''.join(codes) # useful for pdb + print + print codes + # + argvalues = [funcbox.getint()] + for TP in ARGTYPES: + r = (rnd.random() - 0.5) * 999999999999.9 + r = rffi.cast(TP, r) + argvalues.append(r) + # + argvalues_normal = argvalues[:1] + for ffitype, r in zip(ffitypes, argvalues[1:]): + kind = types.getkind(ffitype) + if kind in 'ui': + r = rffi.cast(lltype.Signed, r) + elif kind in 's': + r, = struct.unpack("i", struct.pack("f", float(r))) + elif kind in 'f': + r = longlong.getfloatstorage(r) + elif kind in 'UI': # 32-bit only + r = rffi.cast(lltype.SignedLongLong, r) + else: + assert 0 + argvalues_normal.append(r) + # + ops = [] + loadcodes = [] + insideboxes = [] + for b1 in argboxes: + load = rnd.random() < load_factor + loadcodes.append(' ^'[load]) + if load: + b2 = b1.clonebox() + ops.insert(rnd.randrange(0, len(ops)+1), + ResOperation(rop.SAME_AS, [b1], b2)) + b1 = b2 + insideboxes.append(b1) + loadcodes = ''.join(loadcodes) + print loadcodes + ops += [ + ResOperation(rop.CALL_RELEASE_GIL, insideboxes, None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0)) + ] + ops[-2].setfailargs([]) + # keep alive a random subset of the insideboxes + for b1 in insideboxes: + if rnd.random() < keepalive_factor: + ops.insert(-1, ResOperation(rop.SAME_AS, [b1], + b1.clonebox())) + looptoken = JitCellToken() + self.cpu.compile_loop(argboxes, ops, looptoken) + # + seen = [] + deadframe = self.cpu.execute_token(looptoken, *argvalues_normal) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + expected = argvalues[1:] + [got] = seen + different_values = ['%r != %r' % (a, b) + for a, b in zip(got, expected) + if a != b] + assert got == expected, ', '.join(different_values) + + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py --- a/rpython/jit/backend/x86/arch.py +++ b/rpython/jit/backend/x86/arch.py @@ -40,4 +40,4 @@ PASS_ON_MY_FRAME = 12 JITFRAME_FIXED_SIZE = 28 # 13 GPR + 15 XMM -assert PASS_ON_MY_FRAME >= 11 # asmgcc needs at least JIT_USE_WORDS + 2 +assert PASS_ON_MY_FRAME >= 12 # asmgcc needs at least JIT_USE_WORDS + 3 diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -6,7 +6,7 @@ DEBUG_COUNTER, debug_bridge) from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.llsupport.gcmap import allocate_gcmap -from rpython.jit.metainterp.history import Const, Box +from rpython.jit.metainterp.history import Const, Box, VOID from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory from rpython.rtyper.lltypesystem.lloperation import llop @@ -25,28 +25,17 @@ RegLoc, FrameLoc, ConstFloatLoc, ImmedLoc, AddressLoc, imm, imm0, imm1, FloatImmedLoc, RawEbpLoc, RawEspLoc) from rpython.rlib.objectmodel import we_are_translated -from rpython.jit.backend.x86 import rx86, codebuf +from rpython.jit.backend.x86 import rx86, codebuf, callbuilder from rpython.jit.metainterp.resoperation import rop from rpython.jit.backend.x86 import support from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib import rgc -from rpython.rlib.clibffi import FFI_DEFAULT_ABI -from rpython.jit.backend.x86.jump import remap_frame_layout from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter import longlong from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib.objectmodel import compute_unique_id -# darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0, -# better safe than sorry -CALL_ALIGN = 16 // WORD - - -def align_stack_words(words): - return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - - class Assembler386(BaseAssembler): _regalloc = None _output_loop_log = None @@ -131,10 +120,10 @@ mc.MOV_rs(esi.value, WORD*2) # push first arg mc.MOV_rr(edi.value, ebp.value) - align = align_stack_words(1) + align = callbuilder.align_stack_words(1) mc.SUB_ri(esp.value, (align - 1) * WORD) else: - align = align_stack_words(3) + align = callbuilder.align_stack_words(3) mc.MOV_rs(eax.value, WORD * 2) mc.SUB_ri(esp.value, (align - 1) * WORD) mc.MOV_sr(WORD, eax.value) @@ -1014,175 +1003,24 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def _emit_call(self, x, arglocs, start=0, tmp=eax, - argtypes=None, callconv=FFI_DEFAULT_ABI, - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True, - # max number of arguments we can pass on esp; if more, - # we need to decrease esp temporarily - stack_max=PASS_ON_MY_FRAME): - # - if IS_X86_64: - return self._emit_call_64(x, arglocs, start, argtypes, - can_collect, stack_max) - stack_depth = 0 - n = len(arglocs) - for i in range(start, n): - loc = arglocs[i] - stack_depth += loc.get_width() // WORD - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - self.mc.SUB_ri(esp.value, align * WORD) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) + def simple_call(self, fnloc, arglocs, result_loc=eax): + if result_loc is xmm0: + result_type = FLOAT + result_size = 8 + elif result_loc is None: + result_type = VOID + result_size = 0 else: - align = 0 - p = 0 - for i in range(start, n): - loc = arglocs[i] - if isinstance(loc, RegLoc): - if loc.is_xmm: - self.mc.MOVSD_sx(p, loc.value) - else: - self.mc.MOV_sr(p, loc.value) - p += loc.get_width() - p = 0 - for i in range(start, n): - loc = arglocs[i] - if not isinstance(loc, RegLoc): - if loc.get_width() == 8: - self.mc.MOVSD(xmm0, loc) - self.mc.MOVSD_sx(p, xmm0.value) - else: - self.mc.MOV(tmp, loc) - self.mc.MOV_sr(p, tmp.value) - p += loc.get_width() - # x is a location - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if callconv != FFI_DEFAULT_ABI: - self._fix_stdcall(callconv, p - align * WORD) - elif align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + result_type = INT + result_size = WORD + cb = callbuilder.CallBuilder(self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() - def _fix_stdcall(self, callconv, p): - from rpython.rlib.clibffi import FFI_STDCALL - assert callconv == FFI_STDCALL - # it's a bit stupid, but we're just going to cancel the fact that - # the called function just added 'p' to ESP, by subtracting it again. - self.mc.SUB_ri(esp.value, p) - - def _emit_call_64(self, x, arglocs, start, argtypes, - can_collect, stack_max): - src_locs = [] - dst_locs = [] - xmm_src_locs = [] - xmm_dst_locs = [] - singlefloats = None - - # In reverse order for use with pop() - unused_gpr = [r9, r8, ecx, edx, esi, edi] - unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0] - - on_stack = 0 - # count the stack depth - floats = 0 - for i in range(start, len(arglocs)): - arg = arglocs[i] - if arg.is_float() or argtypes and argtypes[i - start] == 'S': - floats += 1 - all_args = len(arglocs) - start - stack_depth = (max(all_args - floats - len(unused_gpr), 0) + - max(floats - len(unused_xmm), 0)) - align = 0 - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) - self.mc.SUB_ri(esp.value, align * WORD) - for i in range(start, len(arglocs)): - loc = arglocs[i] - if loc.is_float(): - xmm_src_locs.append(loc) - if len(unused_xmm) > 0: - xmm_dst_locs.append(unused_xmm.pop()) - else: - xmm_dst_locs.append(RawEspLoc(on_stack * WORD, FLOAT)) - on_stack += 1 - elif argtypes is not None and argtypes[i-start] == 'S': - # Singlefloat argument - if singlefloats is None: - singlefloats = [] - if len(unused_xmm) > 0: - singlefloats.append((loc, unused_xmm.pop())) - else: - singlefloats.append((loc, RawEspLoc(on_stack * WORD, INT))) - on_stack += 1 - else: - src_locs.append(loc) - if len(unused_gpr) > 0: - dst_locs.append(unused_gpr.pop()) - else: - dst_locs.append(RawEspLoc(on_stack * WORD, INT)) - on_stack += 1 - - # Handle register arguments: first remap the xmm arguments - remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, - X86_64_XMM_SCRATCH_REG) - # Load the singlefloat arguments from main regs or stack to xmm regs - if singlefloats is not None: - for src, dst in singlefloats: - if isinstance(dst, RawEspLoc): - # XXX too much special logic - if isinstance(src, RawEbpLoc): - self.mc.MOV32(X86_64_SCRATCH_REG, src) - self.mc.MOV32(dst, X86_64_SCRATCH_REG) - else: - self.mc.MOV32(dst, src) - continue - if isinstance(src, ImmedLoc): - self.mc.MOV(X86_64_SCRATCH_REG, src) - src = X86_64_SCRATCH_REG - self.mc.MOVD(dst, src) - # Finally remap the arguments in the main regs - # If x is a register and is in dst_locs, then oups, it needs to - # be moved away: - if x in dst_locs: - src_locs.append(x) - dst_locs.append(r10) - x = r10 - remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.CallBuilder(self, fnloc, arglocs) + cb.emit_no_collect() def _reload_frame_if_necessary(self, mc, align_stack=False): gcrootmap = self.cpu.gc_ll_descr.gcrootmap @@ -1198,10 +1036,6 @@ self._write_barrier_fastpath(mc, wbdescr, [ebp], array=False, is_frame=True, align_stack=align_stack) - def call(self, addr, args, res): - self._emit_call(imm(addr), args) - assert res is eax - genop_int_neg = _unaryop("NEG") genop_int_invert = _unaryop("NOT") genop_int_add = _binaryop_or_lea("ADD", True) @@ -1446,7 +1280,7 @@ # ---------- def genop_call_malloc_gc(self, op, arglocs, result_loc): - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self.propagate_memoryerror_if_eax_is_null() def propagate_memoryerror_if_eax_is_null(self): @@ -1993,75 +1827,29 @@ self.pending_guard_tokens.append(guard_token) def genop_call(self, op, arglocs, resloc): - return self._genop_call(op, arglocs, resloc) + self._genop_call(op, arglocs, resloc) def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False): from rpython.jit.backend.llsupport.descr import CallDescr - sizeloc = arglocs[0] - assert isinstance(sizeloc, ImmedLoc) - size = sizeloc.value - signloc = arglocs[1] - - x = arglocs[2] # the function address - if x is eax: - tmp = ecx - else: - tmp = eax + cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:], resloc) descr = op.getdescr() assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[0] + assert isinstance(sizeloc, ImmedLoc) + cb.ressize = sizeloc.value + signloc = arglocs[1] + assert isinstance(signloc, ImmedLoc) + cb.ressign = signloc.value - stack_max = PASS_ON_MY_FRAME if is_call_release_gil: - if self._is_asmgcc(): - from rpython.memory.gctransform import asmgcroot - stack_max -= asmgcroot.JIT_USE_WORDS - can_collect = False + cb.emit_call_release_gil() else: - can_collect = True - - self._emit_call(x, arglocs, 3, tmp=tmp, - argtypes=descr.get_arg_types(), - callconv=descr.get_call_conv(), - can_collect=can_collect, - stack_max=stack_max) - - if IS_X86_32 and isinstance(resloc, FrameLoc) and resloc.type == FLOAT: - # a float or a long long return - if descr.get_result_type() == 'L': - self.mc.MOV_br(resloc.value, eax.value) # long long - self.mc.MOV_br(resloc.value + 4, edx.value) - # XXX should ideally not move the result on the stack, - # but it's a mess to load eax/edx into a xmm register - # and this way is simpler also because the result loc - # can just be always a stack location - else: - self.mc.FSTPL_b(resloc.value) # float return - elif descr.get_result_type() == 'S': - # singlefloat return - assert resloc is eax - if IS_X86_32: - # must convert ST(0) to a 32-bit singlefloat and load it into EAX - # mess mess mess - self.mc.SUB_ri(esp.value, 4) - self.mc.FSTPS_s(0) - self.mc.POP_r(eax.value) - elif IS_X86_64: - # must copy from the lower 32 bits of XMM0 into eax - self.mc.MOVD_rx(eax.value, xmm0.value) - elif size == WORD: - assert resloc is eax or resloc is xmm0 # a full word - elif size == 0: - pass # void return - else: - # use the code in load_from_mem to do the zero- or sign-extension - assert resloc is eax - if size == 1: - srcloc = eax.lowest8bits() - else: - srcloc = eax - self.load_from_mem(eax, srcloc, sizeloc, signloc) + cb.emit() def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() @@ -2077,64 +1865,15 @@ def genop_guard_call_may_force(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self._emit_guard_not_forced(guard_token) def genop_guard_call_release_gil(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs) - # do the call self._genop_call(op, arglocs, result_loc, is_call_release_gil=True) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, result_loc) - self.pop_gcmap(self.mc) # remove the gcmap saved above - # finally, the guard_not_forced self._emit_guard_not_forced(guard_token) - def call_release_gil(self, gcrootmap, save_registers): - if gcrootmap.is_shadow_stack: - args = [] - else: - from rpython.memory.gctransform import asmgcroot - # build a 'css' structure on the stack: 2 words for the linkage, - # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a - # total size of JIT_USE_WORDS. This structure is found at - # [ESP+css]. - css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) - assert css >= 2 - # Save ebp - index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) - self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP - # Save the "return address": we pretend that it's css - if IS_X86_32: - reg = eax - elif IS_X86_64: - reg = edi - self.mc.LEA_rs(reg.value, css) # LEA reg, [css] - frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) - self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg - # Set up jf_extra_stack_depth to pretend that the return address - # was at css, and so our stack frame is supposedly shorter by - # (css+WORD) bytes - self.set_extra_stack_depth(self.mc, -css-WORD) - # Call the closestack() function (also releasing the GIL) - args = [reg] - # - self._emit_call(imm(self.releasegil_addr), args, can_collect=False) - def call_reacquire_gil(self, gcrootmap, save_loc): # save the previous result (eax/xmm0) into the stack temporarily. # XXX like with call_release_gil(), we assume that we don't need @@ -2186,11 +1925,11 @@ self.call_assembler(op, guard_op, argloc, vloc, result_loc, eax) self._emit_guard_not_forced(guard_token) - def _call_assembler_emit_call(self, addr, argloc, tmploc): - self._emit_call(addr, [argloc], 0, tmp=tmploc) + def _call_assembler_emit_call(self, addr, argloc, _): + self.simple_call(addr, [argloc]) - def _call_assembler_emit_helper_call(self, addr, arglocs, _): - self._emit_call(addr, arglocs, 0, tmp=self._second_tmp_reg) + def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc): + self.simple_call(addr, arglocs, result_loc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/x86/callbuilder.py @@ -0,0 +1,577 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32, + PASS_ON_MY_FRAME) +from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, + r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, + RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) +from rpython.jit.backend.x86.jump import remap_frame_layout + + +# darwin requires the stack to be 16 bytes aligned on calls. +# Same for gcc 4.5.0, better safe than sorry +CALL_ALIGN = 16 // WORD + +def align_stack_words(words): + return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) + + + +class AbstractCallBuilder(object): + + # max number of words we have room in esp; if we need more for + # arguments, we need to decrease esp temporarily + stack_max = PASS_ON_MY_FRAME + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # set by save_result_value() + tmpresloc = None + + + def __init__(self, assembler, fnloc, arglocs, + resloc=eax, restype=INT, ressize=WORD): + # Avoid tons of issues with a non-immediate fnloc by sticking it + # as an extra argument if needed + self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) + if self.fnloc_is_immediate: + self.fnloc = fnloc + self.arglocs = arglocs + else: + self.arglocs = arglocs + [fnloc] + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + self.current_esp = 0 # 0 or (usually) negative, counted in bytes + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_esp() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_esp() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_esp() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + if self.asm._is_asmgcc(): + from rpython.memory.gctransform import asmgcroot + self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + assert self.stack_max >= 3 + + def emit_raw_call(self): + self.mc.CALL(self.fnloc) + if self.callconv != FFI_DEFAULT_ABI: + self.current_esp += self._fix_stdcall(self.callconv) + + def subtract_esp_aligned(self, count): + if count > 0: + align = align_stack_words(count) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) + + def restore_esp(self, target_esp=0): + if self.current_esp != target_esp: + self.mc.ADD_ri(esp.value, target_esp - self.current_esp) + self.current_esp = target_esp + + def load_result(self): + """Overridden in CallBuilder32 and CallBuilder64""" + if self.ressize == 0: + return # void result + # use the code in load_from_mem to do the zero- or sign-extension + srcloc = self.tmpresloc + if srcloc is None: + if self.restype == FLOAT: + srcloc = xmm0 + else: + srcloc = eax + if self.ressize >= WORD and self.resloc is srcloc: + return # no need for any MOV + if self.ressize == 1 and isinstance(srcloc, RegLoc): + srcloc = srcloc.lowest8bits() + self.asm.load_from_mem(self.resloc, srcloc, + imm(self.ressize), imm(self.ressign)) + + def push_gcmap(self): + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just before, ignoring the return + # value eax, if necessary + assert not self.is_call_release_gil + self.change_extra_stack_depth = (self.current_esp != 0) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, -self.current_esp) + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, 0) + self.asm.pop_gcmap(self.mc) + + def call_releasegil_addr_and_move_real_arguments(self): + initial_esp = self.current_esp + self.save_register_arguments() + # + if not self.asm._is_asmgcc(): + # the helper takes no argument + self.change_extra_stack_depth = False + else: + from rpython.memory.gctransform import asmgcroot + # build a 'css' structure on the stack: 2 words for the linkage, + # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a + # total size of JIT_USE_WORDS. This structure is found at + # [ESP+css]. + css = -self.current_esp + ( + WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS)) + assert css >= 2 * WORD + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Save the "return address": we pretend that it's css + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) # LEA reg, [css] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg + # Set up jf_extra_stack_depth to pretend that the return address + # was at css, and so our stack frame is supposedly shorter by + # (PASS_ON_MY_FRAME-JIT_USE_WORDS+1) words + delta = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + 1 + self.change_extra_stack_depth = True + self.asm.set_extra_stack_depth(self.mc, -delta * WORD) + # Call the closestack() function (also releasing the GIL) + # with 'reg' as argument + if IS_X86_32: + self.subtract_esp_aligned(1) + self.mc.MOV_sr(0, reg.value) + #else: + # on x86_64, reg is edi so that it is already correct + # + self.mc.CALL(imm(self.asm.releasegil_addr)) + # + if not we_are_translated(): # for testing: we should not access + self.mc.ADD(ebp, imm(1)) # ebp any more + # + self.restore_register_arguments() + self.restore_esp(initial_esp) + + def save_register_arguments(self): + """Overridden in CallBuilder64""" + + def restore_register_arguments(self): + """Overridden in CallBuilder64""" + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got (in eax/eax+edx/st(0)/xmm0) + self.save_result_value() + # call the reopenstack() function (also reacquiring the GIL) + if not self.asm._is_asmgcc(): + css = 0 # the helper takes no argument + else: + from rpython.memory.gctransform import asmgcroot + css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) + if IS_X86_32: + self.mc.MOV_sr(0, reg.value) + # + self.mc.CALL(imm(self.asm.reacqgil_addr)) + # + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB(ebp, imm(1)) # ebp again + # + # Now that we required the GIL, we can reload a possibly modified ebp + if self.asm._is_asmgcc(): + # special-case: reload ebp from the css + from rpython.memory.gctransform import asmgcroot + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_rs(ebp.value, index_of_ebp) # MOV EBP, [css.ebp] + #else: + # for shadowstack, done for us by _reload_frame_if_necessary() + + def save_result_value(self): + """Overridden in CallBuilder32 and CallBuilder64""" + raise NotImplementedError + + +class CallBuilder32(AbstractCallBuilder): + + def prepare_arguments(self): + arglocs = self.arglocs + stack_depth = 0 + n = len(arglocs) + for i in range(n): + loc = arglocs[i] + stack_depth += loc.get_width() // WORD + self.subtract_esp_aligned(stack_depth - self.stack_max) + # + p = 0 + for i in range(n): + loc = arglocs[i] + if isinstance(loc, RegLoc): + if loc.is_xmm: + self.mc.MOVSD_sx(p, loc.value) + else: + self.mc.MOV_sr(p, loc.value) + p += loc.get_width() + p = 0 + for i in range(n): + loc = arglocs[i] + if not isinstance(loc, RegLoc): + if loc.get_width() == 8: + self.mc.MOVSD(xmm0, loc) + self.mc.MOVSD_sx(p, xmm0.value) + elif isinstance(loc, ImmedLoc): + self.mc.MOV_si(p, loc.value) + else: + self.mc.MOV(eax, loc) + self.mc.MOV_sr(p, eax.value) + p += loc.get_width() + self.total_stack_used_by_arguments = p + # + if not self.fnloc_is_immediate: # the last "argument" pushed above + self.fnloc = RawEspLoc(p - WORD, INT) + + + def _fix_stdcall(self, callconv): + from rpython.rlib.clibffi import FFI_STDCALL + assert callconv == FFI_STDCALL + return self.total_stack_used_by_arguments + + def load_result(self): + resloc = self.resloc + if resloc is not None and resloc.is_float(): + # a float or a long long return + if self.tmpresloc is None: + if self.restype == 'L': # long long + # move eax/edx -> xmm0 + self.mc.MOVD_xr(resloc.value^1, edx.value) + self.mc.MOVD_xr(resloc.value, eax.value) + self.mc.PUNPCKLDQ_xx(resloc.value, resloc.value^1) + else: + # float: we have to go via the stack + self.mc.FSTPL_s(0) + self.mc.MOVSD_xs(resloc.value, 0) + else: + self.mc.MOVSD(resloc, self.tmpresloc) + # + elif self.restype == 'S': + # singlefloat return: must convert ST(0) to a 32-bit singlefloat + # and load it into self.resloc. mess mess mess + if self.tmpresloc is None: + self.mc.FSTPS_s(0) + self.mc.MOV_rs(resloc.value, 0) + else: + self.mc.MOV(resloc, self.tmpresloc) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP+4]. We use "+4" + # in order to leave the word at [ESP+0] free, in case it's needed + if self.ressize == 0: # void return + return + if self.resloc.is_float(): + # a float or a long long return + self.tmpresloc = RawEspLoc(4, FLOAT) + if self.restype == 'L': + self.mc.MOV_sr(4, eax.value) # long long + self.mc.MOV_sr(8, edx.value) + else: + self.mc.FSTPL_s(4) # float return + else: + self.tmpresloc = RawEspLoc(4, INT) + if self.restype == 'S': + self.mc.FSTPS_s(4) + else: + assert self.restype == INT + assert self.ressize <= WORD + self.mc.MOV_sr(4, eax.value) + + +class CallBuilder64(AbstractCallBuilder): + + ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] + ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + DONT_MOVE_GPR = [] + _ALL_CALLEE_SAVE_GPR = [ebx, r12, r13, r14, r15] + + next_arg_gpr = 0 + next_arg_xmm = 0 + + def _unused_gpr(self, hint): + i = self.next_arg_gpr + self.next_arg_gpr = i + 1 + try: + res = self.ARGUMENTS_GPR[i] + except IndexError: + return None + if hint in self.DONT_MOVE_GPR: + self.ARGUMENTS_GPR[i] = hint + res = hint + return res + + def _unused_xmm(self): + i = self.next_arg_xmm + self.next_arg_xmm = i + 1 + try: + return self.ARGUMENTS_XMM[i] + except IndexError: + return None + + def _permute_to_prefer_unused_registers(self, lst): + # permute 'lst' so that it starts with registers that are not + # in 'self.already_used', and ends with registers that are. + N = len(lst) + i = 0 + while i < N: + reg = lst[i] + if reg in self.already_used: + # move this reg to the end, and decrement N + N -= 1 + assert N >= i + lst[N], lst[i] = lst[i], lst[N] + else: + i += 1 + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + # We have to copy the arguments around a bit more in this mode, + # but on the other hand we don't need prepare_arguments() moving + # them in precisely the final registers. Here we look around for + # unused registers that may be more likely usable. + from rpython.jit.backend.x86.regalloc import X86_64_RegisterManager + from rpython.jit.backend.x86.regalloc import X86_64_XMMRegisterManager + self.already_used = {} + for loc in self.arglocs: + self.already_used[loc] = None + # + lst = X86_64_RegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + # + extra = [] + for reg in self.asm._regalloc.rm.free_regs: + if (reg not in self.already_used and + reg in self._ALL_CALLEE_SAVE_GPR): + extra.append(reg) + self.free_callee_save_gprs = extra + lst = extra + lst + # + self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] + self.DONT_MOVE_GPR = self._ALL_CALLEE_SAVE_GPR + # + lst = X86_64_XMMRegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + self.ARGUMENTS_XMM = lst[:len(self.ARGUMENTS_XMM)] + + def prepare_arguments(self): + src_locs = [] + dst_locs = [] + xmm_src_locs = [] + xmm_dst_locs = [] + singlefloats = None + + arglocs = self.arglocs + argtypes = self.argtypes + + on_stack = 0 + for i in range(len(arglocs)): + loc = arglocs[i] + if loc.is_float(): + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, FLOAT) + on_stack += 1 + xmm_src_locs.append(loc) + xmm_dst_locs.append(tgt) + elif i < len(argtypes) and argtypes[i] == 'S': + # Singlefloat argument + if singlefloats is None: + singlefloats = [] + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + singlefloats.append((loc, tgt)) + else: + tgt = self._unused_gpr(hint=loc) + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + src_locs.append(loc) + dst_locs.append(tgt) + + if not self.fnloc_is_immediate: + self.fnloc = dst_locs[-1] # the last "argument" prepared above + + if not we_are_translated(): # assert that we got the right stack depth + floats = 0 + for i in range(len(arglocs)): + arg = arglocs[i] + if arg.is_float() or (i < len(argtypes) and argtypes[i]=='S'): + floats += 1 + all_args = len(arglocs) + stack_depth = (max(all_args - floats - len(self.ARGUMENTS_GPR), 0) + + max(floats - len(self.ARGUMENTS_XMM), 0)) + assert stack_depth == on_stack + + self.subtract_esp_aligned(on_stack - self.stack_max) + + # Handle register arguments: first remap the xmm arguments + remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, + X86_64_XMM_SCRATCH_REG) + # Load the singlefloat arguments from main regs or stack to xmm regs + if singlefloats is not None: + for src, dst in singlefloats: + if isinstance(dst, RawEspLoc): + # XXX too much special logic + if isinstance(src, RawEbpLoc): + self.mc.MOV32(X86_64_SCRATCH_REG, src) + self.mc.MOV32(dst, X86_64_SCRATCH_REG) + else: + self.mc.MOV32(dst, src) + continue + if isinstance(src, ImmedLoc): + self.mc.MOV(X86_64_SCRATCH_REG, src) + src = X86_64_SCRATCH_REG + self.mc.MOVD(dst, src) + # Finally remap the arguments in the main regs + remap_frame_layout(self.asm, src_locs, dst_locs, X86_64_SCRATCH_REG) + + + def _fix_stdcall(self, callconv): + assert 0 # should not occur on 64-bit + + def load_result(self): + if self.restype == 'S' and self.tmpresloc is None: + # singlefloat return: use MOVD to load the target register + # from the lower 32 bits of XMM0 + self.mc.MOVD(self.resloc, xmm0) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP]. + if self.ressize == 0: # void return + return + # + if self.restype == FLOAT: # and not 'S' + self.mc.MOVSD_sx(0, xmm0.value) + self.tmpresloc = RawEspLoc(0, FLOAT) + return + # + if len(self.free_callee_save_gprs) == 0: + self.tmpresloc = RawEspLoc(0, INT) + else: + self.tmpresloc = self.free_callee_save_gprs[0] + # + if self.restype == 'S': + # singlefloat return: use MOVD to store the lower 32 bits + # of XMM0 into the tmpresloc (register or [ESP]) + self.mc.MOVD(self.tmpresloc, xmm0) + else: + assert self.restype == INT + self.mc.MOV(self.tmpresloc, eax) + + def save_register_arguments(self): + # Save the argument registers, which are given by self.ARGUMENTS_xxx. + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + n_saved_regs = n_gpr + n_xmm + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] in self._ALL_CALLEE_SAVE_GPR: + n_saved_regs -= 1 # don't need to save it + self.subtract_esp_aligned(n_saved_regs) + # + n = 0 + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_sr(n * WORD, self.ARGUMENTS_GPR[i].value) + n += 1 + for i in range(n_xmm): + self.mc.MOVSD_sx(n * WORD, self.ARGUMENTS_XMM[i].value) + n += 1 + assert n == n_saved_regs + self.n_saved_regs = n_saved_regs + + def restore_register_arguments(self): + # Restore the saved values into the *real* registers used for calls + # --- which are not self.ARGUMENTS_xxx! + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + # + n = 0 + for i in range(n_gpr): + tgtvalue = CallBuilder64.ARGUMENTS_GPR[i].value + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_rs(tgtvalue, n * WORD) + n += 1 + else: + self.mc.MOV_rr(tgtvalue, self.ARGUMENTS_GPR[i].value) + for i in range(n_xmm): + self.mc.MOVSD_xs(CallBuilder64.ARGUMENTS_XMM[i].value, n * WORD) + n += 1 + assert n == self.n_saved_regs + # + if isinstance(self.fnloc, RegLoc): # fix this register + self.fnloc = CallBuilder64.ARGUMENTS_GPR[n_gpr - 1] + + +if IS_X86_32: + CallBuilder = CallBuilder32 +if IS_X86_64: + CallBuilder = CallBuilder64 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -79,26 +79,14 @@ rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), adr)[1] = y return ConstFloatLoc(adr) - def after_call(self, v): - # the result is stored in st0, but we don't have this around, - # so genop_call will move it to some frame location immediately - # after the call - return self.frame_manager.loc(v) + def call_result_location(self, v): + return xmm0 class X86_64_XMMRegisterManager(X86XMMRegisterManager): # xmm15 reserved for scratch use all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14] save_around_call_regs = all_regs - def call_result_location(self, v): - return xmm0 - - def after_call(self, v): - # We use RegisterManager's implementation, since X86XMMRegisterManager - # places the result on the stack, which we don't need to do when the - # calling convention places the result in xmm0 - return RegisterManager.after_call(self, v) - class X86FrameManager(FrameManager): def __init__(self, base_ofs): FrameManager.__init__(self) @@ -799,14 +787,6 @@ self._consider_call(op, guard_op) def consider_call_release_gil(self, op, guard_op): - # We spill the arguments to the stack, because we need to do 3 calls: - # call_release_gil(), the_real_c_function(), and call_reacquire_gil(). - # The arguments are used on the second call only. XXX we assume - # that the XMM arguments won't be modified by call_release_gil(). - for i in range(op.numargs()): - loc = self.loc(op.getarg(i)) - if loc in self.rm.save_around_call_regs: - self.rm.force_spill_var(op.getarg(i)) assert guard_op is not None self._consider_call(op, guard_op) @@ -1151,9 +1131,8 @@ # call memcpy() self.rm.before_call() self.xrm.before_call() - self.assembler._emit_call(imm(self.assembler.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.assembler.simple_call_no_collect(imm(self.assembler.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) self.rm.possibly_free_var(length_box) self.rm.possibly_free_var(dstaddr_box) self.rm.possibly_free_var(srcaddr_box) diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -553,6 +553,7 @@ CALL_l = insn('\xE8', relative(1)) CALL_r = insn(rex_nw, '\xFF', register(1), chr(0xC0 | (2<<3))) CALL_b = insn('\xFF', orbyte(2<<3), stack_bp(1)) + CALL_s = insn('\xFF', orbyte(2<<3), stack_sp(1)) # XXX: Only here for testing purposes..."as" happens the encode the # registers in the opposite order that we would otherwise do in a @@ -583,6 +584,7 @@ # x87 instructions FSTPL_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) # rffi.DOUBLE ('as' wants L??) + FSTPL_s = insn('\xDD', orbyte(3<<3), stack_sp(1)) # rffi.DOUBLE ('as' wants L??) FSTPS_s = insn('\xD9', orbyte(3<<3), stack_sp(1)) # lltype.SingleFloat # ------------------------------ Random mess ----------------------- From noreply at buildbot.pypy.org Mon May 20 13:38:03 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 13:38:03 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Manual merge of emit-call-x86: fix for multithreaded programs, particularly Message-ID: <20130520113803.A47131C0217@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64365:f7e4f43c9487 Date: 2013-05-20 13:30 +0200 http://bitbucket.org/pypy/pypy/changeset/f7e4f43c9487/ Log: Manual merge of emit-call-x86: fix for multithreaded programs, particularly those that run more threads than cores. The issue was that a call_release_gil instruction compiles to code that still accesses ebp/rsp after it released the GIL. diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 diff --git a/rpython/jit/backend/llgraph/test/test_llgraph.py b/rpython/jit/backend/llgraph/test/test_llgraph.py --- a/rpython/jit/backend/llgraph/test/test_llgraph.py +++ b/rpython/jit/backend/llgraph/test/test_llgraph.py @@ -15,6 +15,9 @@ def test_memoryerror(self): py.test.skip("does not make much sense on the llgraph backend") + def test_call_release_gil_variable_function_and_arguments(self): + py.test.skip("the arguments seem not correctly casted") + def test_cast_adr_to_int_and_back(): X = lltype.Struct('X', ('foo', lltype.Signed)) 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 @@ -108,8 +108,7 @@ self.malloc_slowpath_unicode = None self._build_stack_check_slowpath() - if gc_ll_descr.gcrootmap: - self._build_release_gil(gc_ll_descr.gcrootmap) + self._build_release_gil(gc_ll_descr.gcrootmap) if not self._debug: # if self._debug is already set it means that someone called # set_debug by hand before initializing the assembler. Leave it @@ -348,12 +347,19 @@ if after: after() + @staticmethod + def _no_op(): + pass + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], lltype.Void)) def _build_release_gil(self, gcrootmap): - if gcrootmap.is_shadow_stack: + if gcrootmap is None: + releasegil_func = llhelper(self._NOARG_FUNC, self._no_op) + reacqgil_func = llhelper(self._NOARG_FUNC, self._no_op) + elif gcrootmap.is_shadow_stack: releasegil_func = llhelper(self._NOARG_FUNC, self._release_gil_shadowstack) reacqgil_func = llhelper(self._NOARG_FUNC, diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2532,6 +2532,219 @@ assert rffi.charp2strn(buffer, buflen) == cwd lltype.free(buffer, flavor='raw') + def test_call_release_gil_return_types(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + cpu = self.cpu + + for ffitype, result, TP in [ + (types.ulong, r_uint(sys.maxint + 10), lltype.Unsigned), + (types.slong, -4321, lltype.Signed), + (types.uint8, 200, rffi.UCHAR), + (types.sint8, -42, rffi.SIGNEDCHAR), + (types.uint16, 50000, rffi.USHORT), + (types.sint16, -20000, rffi.SHORT), + (types.uint32, r_uint(3000000000), rffi.UINT), + (types.sint32, -2000000000, rffi.INT), + (types.uint64, r_ulonglong(9999999999999999999), + lltype.UnsignedLongLong), + (types.sint64, r_longlong(-999999999999999999), + lltype.SignedLongLong), + (types.double, 12.3475226, rffi.DOUBLE), + (types.float, r_singlefloat(-592.75), rffi.FLOAT), + ]: + if sys.maxint < 2**32 and TP in (lltype.SignedLongLong, + lltype.UnsignedLongLong): + if not cpu.supports_longlong: + continue + if TP == rffi.DOUBLE: + if not cpu.supports_floats: + continue + if TP == rffi.FLOAT: + if not cpu.supports_singlefloats: + continue + # + result = rffi.cast(TP, result) + # + def pseudo_c_function(): + return result + # + FPTR = self.Ptr(self.FuncType([], TP)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests([], ffitype) + faildescr = BasicFailDescr(1) + kind = types.getkind(ffitype) + if kind in 'uis': + b3 = BoxInt() + elif kind in 'fUI': + b3 = BoxFloat() + else: + assert 0, kind + # + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox], b3, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [b3], None, descr=BasicFinalDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = JitCellToken() + self.cpu.compile_loop([], ops, looptoken) + + deadframe = self.cpu.execute_token(looptoken) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + if isinstance(b3, BoxInt): + r = self.cpu.get_int_value(deadframe, 0) + if isinstance(result, r_singlefloat): + assert -sys.maxint-1 <= r <= 0xFFFFFFFF + r, = struct.unpack("f", struct.pack("I", r & 0xFFFFFFFF)) + result = float(result) + else: + r = rffi.cast(TP, r) + assert r == result + elif isinstance(b3, BoxFloat): + r = self.cpu.get_float_value(deadframe, 0) + if isinstance(result, float): + r = longlong.getrealfloat(r) + else: + r = rffi.cast(TP, r) + assert r == result + + def test_call_release_gil_variable_function_and_arguments(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + + cpu = self.cpu + rnd = random.Random(525) + + ALL_TYPES = [ + (types.ulong, lltype.Unsigned), + (types.slong, lltype.Signed), + (types.uint8, rffi.UCHAR), + (types.sint8, rffi.SIGNEDCHAR), + (types.uint16, rffi.USHORT), + (types.sint16, rffi.SHORT), + (types.uint32, rffi.UINT), + (types.sint32, rffi.INT), + ] + if sys.maxint < 2**32 and cpu.supports_longlong: + ALL_TYPES += [ + (types.uint64, lltype.UnsignedLongLong), + (types.sint64, lltype.SignedLongLong), + ] * 2 + if cpu.supports_floats: + ALL_TYPES += [ + (types.double, rffi.DOUBLE), + ] * 4 + if cpu.supports_singlefloats: + ALL_TYPES += [ + (types.float, rffi.FLOAT), + ] * 4 + + for k in range(100): + POSSIBLE_TYPES = [rnd.choice(ALL_TYPES) + for i in range(random.randrange(2, 5))] + load_factor = rnd.random() + keepalive_factor = rnd.random() + # + def pseudo_c_function(*args): + seen.append(list(args)) + # + ffitypes = [] + ARGTYPES = [] + for i in range(rnd.randrange(4, 20)): + ffitype, TP = rnd.choice(POSSIBLE_TYPES) + ffitypes.append(ffitype) + ARGTYPES.append(TP) + # + FPTR = self.Ptr(self.FuncType(ARGTYPES, lltype.Void)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void) + faildescr = BasicFailDescr(1) + # + argboxes = [BoxInt()] # for the function to call + codes = ['X'] + for ffitype in ffitypes: + kind = types.getkind(ffitype) + codes.append(kind) + if kind in 'uis': + b1 = BoxInt() + elif kind in 'fUI': + b1 = BoxFloat() + else: + assert 0, kind + argboxes.append(b1) + codes = ''.join(codes) # useful for pdb + print + print codes + # + argvalues = [funcbox.getint()] + for TP in ARGTYPES: + r = (rnd.random() - 0.5) * 999999999999.9 + r = rffi.cast(TP, r) + argvalues.append(r) + # + argvalues_normal = argvalues[:1] + for ffitype, r in zip(ffitypes, argvalues[1:]): + kind = types.getkind(ffitype) + if kind in 'ui': + r = rffi.cast(lltype.Signed, r) + elif kind in 's': + r, = struct.unpack("i", struct.pack("f", float(r))) + elif kind in 'f': + r = longlong.getfloatstorage(r) + elif kind in 'UI': # 32-bit only + r = rffi.cast(lltype.SignedLongLong, r) + else: + assert 0 + argvalues_normal.append(r) + # + ops = [] + loadcodes = [] + insideboxes = [] + for b1 in argboxes: + load = rnd.random() < load_factor + loadcodes.append(' ^'[load]) + if load: + b2 = b1.clonebox() + ops.insert(rnd.randrange(0, len(ops)+1), + ResOperation(rop.SAME_AS, [b1], b2)) + b1 = b2 + insideboxes.append(b1) + loadcodes = ''.join(loadcodes) + print loadcodes + ops += [ + ResOperation(rop.CALL_RELEASE_GIL, insideboxes, None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0)) + ] + ops[-2].setfailargs([]) + # keep alive a random subset of the insideboxes + for b1 in insideboxes: + if rnd.random() < keepalive_factor: + ops.insert(-1, ResOperation(rop.SAME_AS, [b1], + b1.clonebox())) + looptoken = JitCellToken() + self.cpu.compile_loop(argboxes, ops, looptoken) + # + seen = [] + deadframe = self.cpu.execute_token(looptoken, *argvalues_normal) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + expected = argvalues[1:] + [got] = seen + different_values = ['%r != %r' % (a, b) + for a, b in zip(got, expected) + if a != b] + assert got == expected, ', '.join(different_values) + + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py --- a/rpython/jit/backend/x86/arch.py +++ b/rpython/jit/backend/x86/arch.py @@ -40,4 +40,4 @@ PASS_ON_MY_FRAME = 12 JITFRAME_FIXED_SIZE = 28 # 13 GPR + 15 XMM -assert PASS_ON_MY_FRAME >= 11 # asmgcc needs at least JIT_USE_WORDS + 2 +assert PASS_ON_MY_FRAME >= 12 # asmgcc needs at least JIT_USE_WORDS + 3 diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -6,7 +6,7 @@ DEBUG_COUNTER, debug_bridge) from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.llsupport.gcmap import allocate_gcmap -from rpython.jit.metainterp.history import Const, Box +from rpython.jit.metainterp.history import Const, Box, VOID from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory from rpython.rtyper.lltypesystem.lloperation import llop @@ -25,28 +25,17 @@ RegLoc, FrameLoc, ConstFloatLoc, ImmedLoc, AddressLoc, imm, imm0, imm1, FloatImmedLoc, RawEbpLoc, RawEspLoc) from rpython.rlib.objectmodel import we_are_translated -from rpython.jit.backend.x86 import rx86, codebuf +from rpython.jit.backend.x86 import rx86, codebuf, callbuilder from rpython.jit.metainterp.resoperation import rop from rpython.jit.backend.x86 import support from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib import rgc -from rpython.rlib.clibffi import FFI_DEFAULT_ABI -from rpython.jit.backend.x86.jump import remap_frame_layout from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter import longlong from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib.objectmodel import compute_unique_id -# darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0, -# better safe than sorry -CALL_ALIGN = 16 // WORD - - -def align_stack_words(words): - return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - - class Assembler386(BaseAssembler): _regalloc = None _output_loop_log = None @@ -131,10 +120,10 @@ mc.MOV_rs(esi.value, WORD*2) # push first arg mc.MOV_rr(edi.value, ebp.value) - align = align_stack_words(1) + align = callbuilder.align_stack_words(1) mc.SUB_ri(esp.value, (align - 1) * WORD) else: - align = align_stack_words(3) + align = callbuilder.align_stack_words(3) mc.MOV_rs(eax.value, WORD * 2) mc.SUB_ri(esp.value, (align - 1) * WORD) mc.MOV_sr(WORD, eax.value) @@ -1014,175 +1003,24 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def _emit_call(self, x, arglocs, start=0, tmp=eax, - argtypes=None, callconv=FFI_DEFAULT_ABI, - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True, - # max number of arguments we can pass on esp; if more, - # we need to decrease esp temporarily - stack_max=PASS_ON_MY_FRAME): - # - if IS_X86_64: - return self._emit_call_64(x, arglocs, start, argtypes, - can_collect, stack_max) - stack_depth = 0 - n = len(arglocs) - for i in range(start, n): - loc = arglocs[i] - stack_depth += loc.get_width() // WORD - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - self.mc.SUB_ri(esp.value, align * WORD) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) + def simple_call(self, fnloc, arglocs, result_loc=eax): + if result_loc is xmm0: + result_type = FLOAT + result_size = 8 + elif result_loc is None: + result_type = VOID + result_size = 0 else: - align = 0 - p = 0 - for i in range(start, n): - loc = arglocs[i] - if isinstance(loc, RegLoc): - if loc.is_xmm: - self.mc.MOVSD_sx(p, loc.value) - else: - self.mc.MOV_sr(p, loc.value) - p += loc.get_width() - p = 0 - for i in range(start, n): - loc = arglocs[i] - if not isinstance(loc, RegLoc): - if loc.get_width() == 8: - self.mc.MOVSD(xmm0, loc) - self.mc.MOVSD_sx(p, xmm0.value) - else: - self.mc.MOV(tmp, loc) - self.mc.MOV_sr(p, tmp.value) - p += loc.get_width() - # x is a location - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if callconv != FFI_DEFAULT_ABI: - self._fix_stdcall(callconv, p - align * WORD) - elif align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + result_type = INT + result_size = WORD + cb = callbuilder.CallBuilder(self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() - def _fix_stdcall(self, callconv, p): - from rpython.rlib.clibffi import FFI_STDCALL - assert callconv == FFI_STDCALL - # it's a bit stupid, but we're just going to cancel the fact that - # the called function just added 'p' to ESP, by subtracting it again. - self.mc.SUB_ri(esp.value, p) - - def _emit_call_64(self, x, arglocs, start, argtypes, - can_collect, stack_max): - src_locs = [] - dst_locs = [] - xmm_src_locs = [] - xmm_dst_locs = [] - singlefloats = None - - # In reverse order for use with pop() - unused_gpr = [r9, r8, ecx, edx, esi, edi] - unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0] - - on_stack = 0 - # count the stack depth - floats = 0 - for i in range(start, len(arglocs)): - arg = arglocs[i] - if arg.is_float() or argtypes and argtypes[i - start] == 'S': - floats += 1 - all_args = len(arglocs) - start - stack_depth = (max(all_args - floats - len(unused_gpr), 0) + - max(floats - len(unused_xmm), 0)) - align = 0 - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) - self.mc.SUB_ri(esp.value, align * WORD) - for i in range(start, len(arglocs)): - loc = arglocs[i] - if loc.is_float(): - xmm_src_locs.append(loc) - if len(unused_xmm) > 0: - xmm_dst_locs.append(unused_xmm.pop()) - else: - xmm_dst_locs.append(RawEspLoc(on_stack * WORD, FLOAT)) - on_stack += 1 - elif argtypes is not None and argtypes[i-start] == 'S': - # Singlefloat argument - if singlefloats is None: - singlefloats = [] - if len(unused_xmm) > 0: - singlefloats.append((loc, unused_xmm.pop())) - else: - singlefloats.append((loc, RawEspLoc(on_stack * WORD, INT))) - on_stack += 1 - else: - src_locs.append(loc) - if len(unused_gpr) > 0: - dst_locs.append(unused_gpr.pop()) - else: - dst_locs.append(RawEspLoc(on_stack * WORD, INT)) - on_stack += 1 - - # Handle register arguments: first remap the xmm arguments - remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, - X86_64_XMM_SCRATCH_REG) - # Load the singlefloat arguments from main regs or stack to xmm regs - if singlefloats is not None: - for src, dst in singlefloats: - if isinstance(dst, RawEspLoc): - # XXX too much special logic - if isinstance(src, RawEbpLoc): - self.mc.MOV32(X86_64_SCRATCH_REG, src) - self.mc.MOV32(dst, X86_64_SCRATCH_REG) - else: - self.mc.MOV32(dst, src) - continue - if isinstance(src, ImmedLoc): - self.mc.MOV(X86_64_SCRATCH_REG, src) - src = X86_64_SCRATCH_REG - self.mc.MOVD(dst, src) - # Finally remap the arguments in the main regs - # If x is a register and is in dst_locs, then oups, it needs to - # be moved away: - if x in dst_locs: - src_locs.append(x) - dst_locs.append(r10) - x = r10 - remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.CallBuilder(self, fnloc, arglocs) + cb.emit_no_collect() def _reload_frame_if_necessary(self, mc, align_stack=False): gcrootmap = self.cpu.gc_ll_descr.gcrootmap @@ -1198,10 +1036,6 @@ self._write_barrier_fastpath(mc, wbdescr, [ebp], array=False, is_frame=True, align_stack=align_stack) - def call(self, addr, args, res): - self._emit_call(imm(addr), args) - assert res is eax - genop_int_neg = _unaryop("NEG") genop_int_invert = _unaryop("NOT") genop_int_add = _binaryop_or_lea("ADD", True) @@ -1446,7 +1280,7 @@ # ---------- def genop_call_malloc_gc(self, op, arglocs, result_loc): - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self.propagate_memoryerror_if_eax_is_null() def propagate_memoryerror_if_eax_is_null(self): @@ -1993,75 +1827,29 @@ self.pending_guard_tokens.append(guard_token) def genop_call(self, op, arglocs, resloc): - return self._genop_call(op, arglocs, resloc) + self._genop_call(op, arglocs, resloc) def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False): from rpython.jit.backend.llsupport.descr import CallDescr - sizeloc = arglocs[0] - assert isinstance(sizeloc, ImmedLoc) - size = sizeloc.value - signloc = arglocs[1] - - x = arglocs[2] # the function address - if x is eax: - tmp = ecx - else: - tmp = eax + cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:], resloc) descr = op.getdescr() assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[0] + assert isinstance(sizeloc, ImmedLoc) + cb.ressize = sizeloc.value + signloc = arglocs[1] + assert isinstance(signloc, ImmedLoc) + cb.ressign = signloc.value - stack_max = PASS_ON_MY_FRAME if is_call_release_gil: - if self._is_asmgcc(): - from rpython.memory.gctransform import asmgcroot - stack_max -= asmgcroot.JIT_USE_WORDS - can_collect = False + cb.emit_call_release_gil() else: - can_collect = True - - self._emit_call(x, arglocs, 3, tmp=tmp, - argtypes=descr.get_arg_types(), - callconv=descr.get_call_conv(), - can_collect=can_collect, - stack_max=stack_max) - - if IS_X86_32 and isinstance(resloc, FrameLoc) and resloc.type == FLOAT: - # a float or a long long return - if descr.get_result_type() == 'L': - self.mc.MOV_br(resloc.value, eax.value) # long long - self.mc.MOV_br(resloc.value + 4, edx.value) - # XXX should ideally not move the result on the stack, - # but it's a mess to load eax/edx into a xmm register - # and this way is simpler also because the result loc - # can just be always a stack location - else: - self.mc.FSTPL_b(resloc.value) # float return - elif descr.get_result_type() == 'S': - # singlefloat return - assert resloc is eax - if IS_X86_32: - # must convert ST(0) to a 32-bit singlefloat and load it into EAX - # mess mess mess - self.mc.SUB_ri(esp.value, 4) - self.mc.FSTPS_s(0) - self.mc.POP_r(eax.value) - elif IS_X86_64: - # must copy from the lower 32 bits of XMM0 into eax - self.mc.MOVD_rx(eax.value, xmm0.value) - elif size == WORD: - assert resloc is eax or resloc is xmm0 # a full word - elif size == 0: - pass # void return - else: - # use the code in load_from_mem to do the zero- or sign-extension - assert resloc is eax - if size == 1: - srcloc = eax.lowest8bits() - else: - srcloc = eax - self.load_from_mem(eax, srcloc, sizeloc, signloc) + cb.emit() def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() @@ -2077,64 +1865,15 @@ def genop_guard_call_may_force(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self._emit_guard_not_forced(guard_token) def genop_guard_call_release_gil(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs) - # do the call self._genop_call(op, arglocs, result_loc, is_call_release_gil=True) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, result_loc) - self.pop_gcmap(self.mc) # remove the gcmap saved above - # finally, the guard_not_forced self._emit_guard_not_forced(guard_token) - def call_release_gil(self, gcrootmap, save_registers): - if gcrootmap.is_shadow_stack: - args = [] - else: - from rpython.memory.gctransform import asmgcroot - # build a 'css' structure on the stack: 2 words for the linkage, - # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a - # total size of JIT_USE_WORDS. This structure is found at - # [ESP+css]. - css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) - assert css >= 2 - # Save ebp - index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) - self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP - # Save the "return address": we pretend that it's css - if IS_X86_32: - reg = eax - elif IS_X86_64: - reg = edi - self.mc.LEA_rs(reg.value, css) # LEA reg, [css] - frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) - self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg - # Set up jf_extra_stack_depth to pretend that the return address - # was at css, and so our stack frame is supposedly shorter by - # (css+WORD) bytes - self.set_extra_stack_depth(self.mc, -css-WORD) - # Call the closestack() function (also releasing the GIL) - args = [reg] - # - self._emit_call(imm(self.releasegil_addr), args, can_collect=False) - def call_reacquire_gil(self, gcrootmap, save_loc): # save the previous result (eax/xmm0) into the stack temporarily. # XXX like with call_release_gil(), we assume that we don't need @@ -2186,11 +1925,11 @@ self.call_assembler(op, guard_op, argloc, vloc, result_loc, eax) self._emit_guard_not_forced(guard_token) - def _call_assembler_emit_call(self, addr, argloc, tmploc): - self._emit_call(addr, [argloc], 0, tmp=tmploc) + def _call_assembler_emit_call(self, addr, argloc, _): + self.simple_call(addr, [argloc]) - def _call_assembler_emit_helper_call(self, addr, arglocs, _): - self._emit_call(addr, arglocs, 0, tmp=self._second_tmp_reg) + def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc): + self.simple_call(addr, arglocs, result_loc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/x86/callbuilder.py @@ -0,0 +1,577 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32, + PASS_ON_MY_FRAME) +from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, + r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, + RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) +from rpython.jit.backend.x86.jump import remap_frame_layout + + +# darwin requires the stack to be 16 bytes aligned on calls. +# Same for gcc 4.5.0, better safe than sorry +CALL_ALIGN = 16 // WORD + +def align_stack_words(words): + return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) + + + +class AbstractCallBuilder(object): + + # max number of words we have room in esp; if we need more for + # arguments, we need to decrease esp temporarily + stack_max = PASS_ON_MY_FRAME + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # set by save_result_value() + tmpresloc = None + + + def __init__(self, assembler, fnloc, arglocs, + resloc=eax, restype=INT, ressize=WORD): + # Avoid tons of issues with a non-immediate fnloc by sticking it + # as an extra argument if needed + self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) + if self.fnloc_is_immediate: + self.fnloc = fnloc + self.arglocs = arglocs + else: + self.arglocs = arglocs + [fnloc] + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + self.current_esp = 0 # 0 or (usually) negative, counted in bytes + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_esp() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_esp() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_esp() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + if self.asm._is_asmgcc(): + from rpython.memory.gctransform import asmgcroot + self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + assert self.stack_max >= 3 + + def emit_raw_call(self): + self.mc.CALL(self.fnloc) + if self.callconv != FFI_DEFAULT_ABI: + self.current_esp += self._fix_stdcall(self.callconv) + + def subtract_esp_aligned(self, count): + if count > 0: + align = align_stack_words(count) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) + + def restore_esp(self, target_esp=0): + if self.current_esp != target_esp: + self.mc.ADD_ri(esp.value, target_esp - self.current_esp) + self.current_esp = target_esp + + def load_result(self): + """Overridden in CallBuilder32 and CallBuilder64""" + if self.ressize == 0: + return # void result + # use the code in load_from_mem to do the zero- or sign-extension + srcloc = self.tmpresloc + if srcloc is None: + if self.restype == FLOAT: + srcloc = xmm0 + else: + srcloc = eax + if self.ressize >= WORD and self.resloc is srcloc: + return # no need for any MOV + if self.ressize == 1 and isinstance(srcloc, RegLoc): + srcloc = srcloc.lowest8bits() + self.asm.load_from_mem(self.resloc, srcloc, + imm(self.ressize), imm(self.ressign)) + + def push_gcmap(self): + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just before, ignoring the return + # value eax, if necessary + assert not self.is_call_release_gil + self.change_extra_stack_depth = (self.current_esp != 0) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, -self.current_esp) + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, 0) + self.asm.pop_gcmap(self.mc) + + def call_releasegil_addr_and_move_real_arguments(self): + initial_esp = self.current_esp + self.save_register_arguments() + # + if not self.asm._is_asmgcc(): + # the helper takes no argument + self.change_extra_stack_depth = False + else: + from rpython.memory.gctransform import asmgcroot + # build a 'css' structure on the stack: 2 words for the linkage, + # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a + # total size of JIT_USE_WORDS. This structure is found at + # [ESP+css]. + css = -self.current_esp + ( + WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS)) + assert css >= 2 * WORD + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Save the "return address": we pretend that it's css + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) # LEA reg, [css] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg + # Set up jf_extra_stack_depth to pretend that the return address + # was at css, and so our stack frame is supposedly shorter by + # (PASS_ON_MY_FRAME-JIT_USE_WORDS+1) words + delta = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + 1 + self.change_extra_stack_depth = True + self.asm.set_extra_stack_depth(self.mc, -delta * WORD) + # Call the closestack() function (also releasing the GIL) + # with 'reg' as argument + if IS_X86_32: + self.subtract_esp_aligned(1) + self.mc.MOV_sr(0, reg.value) + #else: + # on x86_64, reg is edi so that it is already correct + # + self.mc.CALL(imm(self.asm.releasegil_addr)) + # + if not we_are_translated(): # for testing: we should not access + self.mc.ADD(ebp, imm(1)) # ebp any more + # + self.restore_register_arguments() + self.restore_esp(initial_esp) + + def save_register_arguments(self): + """Overridden in CallBuilder64""" + + def restore_register_arguments(self): + """Overridden in CallBuilder64""" + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got (in eax/eax+edx/st(0)/xmm0) + self.save_result_value() + # call the reopenstack() function (also reacquiring the GIL) + if not self.asm._is_asmgcc(): + css = 0 # the helper takes no argument + else: + from rpython.memory.gctransform import asmgcroot + css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) + if IS_X86_32: + self.mc.MOV_sr(0, reg.value) + # + self.mc.CALL(imm(self.asm.reacqgil_addr)) + # + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB(ebp, imm(1)) # ebp again + # + # Now that we required the GIL, we can reload a possibly modified ebp + if self.asm._is_asmgcc(): + # special-case: reload ebp from the css + from rpython.memory.gctransform import asmgcroot + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_rs(ebp.value, index_of_ebp) # MOV EBP, [css.ebp] + #else: + # for shadowstack, done for us by _reload_frame_if_necessary() + + def save_result_value(self): + """Overridden in CallBuilder32 and CallBuilder64""" + raise NotImplementedError + + +class CallBuilder32(AbstractCallBuilder): + + def prepare_arguments(self): + arglocs = self.arglocs + stack_depth = 0 + n = len(arglocs) + for i in range(n): + loc = arglocs[i] + stack_depth += loc.get_width() // WORD + self.subtract_esp_aligned(stack_depth - self.stack_max) + # + p = 0 + for i in range(n): + loc = arglocs[i] + if isinstance(loc, RegLoc): + if loc.is_xmm: + self.mc.MOVSD_sx(p, loc.value) + else: + self.mc.MOV_sr(p, loc.value) + p += loc.get_width() + p = 0 + for i in range(n): + loc = arglocs[i] + if not isinstance(loc, RegLoc): + if loc.get_width() == 8: + self.mc.MOVSD(xmm0, loc) + self.mc.MOVSD_sx(p, xmm0.value) + elif isinstance(loc, ImmedLoc): + self.mc.MOV_si(p, loc.value) + else: + self.mc.MOV(eax, loc) + self.mc.MOV_sr(p, eax.value) + p += loc.get_width() + self.total_stack_used_by_arguments = p + # + if not self.fnloc_is_immediate: # the last "argument" pushed above + self.fnloc = RawEspLoc(p - WORD, INT) + + + def _fix_stdcall(self, callconv): + from rpython.rlib.clibffi import FFI_STDCALL + assert callconv == FFI_STDCALL + return self.total_stack_used_by_arguments + + def load_result(self): + resloc = self.resloc + if resloc is not None and resloc.is_float(): + # a float or a long long return + if self.tmpresloc is None: + if self.restype == 'L': # long long + # move eax/edx -> xmm0 + self.mc.MOVD_xr(resloc.value^1, edx.value) + self.mc.MOVD_xr(resloc.value, eax.value) + self.mc.PUNPCKLDQ_xx(resloc.value, resloc.value^1) + else: + # float: we have to go via the stack + self.mc.FSTPL_s(0) + self.mc.MOVSD_xs(resloc.value, 0) + else: + self.mc.MOVSD(resloc, self.tmpresloc) + # + elif self.restype == 'S': + # singlefloat return: must convert ST(0) to a 32-bit singlefloat + # and load it into self.resloc. mess mess mess + if self.tmpresloc is None: + self.mc.FSTPS_s(0) + self.mc.MOV_rs(resloc.value, 0) + else: + self.mc.MOV(resloc, self.tmpresloc) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP+4]. We use "+4" + # in order to leave the word at [ESP+0] free, in case it's needed + if self.ressize == 0: # void return + return + if self.resloc.is_float(): + # a float or a long long return + self.tmpresloc = RawEspLoc(4, FLOAT) + if self.restype == 'L': + self.mc.MOV_sr(4, eax.value) # long long + self.mc.MOV_sr(8, edx.value) + else: + self.mc.FSTPL_s(4) # float return + else: + self.tmpresloc = RawEspLoc(4, INT) + if self.restype == 'S': + self.mc.FSTPS_s(4) + else: + assert self.restype == INT + assert self.ressize <= WORD + self.mc.MOV_sr(4, eax.value) + + +class CallBuilder64(AbstractCallBuilder): + + ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] + ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + DONT_MOVE_GPR = [] + _ALL_CALLEE_SAVE_GPR = [ebx, r12, r13, r14, r15] + + next_arg_gpr = 0 + next_arg_xmm = 0 + + def _unused_gpr(self, hint): + i = self.next_arg_gpr + self.next_arg_gpr = i + 1 + try: + res = self.ARGUMENTS_GPR[i] + except IndexError: + return None + if hint in self.DONT_MOVE_GPR: + self.ARGUMENTS_GPR[i] = hint + res = hint + return res + + def _unused_xmm(self): + i = self.next_arg_xmm + self.next_arg_xmm = i + 1 + try: + return self.ARGUMENTS_XMM[i] + except IndexError: + return None + + def _permute_to_prefer_unused_registers(self, lst): + # permute 'lst' so that it starts with registers that are not + # in 'self.already_used', and ends with registers that are. + N = len(lst) + i = 0 + while i < N: + reg = lst[i] + if reg in self.already_used: + # move this reg to the end, and decrement N + N -= 1 + assert N >= i + lst[N], lst[i] = lst[i], lst[N] + else: + i += 1 + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + # We have to copy the arguments around a bit more in this mode, + # but on the other hand we don't need prepare_arguments() moving + # them in precisely the final registers. Here we look around for + # unused registers that may be more likely usable. + from rpython.jit.backend.x86.regalloc import X86_64_RegisterManager + from rpython.jit.backend.x86.regalloc import X86_64_XMMRegisterManager + self.already_used = {} + for loc in self.arglocs: + self.already_used[loc] = None + # + lst = X86_64_RegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + # + extra = [] + for reg in self.asm._regalloc.rm.free_regs: + if (reg not in self.already_used and + reg in self._ALL_CALLEE_SAVE_GPR): + extra.append(reg) + self.free_callee_save_gprs = extra + lst = extra + lst + # + self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] + self.DONT_MOVE_GPR = self._ALL_CALLEE_SAVE_GPR + # + lst = X86_64_XMMRegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + self.ARGUMENTS_XMM = lst[:len(self.ARGUMENTS_XMM)] + + def prepare_arguments(self): + src_locs = [] + dst_locs = [] + xmm_src_locs = [] + xmm_dst_locs = [] + singlefloats = None + + arglocs = self.arglocs + argtypes = self.argtypes + + on_stack = 0 + for i in range(len(arglocs)): + loc = arglocs[i] + if loc.is_float(): + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, FLOAT) + on_stack += 1 + xmm_src_locs.append(loc) + xmm_dst_locs.append(tgt) + elif i < len(argtypes) and argtypes[i] == 'S': + # Singlefloat argument + if singlefloats is None: + singlefloats = [] + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + singlefloats.append((loc, tgt)) + else: + tgt = self._unused_gpr(hint=loc) + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + src_locs.append(loc) + dst_locs.append(tgt) + + if not self.fnloc_is_immediate: + self.fnloc = dst_locs[-1] # the last "argument" prepared above + + if not we_are_translated(): # assert that we got the right stack depth + floats = 0 + for i in range(len(arglocs)): + arg = arglocs[i] + if arg.is_float() or (i < len(argtypes) and argtypes[i]=='S'): + floats += 1 + all_args = len(arglocs) + stack_depth = (max(all_args - floats - len(self.ARGUMENTS_GPR), 0) + + max(floats - len(self.ARGUMENTS_XMM), 0)) + assert stack_depth == on_stack + + self.subtract_esp_aligned(on_stack - self.stack_max) + + # Handle register arguments: first remap the xmm arguments + remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, + X86_64_XMM_SCRATCH_REG) + # Load the singlefloat arguments from main regs or stack to xmm regs + if singlefloats is not None: + for src, dst in singlefloats: + if isinstance(dst, RawEspLoc): + # XXX too much special logic + if isinstance(src, RawEbpLoc): + self.mc.MOV32(X86_64_SCRATCH_REG, src) + self.mc.MOV32(dst, X86_64_SCRATCH_REG) + else: + self.mc.MOV32(dst, src) + continue + if isinstance(src, ImmedLoc): + self.mc.MOV(X86_64_SCRATCH_REG, src) + src = X86_64_SCRATCH_REG + self.mc.MOVD(dst, src) + # Finally remap the arguments in the main regs + remap_frame_layout(self.asm, src_locs, dst_locs, X86_64_SCRATCH_REG) + + + def _fix_stdcall(self, callconv): + assert 0 # should not occur on 64-bit + + def load_result(self): + if self.restype == 'S' and self.tmpresloc is None: + # singlefloat return: use MOVD to load the target register + # from the lower 32 bits of XMM0 + self.mc.MOVD(self.resloc, xmm0) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP]. + if self.ressize == 0: # void return + return + # + if self.restype == FLOAT: # and not 'S' + self.mc.MOVSD_sx(0, xmm0.value) + self.tmpresloc = RawEspLoc(0, FLOAT) + return + # + if len(self.free_callee_save_gprs) == 0: + self.tmpresloc = RawEspLoc(0, INT) + else: + self.tmpresloc = self.free_callee_save_gprs[0] + # + if self.restype == 'S': + # singlefloat return: use MOVD to store the lower 32 bits + # of XMM0 into the tmpresloc (register or [ESP]) + self.mc.MOVD(self.tmpresloc, xmm0) + else: + assert self.restype == INT + self.mc.MOV(self.tmpresloc, eax) + + def save_register_arguments(self): + # Save the argument registers, which are given by self.ARGUMENTS_xxx. + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + n_saved_regs = n_gpr + n_xmm + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] in self._ALL_CALLEE_SAVE_GPR: + n_saved_regs -= 1 # don't need to save it + self.subtract_esp_aligned(n_saved_regs) + # + n = 0 + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_sr(n * WORD, self.ARGUMENTS_GPR[i].value) + n += 1 + for i in range(n_xmm): + self.mc.MOVSD_sx(n * WORD, self.ARGUMENTS_XMM[i].value) + n += 1 + assert n == n_saved_regs + self.n_saved_regs = n_saved_regs + + def restore_register_arguments(self): + # Restore the saved values into the *real* registers used for calls + # --- which are not self.ARGUMENTS_xxx! + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + # + n = 0 + for i in range(n_gpr): + tgtvalue = CallBuilder64.ARGUMENTS_GPR[i].value + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_rs(tgtvalue, n * WORD) + n += 1 + else: + self.mc.MOV_rr(tgtvalue, self.ARGUMENTS_GPR[i].value) + for i in range(n_xmm): + self.mc.MOVSD_xs(CallBuilder64.ARGUMENTS_XMM[i].value, n * WORD) + n += 1 + assert n == self.n_saved_regs + # + if isinstance(self.fnloc, RegLoc): # fix this register + self.fnloc = CallBuilder64.ARGUMENTS_GPR[n_gpr - 1] + + +if IS_X86_32: + CallBuilder = CallBuilder32 +if IS_X86_64: + CallBuilder = CallBuilder64 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -79,26 +79,14 @@ rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), adr)[1] = y return ConstFloatLoc(adr) - def after_call(self, v): - # the result is stored in st0, but we don't have this around, - # so genop_call will move it to some frame location immediately - # after the call - return self.frame_manager.loc(v) + def call_result_location(self, v): + return xmm0 class X86_64_XMMRegisterManager(X86XMMRegisterManager): # xmm15 reserved for scratch use all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14] save_around_call_regs = all_regs - def call_result_location(self, v): - return xmm0 - - def after_call(self, v): - # We use RegisterManager's implementation, since X86XMMRegisterManager - # places the result on the stack, which we don't need to do when the - # calling convention places the result in xmm0 - return RegisterManager.after_call(self, v) - class X86FrameManager(FrameManager): def __init__(self, base_ofs): FrameManager.__init__(self) @@ -799,14 +787,6 @@ self._consider_call(op, guard_op) def consider_call_release_gil(self, op, guard_op): - # We spill the arguments to the stack, because we need to do 3 calls: - # call_release_gil(), the_real_c_function(), and call_reacquire_gil(). - # The arguments are used on the second call only. XXX we assume - # that the XMM arguments won't be modified by call_release_gil(). - for i in range(op.numargs()): - loc = self.loc(op.getarg(i)) - if loc in self.rm.save_around_call_regs: - self.rm.force_spill_var(op.getarg(i)) assert guard_op is not None self._consider_call(op, guard_op) @@ -1151,9 +1131,8 @@ # call memcpy() self.rm.before_call() self.xrm.before_call() - self.assembler._emit_call(imm(self.assembler.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.assembler.simple_call_no_collect(imm(self.assembler.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) self.rm.possibly_free_var(length_box) self.rm.possibly_free_var(dstaddr_box) self.rm.possibly_free_var(srcaddr_box) diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -553,6 +553,7 @@ CALL_l = insn('\xE8', relative(1)) CALL_r = insn(rex_nw, '\xFF', register(1), chr(0xC0 | (2<<3))) CALL_b = insn('\xFF', orbyte(2<<3), stack_bp(1)) + CALL_s = insn('\xFF', orbyte(2<<3), stack_sp(1)) # XXX: Only here for testing purposes..."as" happens the encode the # registers in the opposite order that we would otherwise do in a @@ -583,6 +584,7 @@ # x87 instructions FSTPL_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) # rffi.DOUBLE ('as' wants L??) + FSTPL_s = insn('\xDD', orbyte(3<<3), stack_sp(1)) # rffi.DOUBLE ('as' wants L??) FSTPS_s = insn('\xD9', orbyte(3<<3), stack_sp(1)) # lltype.SingleFloat # ------------------------------ Random mess ----------------------- From noreply at buildbot.pypy.org Mon May 20 13:52:36 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 13:52:36 +0200 (CEST) Subject: [pypy-commit] cffi default: Fix (motivated by a pypy without cpyext): if we're using vengine_gen.py, Message-ID: <20130520115236.8401A1C1027@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1253:617edf867775 Date: 2013-05-20 13:52 +0200 http://bitbucket.org/cffi/cffi/changeset/617edf867775/ Log: Fix (motivated by a pypy without cpyext): if we're using vengine_gen.py, then we should not use imp.find_module() to locate our compiled module, because it's actually not a CPython C API module at all. Instead, just walk sys.path in that case. diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py --- a/cffi/vengine_cpy.py +++ b/cffi/vengine_cpy.py @@ -15,6 +15,20 @@ def patch_extension_kwds(self, kwds): pass + def find_module(self, module_name, path, so_suffix): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] != so_suffix: + return None + return filename + def collect_types(self): self._typesdict = {} self._generate("collecttype") diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py --- a/cffi/vengine_gen.py +++ b/cffi/vengine_gen.py @@ -1,4 +1,4 @@ -import sys +import sys, os import types from . import model, ffiplatform @@ -20,6 +20,16 @@ # up in kwds['export_symbols']. kwds.setdefault('export_symbols', self.export_symbols) + def find_module(self, module_name, path, so_suffix): + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + return None + def collect_types(self): pass # not needed in the generic engine diff --git a/cffi/verifier.py b/cffi/verifier.py --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -102,21 +102,10 @@ path = pkg.__path__ else: path = None - try: - f, filename, descr = imp.find_module(self.get_module_name(), - path) - except ImportError: + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffix()) + if filename is None: return - if f is not None: - f.close() - if filename.lower().endswith('.py'): - # on PyPy, if there are both .py and .pypy-19.so files in - # the same directory, the .py file is returned. That's the - # case after a setuptools installation. We never want to - # load the .py file here... - filename = filename[:-3] + _get_so_suffix() - if not os.path.isfile(filename): - return self.modulefilename = filename self._vengine.collect_types() self._has_module = True From noreply at buildbot.pypy.org Mon May 20 16:15:09 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 20 May 2013 16:15:09 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Bump the version number Message-ID: <20130520141509.B364A1C131B@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64366:00a6764b871b Date: 2013-05-20 16:14 +0200 http://bitbucket.org/pypy/pypy/changeset/00a6764b871b/ Log: Bump the version number diff --git a/pypy/module/cpyext/include/patchlevel.h b/pypy/module/cpyext/include/patchlevel.h --- a/pypy/module/cpyext/include/patchlevel.h +++ b/pypy/module/cpyext/include/patchlevel.h @@ -29,7 +29,7 @@ #define PY_VERSION "2.7.3" /* PyPy version as a string */ -#define PYPY_VERSION "2.0.1" +#define PYPY_VERSION "2.0.2" /* Subversion Revision number of this file (not of the repository). * Empty since Mercurial migration. */ diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py --- a/pypy/module/sys/version.py +++ b/pypy/module/sys/version.py @@ -11,7 +11,7 @@ #XXX # sync CPYTHON_VERSION with patchlevel.h, package.py CPYTHON_API_VERSION = 1013 #XXX # sync with include/modsupport.h -PYPY_VERSION = (2, 0, 1, "final", 0) #XXX # sync patchlevel.h +PYPY_VERSION = (2, 0, 2, "final", 0) #XXX # sync patchlevel.h if platform.name == 'msvc': COMPILER_INFO = 'MSC v.%d 32 bit' % (platform.version * 10 + 600) From noreply at buildbot.pypy.org Mon May 20 18:33:39 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 20 May 2013 18:33:39 +0200 (CEST) Subject: [pypy-commit] pypy default: add tests for the instructions generated by _{push, pop}_all_regs_{to, from}_jitframe Message-ID: <20130520163339.957C61C0698@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64367:d2e5c70de403 Date: 2013-05-20 11:27 -0500 http://bitbucket.org/pypy/pypy/changeset/d2e5c70de403/ Log: add tests for the instructions generated by _{push,pop}_all_regs_{to,from}_jitframe diff --git a/rpython/jit/backend/arm/test/test_push_pop_frame.py b/rpython/jit/backend/arm/test/test_push_pop_frame.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/test/test_push_pop_frame.py @@ -0,0 +1,177 @@ +import py +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm.test.test_regalloc_mov import BaseMovTest, mi + +base_ofs = 23 +class MockCPU(object): + def get_baseofs_of_frame_field(self): + return base_ofs + + +class TestRegallocPush(BaseMovTest): + def setup_method(self, method): + BaseMovTest.setup_method(self, method) + self.asm.cpu = MockCPU() + + def test_callee_only(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('STM', r.ip.value, [r.r0.value, r.r1.value, + r.r2.value, r.r3.value]), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes(self): + expected = [ + mi('STR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('STR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[r.r1, r.r3], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes_in_front(self): + expected = [ + mi('STR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + mi('STR_ri', r.r3.value, r.fp.value, cond=c.AL, imm=base_ofs + 12), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[r.r0, r.r1], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_ignore_more_than_saved(self): + expected = [ + mi('STR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3, r.r4, r.r5], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_with_floats(self): + expected = [ + mi('STR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('ADD_ri', r.ip.value, r.fp.value, imm=base_ofs + len(r.all_regs) * WORD), + mi('VSTM', r.ip.value, [v.value for v in r.all_vfp_regs]) + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3], + withfloats=True, callee_only=True) + self.validate(expected) + + def test_try_ignore_vfp_reg(self): + py.test.raises(AssertionError, self.asm._push_all_regs_to_jitframe, self.asm.mc, + ignored_regs=[r.d0, r.r2, r.r3], withfloats=True, callee_only=True) + + def test_all_regs(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('STM', r.ip.value, [reg.value for reg in r.all_regs]), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes(self): + ignored = [r.r1, r.r6] + expected = [mi('STR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes_in_front(self): + ignored = [r.r0, r.r1] + expected = [mi('STR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) + + + +class TestRegallocPop(BaseMovTest): + def setup_method(self, method): + BaseMovTest.setup_method(self, method) + self.asm.cpu = MockCPU() + + def test_callee_only(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('LDM', r.ip.value, [r.r0.value, r.r1.value, + r.r2.value, r.r3.value]), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes(self): + expected = [ + mi('LDR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('LDR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[r.r1, r.r3], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes_in_front(self): + expected = [ + mi('LDR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + mi('LDR_ri', r.r3.value, r.fp.value, cond=c.AL, imm=base_ofs + 12), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[r.r0, r.r1], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_ignore_more_than_saved(self): + expected = [ + mi('LDR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3, r.r4, r.r5], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_with_floats(self): + expected = [ + mi('LDR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('ADD_ri', r.ip.value, r.fp.value, imm=base_ofs + len(r.all_regs) * WORD), + mi('VLDM', r.ip.value, [v.value for v in r.all_vfp_regs]) + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3], + withfloats=True, callee_only=True) + self.validate(expected) + + def test_try_ignore_vfp_reg(self): + py.test.raises(AssertionError, self.asm._pop_all_regs_from_jitframe, self.asm.mc, + ignored_regs=[r.d0, r.r2, r.r3], withfloats=True, callee_only=True) + + def test_all_regs(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('LDM', r.ip.value, [reg.value for reg in r.all_regs]), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes(self): + ignored = [r.r1, r.r6] + expected = [mi('LDR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes_in_front(self): + ignored = [r.r0, r.r1] + expected = [mi('LDR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) From noreply at buildbot.pypy.org Mon May 20 18:33:40 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 20 May 2013 18:33:40 +0200 (CEST) Subject: [pypy-commit] pypy default: try to use LDM/STM when pushing a contiguous set of registers to the jitframe Message-ID: <20130520163340.E761C1C131B@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64368:e3b94f67cda3 Date: 2013-05-20 11:29 -0500 http://bitbucket.org/pypy/pypy/changeset/e3b94f67cda3/ Log: try to use LDM/STM when pushing a contiguous set of registers to the jitframe diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -355,54 +355,63 @@ def _push_all_regs_to_jitframe(self, mc, ignored_regs, withfloats, callee_only=False): + # Push general purpose registers base_ofs = self.cpu.get_baseofs_of_frame_field() if callee_only: regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - # XXX use STMDB ops here - for i, gpr in enumerate(regs): - if gpr in ignored_regs: - continue - self.store_reg(mc, gpr, r.fp, base_ofs + i * WORD) + # XXX add special case if ignored_regs are a block at the start of regs + if not ignored_regs: # we want to push a contiguous block of regs + assert check_imm_arg(base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) + mc.STM(r.ip.value, [reg.value for reg in regs]) + else: + for reg in ignored_regs: + assert not reg.is_vfp_reg() # sanity check + # we can have holes in the list of regs + for i, gpr in enumerate(regs): + if gpr in ignored_regs: + continue + self.store_reg(mc, gpr, r.fp, base_ofs + i * WORD) + if withfloats: - if callee_only: - regs = VFPRegisterManager.save_around_call_regs - else: - regs = VFPRegisterManager.all_regs - for i, vfpr in enumerate(regs): - if vfpr in ignored_regs: - continue - ofs = len(CoreRegisterManager.all_regs) * WORD - ofs += i * DOUBLE_WORD + base_ofs - self.store_reg(mc, vfpr, r.fp, ofs) + # Push VFP regs + regs = VFPRegisterManager.all_regs + ofs = len(CoreRegisterManager.all_regs) * WORD + assert check_imm_arg(ofs+base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, imm=ofs+base_ofs) + mc.VSTM(r.ip.value, [vfpr.value for vfpr in regs]) def _pop_all_regs_from_jitframe(self, mc, ignored_regs, withfloats, callee_only=False): - # Pop all general purpose registers + # Pop general purpose registers base_ofs = self.cpu.get_baseofs_of_frame_field() if callee_only: regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - # XXX use LDMDB ops here - for i, gpr in enumerate(regs): - if gpr in ignored_regs: - continue - ofs = i * WORD + base_ofs - self.load_reg(mc, gpr, r.fp, ofs) + # XXX add special case if ignored_regs are a block at the start of regs + if not ignored_regs: # we want to pop a contiguous block of regs + assert check_imm_arg(base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) + mc.LDM(r.ip.value, [reg.value for reg in regs]) + else: + for reg in ignored_regs: + assert not reg.is_vfp_reg() # sanity check + # we can have holes in the list of regs + for i, gpr in enumerate(regs): + if gpr in ignored_regs: + continue + ofs = i * WORD + base_ofs + self.load_reg(mc, gpr, r.fp, ofs) if withfloats: - # Pop all XMM regs - if callee_only: - regs = VFPRegisterManager.save_around_call_regs - else: - regs = VFPRegisterManager.all_regs - for i, vfpr in enumerate(regs): - if vfpr in ignored_regs: - continue - ofs = len(CoreRegisterManager.all_regs) * WORD - ofs += i * DOUBLE_WORD + base_ofs - self.load_reg(mc, vfpr, r.fp, ofs) + # Pop VFP regs + regs = VFPRegisterManager.all_regs + ofs = len(CoreRegisterManager.all_regs) * WORD + assert check_imm_arg(ofs+base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, imm=ofs+base_ofs) + mc.VLDM(r.ip.value, [vfpr.value for vfpr in regs]) def _build_failure_recovery(self, exc, withfloats=False): mc = InstrBuilder(self.cpu.cpuinfo.arch_version) From noreply at buildbot.pypy.org Mon May 20 18:33:42 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 20 May 2013 18:33:42 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130520163342.49CCC1C13E5@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64369:01eefe5a1417 Date: 2013-05-20 11:30 -0500 http://bitbucket.org/pypy/pypy/changeset/01eefe5a1417/ Log: merge heads diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -363,6 +363,9 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + + if config.translation.platform == 'arm' and '_continuation' in modules: + del modules[modules.find('_continuation')] config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -487,6 +487,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -586,7 +587,6 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=<.*>) i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -44,6 +44,7 @@ # gc_id call is hoisted out of the loop, the id of a value obviously # can't change ;) assert loop.match_by_id("getitem", """ + ... i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...) ... p33 = getinteriorfield_gc(p31, i26, descr=>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -36,7 +36,7 @@ assert loop0.match(expected) # XXX: The retracing fails to form a loop since j # becomes constant 0 after the bridge and constant 1 at the end of the - # loop. A bridge back to the peramble is produced instead. + # loop. A bridge back to the peramble is produced instead. #assert loop1.match(expected) def test_factorial(self): @@ -242,6 +242,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) + guard_not_invalidated(descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) diff --git a/rpython/jit/backend/llgraph/test/test_llgraph.py b/rpython/jit/backend/llgraph/test/test_llgraph.py --- a/rpython/jit/backend/llgraph/test/test_llgraph.py +++ b/rpython/jit/backend/llgraph/test/test_llgraph.py @@ -15,6 +15,9 @@ def test_memoryerror(self): py.test.skip("does not make much sense on the llgraph backend") + def test_call_release_gil_variable_function_and_arguments(self): + py.test.skip("the arguments seem not correctly casted") + def test_cast_adr_to_int_and_back(): X = lltype.Struct('X', ('foo', lltype.Signed)) 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 @@ -108,8 +108,7 @@ self.malloc_slowpath_unicode = None self._build_stack_check_slowpath() - if gc_ll_descr.gcrootmap: - self._build_release_gil(gc_ll_descr.gcrootmap) + self._build_release_gil(gc_ll_descr.gcrootmap) if not self._debug: # if self._debug is already set it means that someone called # set_debug by hand before initializing the assembler. Leave it @@ -348,12 +347,19 @@ if after: after() + @staticmethod + def _no_op(): + pass + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], lltype.Void)) def _build_release_gil(self, gcrootmap): - if gcrootmap.is_shadow_stack: + if gcrootmap is None: + releasegil_func = llhelper(self._NOARG_FUNC, self._no_op) + reacqgil_func = llhelper(self._NOARG_FUNC, self._no_op) + elif gcrootmap.is_shadow_stack: releasegil_func = llhelper(self._NOARG_FUNC, self._release_gil_shadowstack) reacqgil_func = llhelper(self._NOARG_FUNC, diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2532,6 +2532,219 @@ assert rffi.charp2strn(buffer, buflen) == cwd lltype.free(buffer, flavor='raw') + def test_call_release_gil_return_types(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + cpu = self.cpu + + for ffitype, result, TP in [ + (types.ulong, r_uint(sys.maxint + 10), lltype.Unsigned), + (types.slong, -4321, lltype.Signed), + (types.uint8, 200, rffi.UCHAR), + (types.sint8, -42, rffi.SIGNEDCHAR), + (types.uint16, 50000, rffi.USHORT), + (types.sint16, -20000, rffi.SHORT), + (types.uint32, r_uint(3000000000), rffi.UINT), + (types.sint32, -2000000000, rffi.INT), + (types.uint64, r_ulonglong(9999999999999999999), + lltype.UnsignedLongLong), + (types.sint64, r_longlong(-999999999999999999), + lltype.SignedLongLong), + (types.double, 12.3475226, rffi.DOUBLE), + (types.float, r_singlefloat(-592.75), rffi.FLOAT), + ]: + if sys.maxint < 2**32 and TP in (lltype.SignedLongLong, + lltype.UnsignedLongLong): + if not cpu.supports_longlong: + continue + if TP == rffi.DOUBLE: + if not cpu.supports_floats: + continue + if TP == rffi.FLOAT: + if not cpu.supports_singlefloats: + continue + # + result = rffi.cast(TP, result) + # + def pseudo_c_function(): + return result + # + FPTR = self.Ptr(self.FuncType([], TP)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests([], ffitype) + faildescr = BasicFailDescr(1) + kind = types.getkind(ffitype) + if kind in 'uis': + b3 = BoxInt() + elif kind in 'fUI': + b3 = BoxFloat() + else: + assert 0, kind + # + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox], b3, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [b3], None, descr=BasicFinalDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = JitCellToken() + self.cpu.compile_loop([], ops, looptoken) + + deadframe = self.cpu.execute_token(looptoken) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + if isinstance(b3, BoxInt): + r = self.cpu.get_int_value(deadframe, 0) + if isinstance(result, r_singlefloat): + assert -sys.maxint-1 <= r <= 0xFFFFFFFF + r, = struct.unpack("f", struct.pack("I", r & 0xFFFFFFFF)) + result = float(result) + else: + r = rffi.cast(TP, r) + assert r == result + elif isinstance(b3, BoxFloat): + r = self.cpu.get_float_value(deadframe, 0) + if isinstance(result, float): + r = longlong.getrealfloat(r) + else: + r = rffi.cast(TP, r) + assert r == result + + def test_call_release_gil_variable_function_and_arguments(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + + cpu = self.cpu + rnd = random.Random(525) + + ALL_TYPES = [ + (types.ulong, lltype.Unsigned), + (types.slong, lltype.Signed), + (types.uint8, rffi.UCHAR), + (types.sint8, rffi.SIGNEDCHAR), + (types.uint16, rffi.USHORT), + (types.sint16, rffi.SHORT), + (types.uint32, rffi.UINT), + (types.sint32, rffi.INT), + ] + if sys.maxint < 2**32 and cpu.supports_longlong: + ALL_TYPES += [ + (types.uint64, lltype.UnsignedLongLong), + (types.sint64, lltype.SignedLongLong), + ] * 2 + if cpu.supports_floats: + ALL_TYPES += [ + (types.double, rffi.DOUBLE), + ] * 4 + if cpu.supports_singlefloats: + ALL_TYPES += [ + (types.float, rffi.FLOAT), + ] * 4 + + for k in range(100): + POSSIBLE_TYPES = [rnd.choice(ALL_TYPES) + for i in range(random.randrange(2, 5))] + load_factor = rnd.random() + keepalive_factor = rnd.random() + # + def pseudo_c_function(*args): + seen.append(list(args)) + # + ffitypes = [] + ARGTYPES = [] + for i in range(rnd.randrange(4, 20)): + ffitype, TP = rnd.choice(POSSIBLE_TYPES) + ffitypes.append(ffitype) + ARGTYPES.append(TP) + # + FPTR = self.Ptr(self.FuncType(ARGTYPES, lltype.Void)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void) + faildescr = BasicFailDescr(1) + # + argboxes = [BoxInt()] # for the function to call + codes = ['X'] + for ffitype in ffitypes: + kind = types.getkind(ffitype) + codes.append(kind) + if kind in 'uis': + b1 = BoxInt() + elif kind in 'fUI': + b1 = BoxFloat() + else: + assert 0, kind + argboxes.append(b1) + codes = ''.join(codes) # useful for pdb + print + print codes + # + argvalues = [funcbox.getint()] + for TP in ARGTYPES: + r = (rnd.random() - 0.5) * 999999999999.9 + r = rffi.cast(TP, r) + argvalues.append(r) + # + argvalues_normal = argvalues[:1] + for ffitype, r in zip(ffitypes, argvalues[1:]): + kind = types.getkind(ffitype) + if kind in 'ui': + r = rffi.cast(lltype.Signed, r) + elif kind in 's': + r, = struct.unpack("i", struct.pack("f", float(r))) + elif kind in 'f': + r = longlong.getfloatstorage(r) + elif kind in 'UI': # 32-bit only + r = rffi.cast(lltype.SignedLongLong, r) + else: + assert 0 + argvalues_normal.append(r) + # + ops = [] + loadcodes = [] + insideboxes = [] + for b1 in argboxes: + load = rnd.random() < load_factor + loadcodes.append(' ^'[load]) + if load: + b2 = b1.clonebox() + ops.insert(rnd.randrange(0, len(ops)+1), + ResOperation(rop.SAME_AS, [b1], b2)) + b1 = b2 + insideboxes.append(b1) + loadcodes = ''.join(loadcodes) + print loadcodes + ops += [ + ResOperation(rop.CALL_RELEASE_GIL, insideboxes, None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0)) + ] + ops[-2].setfailargs([]) + # keep alive a random subset of the insideboxes + for b1 in insideboxes: + if rnd.random() < keepalive_factor: + ops.insert(-1, ResOperation(rop.SAME_AS, [b1], + b1.clonebox())) + looptoken = JitCellToken() + self.cpu.compile_loop(argboxes, ops, looptoken) + # + seen = [] + deadframe = self.cpu.execute_token(looptoken, *argvalues_normal) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + expected = argvalues[1:] + [got] = seen + different_values = ['%r != %r' % (a, b) + for a, b in zip(got, expected) + if a != b] + assert got == expected, ', '.join(different_values) + + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py --- a/rpython/jit/backend/x86/arch.py +++ b/rpython/jit/backend/x86/arch.py @@ -40,4 +40,4 @@ PASS_ON_MY_FRAME = 12 JITFRAME_FIXED_SIZE = 28 # 13 GPR + 15 XMM -assert PASS_ON_MY_FRAME >= 11 # asmgcc needs at least JIT_USE_WORDS + 2 +assert PASS_ON_MY_FRAME >= 12 # asmgcc needs at least JIT_USE_WORDS + 3 diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -6,7 +6,7 @@ DEBUG_COUNTER, debug_bridge) from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.llsupport.gcmap import allocate_gcmap -from rpython.jit.metainterp.history import Const, Box +from rpython.jit.metainterp.history import Const, Box, VOID from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory from rpython.rtyper.lltypesystem.lloperation import llop @@ -25,28 +25,17 @@ RegLoc, FrameLoc, ConstFloatLoc, ImmedLoc, AddressLoc, imm, imm0, imm1, FloatImmedLoc, RawEbpLoc, RawEspLoc) from rpython.rlib.objectmodel import we_are_translated -from rpython.jit.backend.x86 import rx86, codebuf +from rpython.jit.backend.x86 import rx86, codebuf, callbuilder from rpython.jit.metainterp.resoperation import rop from rpython.jit.backend.x86 import support from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib import rgc -from rpython.rlib.clibffi import FFI_DEFAULT_ABI -from rpython.jit.backend.x86.jump import remap_frame_layout from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter import longlong from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib.objectmodel import compute_unique_id -# darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0, -# better safe than sorry -CALL_ALIGN = 16 // WORD - - -def align_stack_words(words): - return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - - class Assembler386(BaseAssembler): _regalloc = None _output_loop_log = None @@ -131,10 +120,10 @@ mc.MOV_rs(esi.value, WORD*2) # push first arg mc.MOV_rr(edi.value, ebp.value) - align = align_stack_words(1) + align = callbuilder.align_stack_words(1) mc.SUB_ri(esp.value, (align - 1) * WORD) else: - align = align_stack_words(3) + align = callbuilder.align_stack_words(3) mc.MOV_rs(eax.value, WORD * 2) mc.SUB_ri(esp.value, (align - 1) * WORD) mc.MOV_sr(WORD, eax.value) @@ -1014,175 +1003,24 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def _emit_call(self, x, arglocs, start=0, tmp=eax, - argtypes=None, callconv=FFI_DEFAULT_ABI, - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True, - # max number of arguments we can pass on esp; if more, - # we need to decrease esp temporarily - stack_max=PASS_ON_MY_FRAME): - # - if IS_X86_64: - return self._emit_call_64(x, arglocs, start, argtypes, - can_collect, stack_max) - stack_depth = 0 - n = len(arglocs) - for i in range(start, n): - loc = arglocs[i] - stack_depth += loc.get_width() // WORD - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - self.mc.SUB_ri(esp.value, align * WORD) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) + def simple_call(self, fnloc, arglocs, result_loc=eax): + if result_loc is xmm0: + result_type = FLOAT + result_size = 8 + elif result_loc is None: + result_type = VOID + result_size = 0 else: - align = 0 - p = 0 - for i in range(start, n): - loc = arglocs[i] - if isinstance(loc, RegLoc): - if loc.is_xmm: - self.mc.MOVSD_sx(p, loc.value) - else: - self.mc.MOV_sr(p, loc.value) - p += loc.get_width() - p = 0 - for i in range(start, n): - loc = arglocs[i] - if not isinstance(loc, RegLoc): - if loc.get_width() == 8: - self.mc.MOVSD(xmm0, loc) - self.mc.MOVSD_sx(p, xmm0.value) - else: - self.mc.MOV(tmp, loc) - self.mc.MOV_sr(p, tmp.value) - p += loc.get_width() - # x is a location - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if callconv != FFI_DEFAULT_ABI: - self._fix_stdcall(callconv, p - align * WORD) - elif align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + result_type = INT + result_size = WORD + cb = callbuilder.CallBuilder(self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() - def _fix_stdcall(self, callconv, p): - from rpython.rlib.clibffi import FFI_STDCALL - assert callconv == FFI_STDCALL - # it's a bit stupid, but we're just going to cancel the fact that - # the called function just added 'p' to ESP, by subtracting it again. - self.mc.SUB_ri(esp.value, p) - - def _emit_call_64(self, x, arglocs, start, argtypes, - can_collect, stack_max): - src_locs = [] - dst_locs = [] - xmm_src_locs = [] - xmm_dst_locs = [] - singlefloats = None - - # In reverse order for use with pop() - unused_gpr = [r9, r8, ecx, edx, esi, edi] - unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0] - - on_stack = 0 - # count the stack depth - floats = 0 - for i in range(start, len(arglocs)): - arg = arglocs[i] - if arg.is_float() or argtypes and argtypes[i - start] == 'S': - floats += 1 - all_args = len(arglocs) - start - stack_depth = (max(all_args - floats - len(unused_gpr), 0) + - max(floats - len(unused_xmm), 0)) - align = 0 - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) - self.mc.SUB_ri(esp.value, align * WORD) - for i in range(start, len(arglocs)): - loc = arglocs[i] - if loc.is_float(): - xmm_src_locs.append(loc) - if len(unused_xmm) > 0: - xmm_dst_locs.append(unused_xmm.pop()) - else: - xmm_dst_locs.append(RawEspLoc(on_stack * WORD, FLOAT)) - on_stack += 1 - elif argtypes is not None and argtypes[i-start] == 'S': - # Singlefloat argument - if singlefloats is None: - singlefloats = [] - if len(unused_xmm) > 0: - singlefloats.append((loc, unused_xmm.pop())) - else: - singlefloats.append((loc, RawEspLoc(on_stack * WORD, INT))) - on_stack += 1 - else: - src_locs.append(loc) - if len(unused_gpr) > 0: - dst_locs.append(unused_gpr.pop()) - else: - dst_locs.append(RawEspLoc(on_stack * WORD, INT)) - on_stack += 1 - - # Handle register arguments: first remap the xmm arguments - remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, - X86_64_XMM_SCRATCH_REG) - # Load the singlefloat arguments from main regs or stack to xmm regs - if singlefloats is not None: - for src, dst in singlefloats: - if isinstance(dst, RawEspLoc): - # XXX too much special logic - if isinstance(src, RawEbpLoc): - self.mc.MOV32(X86_64_SCRATCH_REG, src) - self.mc.MOV32(dst, X86_64_SCRATCH_REG) - else: - self.mc.MOV32(dst, src) - continue - if isinstance(src, ImmedLoc): - self.mc.MOV(X86_64_SCRATCH_REG, src) - src = X86_64_SCRATCH_REG - self.mc.MOVD(dst, src) - # Finally remap the arguments in the main regs - # If x is a register and is in dst_locs, then oups, it needs to - # be moved away: - if x in dst_locs: - src_locs.append(x) - dst_locs.append(r10) - x = r10 - remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.CallBuilder(self, fnloc, arglocs) + cb.emit_no_collect() def _reload_frame_if_necessary(self, mc, align_stack=False): gcrootmap = self.cpu.gc_ll_descr.gcrootmap @@ -1198,10 +1036,6 @@ self._write_barrier_fastpath(mc, wbdescr, [ebp], array=False, is_frame=True, align_stack=align_stack) - def call(self, addr, args, res): - self._emit_call(imm(addr), args) - assert res is eax - genop_int_neg = _unaryop("NEG") genop_int_invert = _unaryop("NOT") genop_int_add = _binaryop_or_lea("ADD", True) @@ -1446,7 +1280,7 @@ # ---------- def genop_call_malloc_gc(self, op, arglocs, result_loc): - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self.propagate_memoryerror_if_eax_is_null() def propagate_memoryerror_if_eax_is_null(self): @@ -1993,75 +1827,29 @@ self.pending_guard_tokens.append(guard_token) def genop_call(self, op, arglocs, resloc): - return self._genop_call(op, arglocs, resloc) + self._genop_call(op, arglocs, resloc) def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False): from rpython.jit.backend.llsupport.descr import CallDescr - sizeloc = arglocs[0] - assert isinstance(sizeloc, ImmedLoc) - size = sizeloc.value - signloc = arglocs[1] - - x = arglocs[2] # the function address - if x is eax: - tmp = ecx - else: - tmp = eax + cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:], resloc) descr = op.getdescr() assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[0] + assert isinstance(sizeloc, ImmedLoc) + cb.ressize = sizeloc.value + signloc = arglocs[1] + assert isinstance(signloc, ImmedLoc) + cb.ressign = signloc.value - stack_max = PASS_ON_MY_FRAME if is_call_release_gil: - if self._is_asmgcc(): - from rpython.memory.gctransform import asmgcroot - stack_max -= asmgcroot.JIT_USE_WORDS - can_collect = False + cb.emit_call_release_gil() else: - can_collect = True - - self._emit_call(x, arglocs, 3, tmp=tmp, - argtypes=descr.get_arg_types(), - callconv=descr.get_call_conv(), - can_collect=can_collect, - stack_max=stack_max) - - if IS_X86_32 and isinstance(resloc, FrameLoc) and resloc.type == FLOAT: - # a float or a long long return - if descr.get_result_type() == 'L': - self.mc.MOV_br(resloc.value, eax.value) # long long - self.mc.MOV_br(resloc.value + 4, edx.value) - # XXX should ideally not move the result on the stack, - # but it's a mess to load eax/edx into a xmm register - # and this way is simpler also because the result loc - # can just be always a stack location - else: - self.mc.FSTPL_b(resloc.value) # float return - elif descr.get_result_type() == 'S': - # singlefloat return - assert resloc is eax - if IS_X86_32: - # must convert ST(0) to a 32-bit singlefloat and load it into EAX - # mess mess mess - self.mc.SUB_ri(esp.value, 4) - self.mc.FSTPS_s(0) - self.mc.POP_r(eax.value) - elif IS_X86_64: - # must copy from the lower 32 bits of XMM0 into eax - self.mc.MOVD_rx(eax.value, xmm0.value) - elif size == WORD: - assert resloc is eax or resloc is xmm0 # a full word - elif size == 0: - pass # void return - else: - # use the code in load_from_mem to do the zero- or sign-extension - assert resloc is eax - if size == 1: - srcloc = eax.lowest8bits() - else: - srcloc = eax - self.load_from_mem(eax, srcloc, sizeloc, signloc) + cb.emit() def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() @@ -2077,64 +1865,15 @@ def genop_guard_call_may_force(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self._emit_guard_not_forced(guard_token) def genop_guard_call_release_gil(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs) - # do the call self._genop_call(op, arglocs, result_loc, is_call_release_gil=True) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, result_loc) - self.pop_gcmap(self.mc) # remove the gcmap saved above - # finally, the guard_not_forced self._emit_guard_not_forced(guard_token) - def call_release_gil(self, gcrootmap, save_registers): - if gcrootmap.is_shadow_stack: - args = [] - else: - from rpython.memory.gctransform import asmgcroot - # build a 'css' structure on the stack: 2 words for the linkage, - # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a - # total size of JIT_USE_WORDS. This structure is found at - # [ESP+css]. - css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) - assert css >= 2 - # Save ebp - index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) - self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP - # Save the "return address": we pretend that it's css - if IS_X86_32: - reg = eax - elif IS_X86_64: - reg = edi - self.mc.LEA_rs(reg.value, css) # LEA reg, [css] - frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) - self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg - # Set up jf_extra_stack_depth to pretend that the return address - # was at css, and so our stack frame is supposedly shorter by - # (css+WORD) bytes - self.set_extra_stack_depth(self.mc, -css-WORD) - # Call the closestack() function (also releasing the GIL) - args = [reg] - # - self._emit_call(imm(self.releasegil_addr), args, can_collect=False) - def call_reacquire_gil(self, gcrootmap, save_loc): # save the previous result (eax/xmm0) into the stack temporarily. # XXX like with call_release_gil(), we assume that we don't need @@ -2186,11 +1925,11 @@ self.call_assembler(op, guard_op, argloc, vloc, result_loc, eax) self._emit_guard_not_forced(guard_token) - def _call_assembler_emit_call(self, addr, argloc, tmploc): - self._emit_call(addr, [argloc], 0, tmp=tmploc) + def _call_assembler_emit_call(self, addr, argloc, _): + self.simple_call(addr, [argloc]) - def _call_assembler_emit_helper_call(self, addr, arglocs, _): - self._emit_call(addr, arglocs, 0, tmp=self._second_tmp_reg) + def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc): + self.simple_call(addr, arglocs, result_loc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/x86/callbuilder.py @@ -0,0 +1,577 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32, + PASS_ON_MY_FRAME) +from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, + r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, + RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) +from rpython.jit.backend.x86.jump import remap_frame_layout + + +# darwin requires the stack to be 16 bytes aligned on calls. +# Same for gcc 4.5.0, better safe than sorry +CALL_ALIGN = 16 // WORD + +def align_stack_words(words): + return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) + + + +class AbstractCallBuilder(object): + + # max number of words we have room in esp; if we need more for + # arguments, we need to decrease esp temporarily + stack_max = PASS_ON_MY_FRAME + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # set by save_result_value() + tmpresloc = None + + + def __init__(self, assembler, fnloc, arglocs, + resloc=eax, restype=INT, ressize=WORD): + # Avoid tons of issues with a non-immediate fnloc by sticking it + # as an extra argument if needed + self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) + if self.fnloc_is_immediate: + self.fnloc = fnloc + self.arglocs = arglocs + else: + self.arglocs = arglocs + [fnloc] + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + self.current_esp = 0 # 0 or (usually) negative, counted in bytes + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_esp() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_esp() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_esp() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + if self.asm._is_asmgcc(): + from rpython.memory.gctransform import asmgcroot + self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + assert self.stack_max >= 3 + + def emit_raw_call(self): + self.mc.CALL(self.fnloc) + if self.callconv != FFI_DEFAULT_ABI: + self.current_esp += self._fix_stdcall(self.callconv) + + def subtract_esp_aligned(self, count): + if count > 0: + align = align_stack_words(count) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) + + def restore_esp(self, target_esp=0): + if self.current_esp != target_esp: + self.mc.ADD_ri(esp.value, target_esp - self.current_esp) + self.current_esp = target_esp + + def load_result(self): + """Overridden in CallBuilder32 and CallBuilder64""" + if self.ressize == 0: + return # void result + # use the code in load_from_mem to do the zero- or sign-extension + srcloc = self.tmpresloc + if srcloc is None: + if self.restype == FLOAT: + srcloc = xmm0 + else: + srcloc = eax + if self.ressize >= WORD and self.resloc is srcloc: + return # no need for any MOV + if self.ressize == 1 and isinstance(srcloc, RegLoc): + srcloc = srcloc.lowest8bits() + self.asm.load_from_mem(self.resloc, srcloc, + imm(self.ressize), imm(self.ressign)) + + def push_gcmap(self): + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just before, ignoring the return + # value eax, if necessary + assert not self.is_call_release_gil + self.change_extra_stack_depth = (self.current_esp != 0) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, -self.current_esp) + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, 0) + self.asm.pop_gcmap(self.mc) + + def call_releasegil_addr_and_move_real_arguments(self): + initial_esp = self.current_esp + self.save_register_arguments() + # + if not self.asm._is_asmgcc(): + # the helper takes no argument + self.change_extra_stack_depth = False + else: + from rpython.memory.gctransform import asmgcroot + # build a 'css' structure on the stack: 2 words for the linkage, + # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a + # total size of JIT_USE_WORDS. This structure is found at + # [ESP+css]. + css = -self.current_esp + ( + WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS)) + assert css >= 2 * WORD + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Save the "return address": we pretend that it's css + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) # LEA reg, [css] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg + # Set up jf_extra_stack_depth to pretend that the return address + # was at css, and so our stack frame is supposedly shorter by + # (PASS_ON_MY_FRAME-JIT_USE_WORDS+1) words + delta = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + 1 + self.change_extra_stack_depth = True + self.asm.set_extra_stack_depth(self.mc, -delta * WORD) + # Call the closestack() function (also releasing the GIL) + # with 'reg' as argument + if IS_X86_32: + self.subtract_esp_aligned(1) + self.mc.MOV_sr(0, reg.value) + #else: + # on x86_64, reg is edi so that it is already correct + # + self.mc.CALL(imm(self.asm.releasegil_addr)) + # + if not we_are_translated(): # for testing: we should not access + self.mc.ADD(ebp, imm(1)) # ebp any more + # + self.restore_register_arguments() + self.restore_esp(initial_esp) + + def save_register_arguments(self): + """Overridden in CallBuilder64""" + + def restore_register_arguments(self): + """Overridden in CallBuilder64""" + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got (in eax/eax+edx/st(0)/xmm0) + self.save_result_value() + # call the reopenstack() function (also reacquiring the GIL) + if not self.asm._is_asmgcc(): + css = 0 # the helper takes no argument + else: + from rpython.memory.gctransform import asmgcroot + css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) + if IS_X86_32: + self.mc.MOV_sr(0, reg.value) + # + self.mc.CALL(imm(self.asm.reacqgil_addr)) + # + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB(ebp, imm(1)) # ebp again + # + # Now that we required the GIL, we can reload a possibly modified ebp + if self.asm._is_asmgcc(): + # special-case: reload ebp from the css + from rpython.memory.gctransform import asmgcroot + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_rs(ebp.value, index_of_ebp) # MOV EBP, [css.ebp] + #else: + # for shadowstack, done for us by _reload_frame_if_necessary() + + def save_result_value(self): + """Overridden in CallBuilder32 and CallBuilder64""" + raise NotImplementedError + + +class CallBuilder32(AbstractCallBuilder): + + def prepare_arguments(self): + arglocs = self.arglocs + stack_depth = 0 + n = len(arglocs) + for i in range(n): + loc = arglocs[i] + stack_depth += loc.get_width() // WORD + self.subtract_esp_aligned(stack_depth - self.stack_max) + # + p = 0 + for i in range(n): + loc = arglocs[i] + if isinstance(loc, RegLoc): + if loc.is_xmm: + self.mc.MOVSD_sx(p, loc.value) + else: + self.mc.MOV_sr(p, loc.value) + p += loc.get_width() + p = 0 + for i in range(n): + loc = arglocs[i] + if not isinstance(loc, RegLoc): + if loc.get_width() == 8: + self.mc.MOVSD(xmm0, loc) + self.mc.MOVSD_sx(p, xmm0.value) + elif isinstance(loc, ImmedLoc): + self.mc.MOV_si(p, loc.value) + else: + self.mc.MOV(eax, loc) + self.mc.MOV_sr(p, eax.value) + p += loc.get_width() + self.total_stack_used_by_arguments = p + # + if not self.fnloc_is_immediate: # the last "argument" pushed above + self.fnloc = RawEspLoc(p - WORD, INT) + + + def _fix_stdcall(self, callconv): + from rpython.rlib.clibffi import FFI_STDCALL + assert callconv == FFI_STDCALL + return self.total_stack_used_by_arguments + + def load_result(self): + resloc = self.resloc + if resloc is not None and resloc.is_float(): + # a float or a long long return + if self.tmpresloc is None: + if self.restype == 'L': # long long + # move eax/edx -> xmm0 + self.mc.MOVD_xr(resloc.value^1, edx.value) + self.mc.MOVD_xr(resloc.value, eax.value) + self.mc.PUNPCKLDQ_xx(resloc.value, resloc.value^1) + else: + # float: we have to go via the stack + self.mc.FSTPL_s(0) + self.mc.MOVSD_xs(resloc.value, 0) + else: + self.mc.MOVSD(resloc, self.tmpresloc) + # + elif self.restype == 'S': + # singlefloat return: must convert ST(0) to a 32-bit singlefloat + # and load it into self.resloc. mess mess mess + if self.tmpresloc is None: + self.mc.FSTPS_s(0) + self.mc.MOV_rs(resloc.value, 0) + else: + self.mc.MOV(resloc, self.tmpresloc) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP+4]. We use "+4" + # in order to leave the word at [ESP+0] free, in case it's needed + if self.ressize == 0: # void return + return + if self.resloc.is_float(): + # a float or a long long return + self.tmpresloc = RawEspLoc(4, FLOAT) + if self.restype == 'L': + self.mc.MOV_sr(4, eax.value) # long long + self.mc.MOV_sr(8, edx.value) + else: + self.mc.FSTPL_s(4) # float return + else: + self.tmpresloc = RawEspLoc(4, INT) + if self.restype == 'S': + self.mc.FSTPS_s(4) + else: + assert self.restype == INT + assert self.ressize <= WORD + self.mc.MOV_sr(4, eax.value) + + +class CallBuilder64(AbstractCallBuilder): + + ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] + ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + DONT_MOVE_GPR = [] + _ALL_CALLEE_SAVE_GPR = [ebx, r12, r13, r14, r15] + + next_arg_gpr = 0 + next_arg_xmm = 0 + + def _unused_gpr(self, hint): + i = self.next_arg_gpr + self.next_arg_gpr = i + 1 + try: + res = self.ARGUMENTS_GPR[i] + except IndexError: + return None + if hint in self.DONT_MOVE_GPR: + self.ARGUMENTS_GPR[i] = hint + res = hint + return res + + def _unused_xmm(self): + i = self.next_arg_xmm + self.next_arg_xmm = i + 1 + try: + return self.ARGUMENTS_XMM[i] + except IndexError: + return None + + def _permute_to_prefer_unused_registers(self, lst): + # permute 'lst' so that it starts with registers that are not + # in 'self.already_used', and ends with registers that are. + N = len(lst) + i = 0 + while i < N: + reg = lst[i] + if reg in self.already_used: + # move this reg to the end, and decrement N + N -= 1 + assert N >= i + lst[N], lst[i] = lst[i], lst[N] + else: + i += 1 + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + # We have to copy the arguments around a bit more in this mode, + # but on the other hand we don't need prepare_arguments() moving + # them in precisely the final registers. Here we look around for + # unused registers that may be more likely usable. + from rpython.jit.backend.x86.regalloc import X86_64_RegisterManager + from rpython.jit.backend.x86.regalloc import X86_64_XMMRegisterManager + self.already_used = {} + for loc in self.arglocs: + self.already_used[loc] = None + # + lst = X86_64_RegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + # + extra = [] + for reg in self.asm._regalloc.rm.free_regs: + if (reg not in self.already_used and + reg in self._ALL_CALLEE_SAVE_GPR): + extra.append(reg) + self.free_callee_save_gprs = extra + lst = extra + lst + # + self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] + self.DONT_MOVE_GPR = self._ALL_CALLEE_SAVE_GPR + # + lst = X86_64_XMMRegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + self.ARGUMENTS_XMM = lst[:len(self.ARGUMENTS_XMM)] + + def prepare_arguments(self): + src_locs = [] + dst_locs = [] + xmm_src_locs = [] + xmm_dst_locs = [] + singlefloats = None + + arglocs = self.arglocs + argtypes = self.argtypes + + on_stack = 0 + for i in range(len(arglocs)): + loc = arglocs[i] + if loc.is_float(): + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, FLOAT) + on_stack += 1 + xmm_src_locs.append(loc) + xmm_dst_locs.append(tgt) + elif i < len(argtypes) and argtypes[i] == 'S': + # Singlefloat argument + if singlefloats is None: + singlefloats = [] + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + singlefloats.append((loc, tgt)) + else: + tgt = self._unused_gpr(hint=loc) + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + src_locs.append(loc) + dst_locs.append(tgt) + + if not self.fnloc_is_immediate: + self.fnloc = dst_locs[-1] # the last "argument" prepared above + + if not we_are_translated(): # assert that we got the right stack depth + floats = 0 + for i in range(len(arglocs)): + arg = arglocs[i] + if arg.is_float() or (i < len(argtypes) and argtypes[i]=='S'): + floats += 1 + all_args = len(arglocs) + stack_depth = (max(all_args - floats - len(self.ARGUMENTS_GPR), 0) + + max(floats - len(self.ARGUMENTS_XMM), 0)) + assert stack_depth == on_stack + + self.subtract_esp_aligned(on_stack - self.stack_max) + + # Handle register arguments: first remap the xmm arguments + remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, + X86_64_XMM_SCRATCH_REG) + # Load the singlefloat arguments from main regs or stack to xmm regs + if singlefloats is not None: + for src, dst in singlefloats: + if isinstance(dst, RawEspLoc): + # XXX too much special logic + if isinstance(src, RawEbpLoc): + self.mc.MOV32(X86_64_SCRATCH_REG, src) + self.mc.MOV32(dst, X86_64_SCRATCH_REG) + else: + self.mc.MOV32(dst, src) + continue + if isinstance(src, ImmedLoc): + self.mc.MOV(X86_64_SCRATCH_REG, src) + src = X86_64_SCRATCH_REG + self.mc.MOVD(dst, src) + # Finally remap the arguments in the main regs + remap_frame_layout(self.asm, src_locs, dst_locs, X86_64_SCRATCH_REG) + + + def _fix_stdcall(self, callconv): + assert 0 # should not occur on 64-bit + + def load_result(self): + if self.restype == 'S' and self.tmpresloc is None: + # singlefloat return: use MOVD to load the target register + # from the lower 32 bits of XMM0 + self.mc.MOVD(self.resloc, xmm0) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP]. + if self.ressize == 0: # void return + return + # + if self.restype == FLOAT: # and not 'S' + self.mc.MOVSD_sx(0, xmm0.value) + self.tmpresloc = RawEspLoc(0, FLOAT) + return + # + if len(self.free_callee_save_gprs) == 0: + self.tmpresloc = RawEspLoc(0, INT) + else: + self.tmpresloc = self.free_callee_save_gprs[0] + # + if self.restype == 'S': + # singlefloat return: use MOVD to store the lower 32 bits + # of XMM0 into the tmpresloc (register or [ESP]) + self.mc.MOVD(self.tmpresloc, xmm0) + else: + assert self.restype == INT + self.mc.MOV(self.tmpresloc, eax) + + def save_register_arguments(self): + # Save the argument registers, which are given by self.ARGUMENTS_xxx. + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + n_saved_regs = n_gpr + n_xmm + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] in self._ALL_CALLEE_SAVE_GPR: + n_saved_regs -= 1 # don't need to save it + self.subtract_esp_aligned(n_saved_regs) + # + n = 0 + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_sr(n * WORD, self.ARGUMENTS_GPR[i].value) + n += 1 + for i in range(n_xmm): + self.mc.MOVSD_sx(n * WORD, self.ARGUMENTS_XMM[i].value) + n += 1 + assert n == n_saved_regs + self.n_saved_regs = n_saved_regs + + def restore_register_arguments(self): + # Restore the saved values into the *real* registers used for calls + # --- which are not self.ARGUMENTS_xxx! + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + # + n = 0 + for i in range(n_gpr): + tgtvalue = CallBuilder64.ARGUMENTS_GPR[i].value + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_rs(tgtvalue, n * WORD) + n += 1 + else: + self.mc.MOV_rr(tgtvalue, self.ARGUMENTS_GPR[i].value) + for i in range(n_xmm): + self.mc.MOVSD_xs(CallBuilder64.ARGUMENTS_XMM[i].value, n * WORD) + n += 1 + assert n == self.n_saved_regs + # + if isinstance(self.fnloc, RegLoc): # fix this register + self.fnloc = CallBuilder64.ARGUMENTS_GPR[n_gpr - 1] + + +if IS_X86_32: + CallBuilder = CallBuilder32 +if IS_X86_64: + CallBuilder = CallBuilder64 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -79,26 +79,14 @@ rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), adr)[1] = y return ConstFloatLoc(adr) - def after_call(self, v): - # the result is stored in st0, but we don't have this around, - # so genop_call will move it to some frame location immediately - # after the call - return self.frame_manager.loc(v) + def call_result_location(self, v): + return xmm0 class X86_64_XMMRegisterManager(X86XMMRegisterManager): # xmm15 reserved for scratch use all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14] save_around_call_regs = all_regs - def call_result_location(self, v): - return xmm0 - - def after_call(self, v): - # We use RegisterManager's implementation, since X86XMMRegisterManager - # places the result on the stack, which we don't need to do when the - # calling convention places the result in xmm0 - return RegisterManager.after_call(self, v) - class X86FrameManager(FrameManager): def __init__(self, base_ofs): FrameManager.__init__(self) @@ -799,14 +787,6 @@ self._consider_call(op, guard_op) def consider_call_release_gil(self, op, guard_op): - # We spill the arguments to the stack, because we need to do 3 calls: - # call_release_gil(), the_real_c_function(), and call_reacquire_gil(). - # The arguments are used on the second call only. XXX we assume - # that the XMM arguments won't be modified by call_release_gil(). - for i in range(op.numargs()): - loc = self.loc(op.getarg(i)) - if loc in self.rm.save_around_call_regs: - self.rm.force_spill_var(op.getarg(i)) assert guard_op is not None self._consider_call(op, guard_op) @@ -1151,9 +1131,8 @@ # call memcpy() self.rm.before_call() self.xrm.before_call() - self.assembler._emit_call(imm(self.assembler.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.assembler.simple_call_no_collect(imm(self.assembler.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) self.rm.possibly_free_var(length_box) self.rm.possibly_free_var(dstaddr_box) self.rm.possibly_free_var(srcaddr_box) diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -553,6 +553,7 @@ CALL_l = insn('\xE8', relative(1)) CALL_r = insn(rex_nw, '\xFF', register(1), chr(0xC0 | (2<<3))) CALL_b = insn('\xFF', orbyte(2<<3), stack_bp(1)) + CALL_s = insn('\xFF', orbyte(2<<3), stack_sp(1)) # XXX: Only here for testing purposes..."as" happens the encode the # registers in the opposite order that we would otherwise do in a @@ -583,6 +584,7 @@ # x87 instructions FSTPL_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) # rffi.DOUBLE ('as' wants L??) + FSTPL_s = insn('\xDD', orbyte(3<<3), stack_sp(1)) # rffi.DOUBLE ('as' wants L??) FSTPS_s = insn('\xD9', orbyte(3<<3), stack_sp(1)) # lltype.SingleFloat # ------------------------------ Random mess ----------------------- From noreply at buildbot.pypy.org Tue May 21 00:28:36 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 21 May 2013 00:28:36 +0200 (CEST) Subject: [pypy-commit] pypy py3k: skip when _testcapi ImportErrors Message-ID: <20130520222836.EE9BD1C0698@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64370:4214388aa89b Date: 2013-05-20 12:30 -0700 http://bitbucket.org/pypy/pypy/changeset/4214388aa89b/ Log: skip when _testcapi ImportErrors diff --git a/lib-python/3/importlib/test/extension/test_finder.py b/lib-python/3/importlib/test/extension/test_finder.py --- a/lib-python/3/importlib/test/extension/test_finder.py +++ b/lib-python/3/importlib/test/extension/test_finder.py @@ -8,6 +8,7 @@ """Test the finder for extension modules.""" + @util.skip_unless__testcapi def find_module(self, fullname): importer = _bootstrap._FileFinder(util.PATH, _bootstrap._ExtensionFinderDetails()) diff --git a/lib-python/3/importlib/test/extension/test_loader.py b/lib-python/3/importlib/test/extension/test_loader.py --- a/lib-python/3/importlib/test/extension/test_loader.py +++ b/lib-python/3/importlib/test/extension/test_loader.py @@ -11,6 +11,7 @@ """Test load_module() for extension modules.""" + @ext_util.skip_unless__testcapi def load_module(self, fullname): loader = _bootstrap._ExtensionFileLoader(ext_util.NAME, ext_util.FILEPATH) diff --git a/lib-python/3/importlib/test/extension/util.py b/lib-python/3/importlib/test/extension/util.py --- a/lib-python/3/importlib/test/extension/util.py +++ b/lib-python/3/importlib/test/extension/util.py @@ -1,6 +1,7 @@ import imp import os import sys +import unittest PATH = None EXT = None @@ -27,3 +28,8 @@ except StopIteration: pass del _file_exts + + +def skip_unless__testcapi(func): + msg = "Requires the CPython C Extension API ({!r} module)".format(NAME) + return unittest.skipUnless(PATH, msg)(func) From noreply at buildbot.pypy.org Tue May 21 00:28:38 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 21 May 2013 00:28:38 +0200 (CEST) Subject: [pypy-commit] pypy py3k: updates Message-ID: <20130520222838.2AB001C131B@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64371:a411d3657be1 Date: 2013-05-20 15:27 -0700 http://bitbucket.org/pypy/pypy/changeset/a411d3657be1/ Log: updates diff --git a/pypy/TODO b/pypy/TODO --- a/pypy/TODO +++ b/pypy/TODO @@ -1,18 +1,5 @@ TODO for the python3 test suite: -* test_decimal: - In py3k, hash(-1) is now -2 (probably as an optimisation, because - PyObject_Hash() return -1 on exception). - It's important to be compatible, since other classes like Decimal - and Fractions have to return the same hashes for equivalent values. - IOW: int.__hash__ is part of the Python language specification. - The py3k-newhash branch has an updated float hash, int's hash is - still pending - -* test_fractions -* test_numeric_tower - float.__hash__ has changed as well (fixed on py3k-newhash) - * test_float nan = float('nan'); assert nan in [nan] This has always been true in CPython, it is now guaranteed that the @@ -25,11 +12,6 @@ Needs bytes/str changes. Probably easy. Work for this has begun on py3k-memoryview (by mjacob) -* test_peepholer - 'a in [1,2,3]' is rewritten as 'a in (1, 2, 3)' - and the tuple is a prebuilt constant. - Likewise, a set becomes a frozenset. - * test_pep263 Tracebacks should be able to print unicode source code. This is really due to the tokenizer not being fully unicode aware. The @@ -45,16 +27,8 @@ own-tests: * module/test_lib_pypy - These crash the buildbots (via SyntaxErrors): some were really made - to run under Python 2.x - -* interpreter.test.test_zzpickle_and_slow test_pickle_frame_with_exc - Due to W_OperationError not being pickleable. Probably be best for - the ExceptionHandlerBlock to push *sys.exc_info() instead of it, - like CPython does - -* module.bz2.test.test_bz2_file test_open_non_existent - Some really obscure GC stuff + These crash the buildbots (via SyntaxErrors): others were really + made to run under Python 2.x and so simply fail * module.cpyext.test.test_structseq test_StructSeq structseq now subclasses tuple on py3, which breaks how From noreply at buildbot.pypy.org Tue May 21 09:48:03 2013 From: noreply at buildbot.pypy.org (bivab) Date: Tue, 21 May 2013 09:48:03 +0200 (CEST) Subject: [pypy-commit] pypy default: fix translation Message-ID: <20130521074803.C0D391C0217@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64372:e50833e88c65 Date: 2013-05-21 07:46 +0000 http://bitbucket.org/pypy/pypy/changeset/e50833e88c65/ Log: fix translation diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -365,7 +365,7 @@ modules = [name for name in modules if name not in essential_modules] if config.translation.platform == 'arm' and '_continuation' in modules: - del modules[modules.find('_continuation')] + modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): From noreply at buildbot.pypy.org Tue May 21 10:10:45 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 10:10:45 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Manual merge of the "doc" directory from trunk. Message-ID: <20130521081045.709A11C0217@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64373:f66246c46ca3 Date: 2013-05-21 10:00 +0200 http://bitbucket.org/pypy/pypy/changeset/f66246c46ca3/ Log: Manual merge of the "doc" directory from trunk. diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0-beta1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -105,7 +105,7 @@ $ ./pypy-c Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``RPython magically makes you rich and famous (says so on the tin)'' @@ -235,7 +235,7 @@ the ``bin/pypy`` executable. To install PyPy system wide on unix-like systems, it is recommended to put the -whole hierarchy alone (e.g. in ``/opt/pypy2.0-beta1``) and put a symlink to the +whole hierarchy alone (e.g. in ``/opt/pypy2.0``) and put a symlink to the ``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -53,10 +53,10 @@ PyPy is ready to be executed as soon as you unpack the tarball or the zip file, with no need to install it in any specific location:: - $ tar xf pypy-2.0-beta1-linux.tar.bz2 - $ ./pypy-2.0-beta1/bin/pypy + $ tar xf pypy-2.0.tar.bz2 + $ ./pypy-2.0/bin/pypy Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``PyPy is an exciting technology that lets you to write fast, portable, multi-platform interpreters with less @@ -75,14 +75,14 @@ $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.0-beta1/bin/pypy distribute_setup.py + $ ./pypy-2.0/bin/pypy distribute_setup.py - $ ./pypy-2.0-beta1/bin/pypy get-pip.py + $ ./pypy-2.0/bin/pypy get-pip.py - $ ./pypy-2.0-beta1/bin/pip install pygments # for example + $ ./pypy-2.0/bin/pip install pygments # for example -3rd party libraries will be installed in ``pypy-2.0-beta1/site-packages``, and -the scripts in ``pypy-2.0-beta1/bin``. +3rd party libraries will be installed in ``pypy-2.0/site-packages``, and +the scripts in ``pypy-2.0/bin``. Installing using virtualenv --------------------------- diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0 beta 2`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0 beta 2`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst --- a/pypy/doc/release-2.0.0.rst +++ b/pypy/doc/release-2.0.0.rst @@ -4,6 +4,8 @@ We're pleased to announce PyPy 2.0. This is a stable release that brings a swath of bugfixes, small performance improvements and compatibility fixes. +PyPy 2.0 is a big step for us and we hope in the future we'll be able to +provide stable releases more often. You can download the PyPy 2.0 release here: @@ -19,6 +21,10 @@ .. _`cffi`: http://cffi.readthedocs.org +If you're using PyPy for anything, it would help us immensely if you fill out +the following survey: http://bit.ly/pypysurvey This is for the developers +eyes and we will not make any information public without your agreement. + What is PyPy? ============= @@ -28,8 +34,8 @@ This release supports x86 machines running Linux 32/64, Mac OS X 64 or Windows 32. Windows 64 work is still stalling, we would welcome a volunteer -to handle that. ARM support is on the way and we're expecting to release -an alpha ARM version shortly. +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. .. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org @@ -54,6 +60,10 @@ * A lot of stability issues fixed. +* Refactoring much of the numpypy array classes, which resulted in removal of + lazy expression evaluation. On the other hand, we now have more complete + dtype support and support more array attributes. + .. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ .. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks 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 @@ -5,3 +5,20 @@ .. this is a revision shortly after release-2.0 .. startrev: a13c07067613 +.. branch: numpy-pickle +Pickling of numpy arrays and dtypes (including record dtypes) + +.. branch: remove-array-smm +Remove multimethods in the arraymodule + +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback + +.. branch: remove-set-smm +Remove multi-methods on sets + +.. branch: numpy-subarrays +Implement subarrays for numpy + +.. branch: remove-dict-smm +Remove multi-methods on dict From noreply at buildbot.pypy.org Tue May 21 10:10:46 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 10:10:46 +0200 (CEST) Subject: [pypy-commit] pypy release-2.0.x: Added tag release-2.0.2 for changeset f66246c46ca3 Message-ID: <20130521081046.B684F1C0217@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: release-2.0.x Changeset: r64374:5acfe049a5b0 Date: 2013-05-21 10:01 +0200 http://bitbucket.org/pypy/pypy/changeset/5acfe049a5b0/ Log: Added tag release-2.0.2 for changeset f66246c46ca3 diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -5,3 +5,4 @@ 07e08e9c885ca67d89bcc304e45a32346daea2fa release-2.0-beta-1 b9c3566aa0170aaa736db0491d542c309ec7a5dc release-2.0.0 3b53c1137d001c9292c47006c1418e8b895c8941 release-2.0.1 +f66246c46ca30b26a5c73e4cc95dd6235c966b8f release-2.0.2 From noreply at buildbot.pypy.org Tue May 21 10:26:40 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 10:26:40 +0200 (CEST) Subject: [pypy-commit] pypy default: Update version numbers Message-ID: <20130521082640.4FAC71C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64375:c386fd12ea7a Date: 2013-05-21 10:10 +0200 http://bitbucket.org/pypy/pypy/changeset/c386fd12ea7a/ Log: Update version numbers diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0.1`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0.1`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html From noreply at buildbot.pypy.org Tue May 21 10:26:41 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 10:26:41 +0200 (CEST) Subject: [pypy-commit] pypy default: Add release announcement. Message-ID: <20130521082641.BBB1A1C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64376:75ca8e0c9c51 Date: 2013-05-21 10:25 +0200 http://bitbucket.org/pypy/pypy/changeset/75ca8e0c9c51/ Log: Add release announcement. diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,41 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash used to +occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +Cheers, +arigo et. al. for the PyPy team From noreply at buildbot.pypy.org Tue May 21 10:35:45 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 10:35:45 +0200 (CEST) Subject: [pypy-commit] pypy default: Add a link Message-ID: <20130521083545.2AD811C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64377:07fb30f3ae69 Date: 2013-05-21 10:35 +0200 http://bitbucket.org/pypy/pypy/changeset/07fb30f3ae69/ Log: Add a link diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst --- a/pypy/doc/release-2.0.2.rst +++ b/pypy/doc/release-2.0.2.rst @@ -28,8 +28,8 @@ Highlights ========== -This release contains only the fix described above. A crash used to -occur if all these conditions were true: +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: - your program is multithreaded; @@ -37,5 +37,10 @@ - it uses ctypes or cffi to issue external calls to C functions. +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + Cheers, arigo et. al. for the PyPy team From noreply at buildbot.pypy.org Tue May 21 10:36:25 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 10:36:25 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Update to point to 2.0.2. Message-ID: <20130521083625.928541C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r437:12bba861cdd6 Date: 2013-05-21 10:36 +0200 http://bitbucket.org/pypy/pypy.org/changeset/12bba861cdd6/ Log: Update to point to 2.0.2. diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -50,8 +50,10 @@ performance improvements. Note that the OS X nightly builds (but not the release) are slightly miscompiled due to buildslave being old. Contributions are welcomed.

    -

    Here are the binaries of the current release — PyPy 2.0.1 — -(what's new in PyPy 2.0? and fixes of PyPy 2.0.1) for x86 Linux, Mac OS/X, Windows. The support for ARM in 2.0 and 2.0.1 is alpha-level.

    +

    Here are the binaries of the current release — PyPy 2.0.2 — +(what's new in PyPy 2.0?, fixes of PyPy 2.0.1, fix of PyPy +2.0.2) for x86 Linux, Mac OS/X, Windows. The support for ARM in +2.0(.2) is alpha-level.

    • Download
      • Default (with a JIT Compiler)
      • @@ -69,11 +71,11 @@ x86 CPUs that have the SSE2 instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain stackless extensions, like greenlets. -(This is the official release 2.0.1; +(This is the official release 2.0.2; for the most up-to-date version see below.)

    -

    2.0.1

    +

    2.0.2

    Note that Linux binaries are dynamically linked, as is usual, and thus might not be usable due to the sad story of linux binary compatibility. This means that Linux binaries are only usable on the distributions written next to @@ -87,13 +89,13 @@ in production due to potential future security issues), you can find the older 32bit Linux and 64bit Linux at an earlier time of release 2.0.

    If your CPU is really old, it may not have SSE2. In this case, you need to translate yourself with the option --jit-backend=x86-without-sse2.

    @@ -140,7 +142,7 @@ uncompressed, they run in-place. For now you can uncompress them either somewhere in your home directory or, say, in /opt, and if you want, put a symlink from somewhere like -/usr/local/bin/pypy to /path/to/pypy-2.0.1/bin/pypy. Do +/usr/local/bin/pypy to /path/to/pypy-2.0.2/bin/pypy. Do not move or copy the executable pypy outside the tree – put a symlink to it, otherwise it will not find its libraries.

    @@ -150,8 +152,8 @@
  • Get the source code. The following packages contain the source at the same revision as the above binaries:

    Or you can checkout the current trunk using Mercurial (the trunk usually works and is of course more up-to-date):

    @@ -218,28 +220,28 @@

    Checksums

    Here are the checksums for each of the downloads (md5 and sha1):

    -5c11d727579443d0834caadb4dfe53e3  pypy-2.0.1-linux64.tar.bz2
    -8d11952e0356ea751321e7d2a1d4f17a  pypy-2.0.1-linux.tar.bz2
    +51ac0aa37a8255acbc71eca23ea29609  pypy-2.0.2-linux.tar.bz2
    +9d9f512ab2f114bfb4f165c71181a511  pypy-2.0.2-linux64.tar.bz2
     e666450bcfbd936b016a2dd7312f9853  pypy-2.0.1-osx64.tar.bz2
    -4c40b19ea1ec5c8c8c2a1f94f59bdf02  pypy-2.0.1-win32.zip
    +3e51dce7ecfc8fb069d65d95e8de6fb2  pypy-2.0.2-win32.zip
     b9c36b99296c85a590c3e480b05d5a13  pypy-2.0-alpha-arm-armel.tar.bz2
     2565ce68b4032eb306d998e722495694  pypy-2.0-alpha-arm-armhf.tar.bz2
     b39d98de75f4948bfd2d606a8263ac1f  pypy-upstream_2.0~alpha+arm_armhf.deb
     2c9f0054f3b93a6473f10be35277825a  pypy-1.8-sandbox-linux64.tar.bz2
     009c970b5fa75754ae4c32a5d108a8d4  pypy-1.8-sandbox-linux.tar.bz2
    -34072be1eeb63f9d37cf387e58aae81d  pypy-2.0.1-src.tar.bz2
    -ea8764e387e74c62e898536a862c66c7  pypy-2.0.1-src.zip
    -cbcd60a78d90caca98fdc2562fc7fcbe76c6e699  pypy-2.0.1-linux64.tar.bz2
    -a909742d41fb540d9c12ce010bdc7f9e19353fcc  pypy-2.0.1-linux.tar.bz2
    +c26662e348159b460057548ddaf35333  pypy-2.0.2-src.tar.bz2
    +4da8c6dfbe7d2044d892c9bc20a649b0  pypy-2.0.2-src.zip
    +c8ec9872fe823f4f7574620a5303c5b0f4576393  pypy-2.0.2-linux.tar.bz2
    +3d045ab7871bc478604cf1f16a3c4ec46c950e70  pypy-2.0.2-linux64.tar.bz2
     811fd377ab2eda9233a0c34340f981f9aba1ba9a  pypy-2.0.1-osx64.tar.bz2
    -0fa90e240648e628c6ac3dfed467f88563897a2a  pypy-2.0.1-win32.zip
    +4ae8a35dd8043312199aacdbe3abb1a666fc9312  pypy-2.0.2-win32.zip
     dc09a293b85ab4f0032f6943815aaf5bbbceb645  pypy-2.0-alpha-arm-armel.tar.bz2
     0971c4b668bfd2fcd52aa35087aa995e03bd5842  pypy-2.0-alpha-arm-armhf.tar.bz2
     91910eb654ffbe0509bec2a7aeb460984acf8d82  pypy-upstream_2.0~alpha+arm_armhf.deb
     895aaf7bba5787dd30adda5cc0e0e7fc297c0ca7  pypy-1.8-sandbox-linux64.tar.bz2
     be94460bed8b2682880495435c309b6611ae2c31  pypy-1.8-sandbox-linux.tar.bz2
    -8bc02e922e758048f294a5c6848f97125b0b557f  pypy-2.0.1-src.tar.bz2
    -61b7326c1379af0914b81936bc057dfec0292458  pypy-2.0.1-src.zip
    +49e0af6e57bd2738cd3eb09c3246c69a3dc01319  pypy-2.0.2-src.tar.bz2
    +bfb23e7ea17cf9f2e9bf7f2211c6df3aeeafed32  pypy-2.0.2-src.zip
     
  • diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -45,7 +45,7 @@

    Features

    -

    PyPy 2.0.1 implements Python 2.7.3 and runs on Intel +

    PyPy 2.0.2 implements Python 2.7.3 and runs on Intel x86 (IA-32) , x86_64 and ARM platforms (alpha), with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -63,7 +63,7 @@

  • As well as other features.
  • -

    Download and try out the PyPy release 2.0.1!

    +

    Download and try out the PyPy release 2.0.2!

    Want to know more? A good place to start is our detailed speed and compatibility reports!

    diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -14,11 +14,14 @@ (but not the release) are slightly miscompiled due to buildslave being old. Contributions are welcomed**. -Here are the binaries of the current release — **PyPy 2.0.1** — -(`what's new in PyPy 2.0?`_ and `fixes of PyPy 2.0.1`_) for x86 Linux, Mac OS/X, Windows. The support for ARM in 2.0 and 2.0.1 is alpha-level. +Here are the binaries of the current release — **PyPy 2.0.2** — +(`what's new in PyPy 2.0?`_, `fixes of PyPy 2.0.1`_, `fix of PyPy +2.0.2`_) for x86 Linux, Mac OS/X, Windows. The support for ARM in +2.0(.2) is alpha-level. .. _what's new in PyPy 2.0?: http://doc.pypy.org/en/latest/release-2.0.0.html .. _fixes of PyPy 2.0.1: http://doc.pypy.org/en/latest/release-2.0.1.html +.. _fix of PyPy 2.0.2: http://doc.pypy.org/en/latest/release-2.0.2.html .. class:: download_menu @@ -42,10 +45,10 @@ x86 CPUs that have the SSE2_ instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain `stackless`_ extensions, like `greenlets`_. -(This is the official release 2.0.1; +(This is the official release 2.0.2; for the most up-to-date version see below.) -2.0.1 +2.0.2 ----- Note that Linux binaries are dynamically linked, as is usual, and thus might @@ -73,19 +76,19 @@ * `Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS)`__ (see ``[1]`` below) * `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ (see ``[1]`` below) -* `Mac OS/X binary (64bit)`__ +* `Mac OS/X binary (64bit)`__ (STILL POINTS TO 2.0.1, UPDATED SOON) * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) * `Source (tar.bz2)`__ * `Source (zip)`__ -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-linux.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-linux64.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux64.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-osx64.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-win32.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-win32.zip .. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-src.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-src.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.zip If your CPU is really old, it may not have SSE2. In this case, you need to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. @@ -147,7 +150,7 @@ uncompressed, they run in-place. For now you can uncompress them either somewhere in your home directory or, say, in ``/opt``, and if you want, put a symlink from somewhere like -``/usr/local/bin/pypy`` to ``/path/to/pypy-2.0.1/bin/pypy``. Do +``/usr/local/bin/pypy`` to ``/path/to/pypy-2.0.2/bin/pypy``. Do not move or copy the executable ``pypy`` outside the tree --- put a symlink to it, otherwise it will not find its libraries. @@ -160,11 +163,11 @@ 1. Get the source code. The following packages contain the source at the same revision as the above binaries: - * `pypy-2.0.1-src.tar.bz2`__ (sources, Unix line endings) - * `pypy-2.0.1-src.zip`__ (sources, Unix line endings too, sorry) + * `pypy-2.0.2-src.tar.bz2`__ (sources, Unix line endings) + * `pypy-2.0.2-src.zip`__ (sources, Unix line endings too, sorry) - .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-src.tar.bz2 - .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-src.zip + .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.tar.bz2 + .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.zip Or you can checkout the current trunk using Mercurial_ (the trunk usually works and is of course more up-to-date):: @@ -239,26 +242,26 @@ Here are the checksums for each of the downloads (md5 and sha1):: - 5c11d727579443d0834caadb4dfe53e3 pypy-2.0.1-linux64.tar.bz2 - 8d11952e0356ea751321e7d2a1d4f17a pypy-2.0.1-linux.tar.bz2 + 51ac0aa37a8255acbc71eca23ea29609 pypy-2.0.2-linux.tar.bz2 + 9d9f512ab2f114bfb4f165c71181a511 pypy-2.0.2-linux64.tar.bz2 e666450bcfbd936b016a2dd7312f9853 pypy-2.0.1-osx64.tar.bz2 - 4c40b19ea1ec5c8c8c2a1f94f59bdf02 pypy-2.0.1-win32.zip + 3e51dce7ecfc8fb069d65d95e8de6fb2 pypy-2.0.2-win32.zip b9c36b99296c85a590c3e480b05d5a13 pypy-2.0-alpha-arm-armel.tar.bz2 2565ce68b4032eb306d998e722495694 pypy-2.0-alpha-arm-armhf.tar.bz2 b39d98de75f4948bfd2d606a8263ac1f pypy-upstream_2.0~alpha+arm_armhf.deb 2c9f0054f3b93a6473f10be35277825a pypy-1.8-sandbox-linux64.tar.bz2 009c970b5fa75754ae4c32a5d108a8d4 pypy-1.8-sandbox-linux.tar.bz2 - 34072be1eeb63f9d37cf387e58aae81d pypy-2.0.1-src.tar.bz2 - ea8764e387e74c62e898536a862c66c7 pypy-2.0.1-src.zip + c26662e348159b460057548ddaf35333 pypy-2.0.2-src.tar.bz2 + 4da8c6dfbe7d2044d892c9bc20a649b0 pypy-2.0.2-src.zip - cbcd60a78d90caca98fdc2562fc7fcbe76c6e699 pypy-2.0.1-linux64.tar.bz2 - a909742d41fb540d9c12ce010bdc7f9e19353fcc pypy-2.0.1-linux.tar.bz2 + c8ec9872fe823f4f7574620a5303c5b0f4576393 pypy-2.0.2-linux.tar.bz2 + 3d045ab7871bc478604cf1f16a3c4ec46c950e70 pypy-2.0.2-linux64.tar.bz2 811fd377ab2eda9233a0c34340f981f9aba1ba9a pypy-2.0.1-osx64.tar.bz2 - 0fa90e240648e628c6ac3dfed467f88563897a2a pypy-2.0.1-win32.zip + 4ae8a35dd8043312199aacdbe3abb1a666fc9312 pypy-2.0.2-win32.zip dc09a293b85ab4f0032f6943815aaf5bbbceb645 pypy-2.0-alpha-arm-armel.tar.bz2 0971c4b668bfd2fcd52aa35087aa995e03bd5842 pypy-2.0-alpha-arm-armhf.tar.bz2 91910eb654ffbe0509bec2a7aeb460984acf8d82 pypy-upstream_2.0~alpha+arm_armhf.deb 895aaf7bba5787dd30adda5cc0e0e7fc297c0ca7 pypy-1.8-sandbox-linux64.tar.bz2 be94460bed8b2682880495435c309b6611ae2c31 pypy-1.8-sandbox-linux.tar.bz2 - 8bc02e922e758048f294a5c6848f97125b0b557f pypy-2.0.1-src.tar.bz2 - 61b7326c1379af0914b81936bc057dfec0292458 pypy-2.0.1-src.zip + 49e0af6e57bd2738cd3eb09c3246c69a3dc01319 pypy-2.0.2-src.tar.bz2 + bfb23e7ea17cf9f2e9bf7f2211c6df3aeeafed32 pypy-2.0.2-src.zip diff --git a/source/features.txt b/source/features.txt --- a/source/features.txt +++ b/source/features.txt @@ -6,7 +6,7 @@ PyPy features =========================================================== -**PyPy 2.0.1** implements **Python 2.7.3** and runs on Intel +**PyPy 2.0.2** implements **Python 2.7.3** and runs on Intel `x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms (alpha), with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/source/index.txt b/source/index.txt --- a/source/index.txt +++ b/source/index.txt @@ -26,7 +26,7 @@ .. class:: download -`Download and try out the PyPy release 2.0.1!`__ +`Download and try out the PyPy release 2.0.2!`__ .. __: download.html From noreply at buildbot.pypy.org Tue May 21 11:28:39 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 21 May 2013 11:28:39 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added printing capabilities to the vm-debugging plugin Message-ID: <20130521092839.18BC01C0217@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r397:ed77e03406eb Date: 2013-05-21 11:28 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/ed77e03406eb/ Log: added printing capabilities to the vm-debugging plugin diff --git a/spyvm/plugins/vmdebugging.py b/spyvm/plugins/vmdebugging.py --- a/spyvm/plugins/vmdebugging.py +++ b/spyvm/plugins/vmdebugging.py @@ -27,3 +27,10 @@ print s_frame raise Exit('Halt is not well defined when translated.') return w_rcvr + + at DebuggingPlugin.expose_primitive(unwrap_spec=[object, object]) +def debugPrint(interp, s_frame, w_rcvr, w_string): + if not isinstance(w_string, model.W_BytesObject): + raise error.PrimitiveFailedError() + print w_string.as_string() + return w_rcvr From noreply at buildbot.pypy.org Tue May 21 11:49:28 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 11:49:28 +0200 (CEST) Subject: [pypy-commit] pypy default: Update these files to include not only "import *" in sysconfig, Message-ID: <20130521094928.5A4451C0217@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64378:b5f6146ec902 Date: 2013-05-21 11:48 +0200 http://bitbucket.org/pypy/pypy/changeset/b5f6146ec902/ Log: Update these files to include not only "import *" in sysconfig, but really import all the names, including the ones that start with underscores. Might help with people that write in their setup.py things like "sysconfig._init_posix" or other completely undocumented hacks. diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp From noreply at buildbot.pypy.org Tue May 21 14:39:15 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 14:39:15 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Kill all tuple SMMs. Message-ID: <20130521123915.C00C01C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64379:8d7578543296 Date: 2013-05-21 14:32 +0200 http://bitbucket.org/pypy/pypy/changeset/8d7578543296/ Log: Kill all tuple SMMs. diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,3 +1,4 @@ +import sys from pypy.interpreter.error import OperationError from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all @@ -6,9 +7,12 @@ from rpython.rlib.rarithmetic import intmask from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std import slicetype +from pypy.objspace.std.util import negate +from pypy.objspace.std.stdtypedef import StdTypeDef from rpython.rlib.debug import make_sure_not_resized from rpython.rlib import jit from rpython.tool.sourcetools import func_with_new_name +from pypy.interpreter import gateway UNROLL_CUTOFF = 10 @@ -24,8 +28,12 @@ raise NotImplementedError +def tuple_unroll_condition(space, self, w_other): + return jit.loop_unrolling_heuristic(self, len(self.wrappeditems), UNROLL_CUTOFF) or \ + jit.loop_unrolling_heuristic(w_other, len(w_other.wrappeditems), UNROLL_CUTOFF) + + class W_TupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef _immutable_fields_ = ['wrappeditems[*]'] def __init__(w_self, wrappeditems): @@ -47,132 +55,202 @@ def getitems_copy(self): return self.wrappeditems[:] # returns a resizable list + @staticmethod + def descr_new(space, w_tupletype, w_sequence=None): + from pypy.objspace.std.tupleobject import W_TupleObject + if w_sequence is None: + tuple_w = [] + elif (space.is_w(w_tupletype, space.w_tuple) and + space.is_w(space.type(w_sequence), space.w_tuple)): + return w_sequence + else: + tuple_w = space.fixedview(w_sequence) + w_obj = space.allocate_instance(W_TupleObject, w_tupletype) + W_TupleObject.__init__(w_obj, tuple_w) + return w_obj + + def descr_repr(self, space): + items = self.wrappeditems + # XXX this is quite innefficient, still better than calling + # it via applevel + if len(items) == 1: + return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") + return space.wrap("(" + + (", ".join([space.str_w(space.repr(item)) for item in items])) + + ")") + + def descr_hash(self, space): + return space.wrap(hash_tuple(space, self.wrappeditems)) + + @jit.look_inside_iff(tuple_unroll_condition) + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_TupleObject): + return space.w_NotImplemented + items1 = self.wrappeditems + items2 = w_other.wrappeditems + lgt1 = len(items1) + lgt2 = len(items2) + if lgt1 != lgt2: + return space.w_False + for i in range(lgt1): + item1 = items1[i] + item2 = items2[i] + if not space.eq_w(item1, item2): + return space.w_False + return space.w_True + + descr_ne = negate(descr_eq) + + def _make_tuple_comparison(name): + import operator + op = getattr(operator, name) + + @jit.look_inside_iff(tuple_unroll_condition) + def compare_tuples(self, space, w_other): + if not isinstance(w_other, W_TupleObject): + return space.w_NotImplemented + items1 = self.wrappeditems + items2 = w_other.wrappeditems + ncmp = min(len(items1), len(items2)) + # Search for the first index where items are different + for p in range(ncmp): + if not space.eq_w(items1[p], items2[p]): + return getattr(space, name)(items1[p], items2[p]) + # No more items to compare -- compare sizes + return space.newbool(op(len(items1), len(items2))) + return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') + + descr_lt = _make_tuple_comparison('lt') + descr_le = _make_tuple_comparison('le') + descr_gt = _make_tuple_comparison('gt') + descr_ge = _make_tuple_comparison('ge') + + def descr_len(self, space): + result = len(self.wrappeditems) + return wrapint(space, result) + + def descr_iter(self, space): + from pypy.objspace.std import iterobject + return iterobject.W_FastTupleIterObject(self, self.wrappeditems) + + @jit.look_inside_iff(lambda self, space, w_obj: + jit.loop_unrolling_heuristic(self, len(self.wrappeditems), UNROLL_CUTOFF)) + def descr_contains(self, space, w_obj): + for w_item in self.wrappeditems: + if space.eq_w(w_item, w_obj): + return space.w_True + return space.w_False + + def descr_add(self, space, w_other): + if not isinstance(w_other, W_TupleObject): + return space.w_NotImplemented + items1 = self.wrappeditems + items2 = w_other.wrappeditems + return space.newtuple(items1 + items2) + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + raise FailedToImplement + raise + if times == 1 and space.type(self) == space.w_tuple: + return self + items = self.wrappeditems + return space.newtuple(items * times) + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + items = self.wrappeditems + length = len(items) + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = items[start] + start += step + return space.newtuple(subitems) + + # getindex_w should get a second argument space.w_IndexError, + # but that doesn't exist the first time this is called. + try: + w_IndexError = space.w_IndexError + except AttributeError: + w_IndexError = None + index = space.getindex_w(w_index, w_IndexError, "tuple index") + try: + return self.wrappeditems[index] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) + + def descr_getslice(self, space, w_start, w_stop): + length = len(self.wrappeditems) + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + return space.newtuple(self.wrappeditems[start:stop]) + + def descr_getnewargs(self, space): + return space.newtuple([space.newtuple(self.wrappeditems)]) + + def descr_count(self, space, w_obj): + """count(obj) -> number of times obj appears in the tuple""" + count = 0 + for w_item in self.wrappeditems: + if space.eq_w(w_item, w_obj): + count += 1 + return space.wrap(count) + + @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), + w_stop=gateway.WrappedDefault(sys.maxint)) + def descr_index(self, space, w_obj, w_start, w_stop): + """index(obj, [start, [stop]]) -> first index that obj appears in the + tuple + """ + length = len(self.wrappeditems) + start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) + for i in range(start, min(stop, length)): + w_item = self.wrappeditems[i] + if space.eq_w(w_item, w_obj): + return space.wrap(i) + raise OperationError(space.w_ValueError, + space.wrap("tuple.index(x): x not in tuple")) + +W_TupleObject.typedef = StdTypeDef("tuple", + __doc__ = '''tuple() -> an empty tuple +tuple(sequence) -> tuple initialized from sequence's items + +If the argument is a tuple, the return value is the same object.''', + __new__ = gateway.interp2app(W_TupleObject.descr_new), + __repr__ = gateway.interp2app(W_TupleObject.descr_repr), + __hash__ = gateway.interp2app(W_TupleObject.descr_hash), + + __eq__ = gateway.interp2app(W_TupleObject.descr_eq), + __ne__ = gateway.interp2app(W_TupleObject.descr_ne), + __lt__ = gateway.interp2app(W_TupleObject.descr_lt), + __le__ = gateway.interp2app(W_TupleObject.descr_le), + __gt__ = gateway.interp2app(W_TupleObject.descr_gt), + __ge__ = gateway.interp2app(W_TupleObject.descr_ge), + + __len__ = gateway.interp2app(W_TupleObject.descr_len), + __iter__ = gateway.interp2app(W_TupleObject.descr_iter), + __contains__ = gateway.interp2app(W_TupleObject.descr_contains), + + __add__ = gateway.interp2app(W_TupleObject.descr_add), + __mul__ = gateway.interp2app(W_TupleObject.descr_mul), + __rmul__ = gateway.interp2app(W_TupleObject.descr_mul), + + __getitem__ = gateway.interp2app(W_TupleObject.descr_getitem), + __getslice__ = gateway.interp2app(W_TupleObject.descr_getslice), + + __getnewargs__ = gateway.interp2app(W_TupleObject.descr_getnewargs), + count = gateway.interp2app(W_TupleObject.descr_count), + index = gateway.interp2app(W_TupleObject.descr_index) +) + registerimplementation(W_TupleObject) -def len__Tuple(space, w_tuple): - result = len(w_tuple.wrappeditems) - return wrapint(space, result) - -def getitem__Tuple_ANY(space, w_tuple, w_index): - # getindex_w should get a second argument space.w_IndexError, - # but that doesn't exist the first time this is called. - try: - w_IndexError = space.w_IndexError - except AttributeError: - w_IndexError = None - index = space.getindex_w(w_index, w_IndexError, "tuple index") - try: - return w_tuple.wrappeditems[index] - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__Tuple_Slice(space, w_tuple, w_slice): - items = w_tuple.wrappeditems - length = len(items) - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = items[start] - start += step - return space.newtuple(subitems) - -def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return space.newtuple(w_tuple.wrappeditems[start:stop]) - - at jit.look_inside_iff(lambda space, w_tuple, w_obj: - jit.loop_unrolling_heuristic(w_tuple, len(w_tuple.wrappeditems), UNROLL_CUTOFF)) -def contains__Tuple_ANY(space, w_tuple, w_obj): - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - return space.w_True - return space.w_False - -def iter__Tuple(space, w_tuple): - from pypy.objspace.std import iterobject - return iterobject.W_FastTupleIterObject(w_tuple, w_tuple.wrappeditems) - -def add__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - return space.newtuple(items1 + items2) - -def mul_tuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.wrappeditems - return space.newtuple(items * times) - -def mul__Tuple_ANY(space, w_tuple, w_times): - return mul_tuple_times(space, w_tuple, w_times) - -def mul__ANY_Tuple(space, w_times, w_tuple): - return mul_tuple_times(space, w_tuple, w_times) - -def tuple_unroll_condition(space, w_tuple1, w_tuple2): - return jit.loop_unrolling_heuristic(w_tuple1, len(w_tuple1.wrappeditems), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_tuple2, len(w_tuple2.wrappeditems), UNROLL_CUTOFF) - - at jit.look_inside_iff(tuple_unroll_condition) -def eq__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - lgt1 = len(items1) - lgt2 = len(items2) - if lgt1 != lgt2: - return space.w_False - for i in range(lgt1): - item1 = items1[i] - item2 = items2[i] - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - -def _make_tuple_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(tuple_unroll_condition) - def compare_tuples(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - ncmp = min(len(items1), len(items2)) - # Search for the first index where items are different - for p in range(ncmp): - if not space.eq_w(items1[p], items2[p]): - return getattr(space, name)(items1[p], items2[p]) - # No more items to compare -- compare sizes - return space.newbool(op(len(items1), len(items2))) - return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') - -lt__Tuple_Tuple = _make_tuple_comparison('lt') -le__Tuple_Tuple = _make_tuple_comparison('le') -gt__Tuple_Tuple = _make_tuple_comparison('gt') -ge__Tuple_Tuple = _make_tuple_comparison('ge') - -def repr__Tuple(space, w_tuple): - items = w_tuple.wrappeditems - # XXX this is quite innefficient, still better than calling - # it via applevel - if len(items) == 1: - return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") - return space.wrap("(" + - (", ".join([space.str_w(space.repr(item)) for item in items])) - + ")") - -def hash__Tuple(space, w_tuple): - return space.wrap(hash_tuple(space, w_tuple.wrappeditems)) - @jit.look_inside_iff(lambda space, wrappeditems: jit.loop_unrolling_heuristic(wrappeditems, len(wrappeditems), UNROLL_CUTOFF)) def hash_tuple(space, wrappeditems): @@ -188,25 +266,5 @@ x += 97531 return intmask(x) -def getnewargs__Tuple(space, w_tuple): - return space.newtuple([space.newtuple(w_tuple.wrappeditems)]) - -def tuple_count__Tuple_ANY(space, w_tuple, w_obj): - count = 0 - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - count += 1 - return space.wrap(count) - -def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) - for i in range(start, min(stop, length)): - w_item = w_tuple.wrappeditems[i] - if space.eq_w(w_item, w_obj): - return space.wrap(i) - raise OperationError(space.w_ValueError, - space.wrap("tuple.index(x): x not in tuple")) - from pypy.objspace.std import tupletype -register_all(vars(), tupletype) +tupletype.tuple_typedef = W_TupleObject.typedef diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py --- a/pypy/objspace/std/tupletype.py +++ b/pypy/objspace/std/tupletype.py @@ -1,7 +1,4 @@ -import sys -from pypy.interpreter import gateway from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM def wraptuple(space, list_w): from pypy.objspace.std.tupleobject import W_TupleObject @@ -37,34 +34,3 @@ return W_SmallTupleObject8(list_w) return W_TupleObject(list_w) -tuple_count = SMM("count", 2, - doc="count(obj) -> number of times obj appears in the tuple") - -tuple_index = SMM("index", 4, defaults=(0, sys.maxint), - doc="index(obj, [start, [stop]]) -> first index that obj " - "appears in the tuple") - - -def descr__new__(space, w_tupletype, w_sequence=None): - from pypy.objspace.std.tupleobject import W_TupleObject - if w_sequence is None: - tuple_w = [] - elif (space.is_w(w_tupletype, space.w_tuple) and - space.is_w(space.type(w_sequence), space.w_tuple)): - return w_sequence - else: - tuple_w = space.fixedview(w_sequence) - w_obj = space.allocate_instance(W_TupleObject, w_tupletype) - W_TupleObject.__init__(w_obj, tuple_w) - return w_obj - -# ____________________________________________________________ - -tuple_typedef = StdTypeDef("tuple", - __doc__ = '''tuple() -> an empty tuple -tuple(sequence) -> tuple initialized from sequence's items - -If the argument is a tuple, the return value is the same object.''', - __new__ = gateway.interp2app(descr__new__), - ) -tuple_typedef.registermethods(globals()) From noreply at buildbot.pypy.org Tue May 21 14:54:17 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 21 May 2013 14:54:17 +0200 (CEST) Subject: [pypy-commit] pypy default: try to not export cpyext_tp_setattro Message-ID: <20130521125417.28C1F1C0328@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64380:a3b64c491850 Date: 2013-05-21 14:53 +0200 http://bitbucket.org/pypy/pypy/changeset/a3b64c491850/ Log: try to not export cpyext_tp_setattro 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 @@ -344,7 +344,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1, external=False) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: From noreply at buildbot.pypy.org Tue May 21 14:55:54 2013 From: noreply at buildbot.pypy.org (bivab) Date: Tue, 21 May 2013 14:55:54 +0200 (CEST) Subject: [pypy-commit] pypy default: platform.machine seems to be rpython enough to go through translation, but it Message-ID: <20130521125554.0587D1C0328@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64381:8611029d42e8 Date: 2013-05-21 14:52 +0200 http://bitbucket.org/pypy/pypy/changeset/8611029d42e8/ Log: platform.machine seems to be rpython enough to go through translation, but it caches the result coming from the host machine. Use os.uname instead diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -132,7 +132,7 @@ # ---------- Linux2 ---------- def get_L2cache_linux2(): - arch = platform.machine() + arch = os.uname()[4] # machine if arch.endswith('86') or arch == 'x86_64': return get_L2cache_linux2_cpuinfo() if arch in ('alpha', 'ppc', 'ppc64'): From noreply at buildbot.pypy.org Tue May 21 14:55:55 2013 From: noreply at buildbot.pypy.org (bivab) Date: Tue, 21 May 2013 14:55:55 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130521125555.7A74B1C0328@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64382:469d4ebafa75 Date: 2013-05-21 14:54 +0200 http://bitbucket.org/pypy/pypy/changeset/469d4ebafa75/ Log: merge heads diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0.1`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0.1`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,46 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + +Cheers, +arigo et. al. for the PyPy team From noreply at buildbot.pypy.org Tue May 21 14:55:56 2013 From: noreply at buildbot.pypy.org (bivab) Date: Tue, 21 May 2013 14:55:56 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130521125556.D1E051C0328@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64383:3ec3d88d8e3f Date: 2013-05-21 14:55 +0200 http://bitbucket.org/pypy/pypy/changeset/3ec3d88d8e3f/ Log: merge heads 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 @@ -344,7 +344,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1, external=False) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: From noreply at buildbot.pypy.org Tue May 21 15:10:14 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 15:10:14 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: hg merge default Message-ID: <20130521131014.9F9781C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64384:b9d6357b218a Date: 2013-05-21 14:53 +0200 http://bitbucket.org/pypy/pypy/changeset/b9d6357b218a/ Log: hg merge default diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -363,6 +363,9 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + + if config.translation.platform == 'arm' and '_continuation' in modules: + modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0.1`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0.1`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,46 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -487,6 +487,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -586,7 +587,6 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=<.*>) i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -44,6 +44,7 @@ # gc_id call is hoisted out of the loop, the id of a value obviously # can't change ;) assert loop.match_by_id("getitem", """ + ... i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...) ... p33 = getinteriorfield_gc(p31, i26, descr=>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -36,7 +36,7 @@ assert loop0.match(expected) # XXX: The retracing fails to form a loop since j # becomes constant 0 after the bridge and constant 1 at the end of the - # loop. A bridge back to the peramble is produced instead. + # loop. A bridge back to the peramble is produced instead. #assert loop1.match(expected) def test_factorial(self): @@ -242,6 +242,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) + guard_not_invalidated(descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -355,54 +355,63 @@ def _push_all_regs_to_jitframe(self, mc, ignored_regs, withfloats, callee_only=False): + # Push general purpose registers base_ofs = self.cpu.get_baseofs_of_frame_field() if callee_only: regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - # XXX use STMDB ops here - for i, gpr in enumerate(regs): - if gpr in ignored_regs: - continue - self.store_reg(mc, gpr, r.fp, base_ofs + i * WORD) + # XXX add special case if ignored_regs are a block at the start of regs + if not ignored_regs: # we want to push a contiguous block of regs + assert check_imm_arg(base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) + mc.STM(r.ip.value, [reg.value for reg in regs]) + else: + for reg in ignored_regs: + assert not reg.is_vfp_reg() # sanity check + # we can have holes in the list of regs + for i, gpr in enumerate(regs): + if gpr in ignored_regs: + continue + self.store_reg(mc, gpr, r.fp, base_ofs + i * WORD) + if withfloats: - if callee_only: - regs = VFPRegisterManager.save_around_call_regs - else: - regs = VFPRegisterManager.all_regs - for i, vfpr in enumerate(regs): - if vfpr in ignored_regs: - continue - ofs = len(CoreRegisterManager.all_regs) * WORD - ofs += i * DOUBLE_WORD + base_ofs - self.store_reg(mc, vfpr, r.fp, ofs) + # Push VFP regs + regs = VFPRegisterManager.all_regs + ofs = len(CoreRegisterManager.all_regs) * WORD + assert check_imm_arg(ofs+base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, imm=ofs+base_ofs) + mc.VSTM(r.ip.value, [vfpr.value for vfpr in regs]) def _pop_all_regs_from_jitframe(self, mc, ignored_regs, withfloats, callee_only=False): - # Pop all general purpose registers + # Pop general purpose registers base_ofs = self.cpu.get_baseofs_of_frame_field() if callee_only: regs = CoreRegisterManager.save_around_call_regs else: regs = CoreRegisterManager.all_regs - # XXX use LDMDB ops here - for i, gpr in enumerate(regs): - if gpr in ignored_regs: - continue - ofs = i * WORD + base_ofs - self.load_reg(mc, gpr, r.fp, ofs) + # XXX add special case if ignored_regs are a block at the start of regs + if not ignored_regs: # we want to pop a contiguous block of regs + assert check_imm_arg(base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, base_ofs) + mc.LDM(r.ip.value, [reg.value for reg in regs]) + else: + for reg in ignored_regs: + assert not reg.is_vfp_reg() # sanity check + # we can have holes in the list of regs + for i, gpr in enumerate(regs): + if gpr in ignored_regs: + continue + ofs = i * WORD + base_ofs + self.load_reg(mc, gpr, r.fp, ofs) if withfloats: - # Pop all XMM regs - if callee_only: - regs = VFPRegisterManager.save_around_call_regs - else: - regs = VFPRegisterManager.all_regs - for i, vfpr in enumerate(regs): - if vfpr in ignored_regs: - continue - ofs = len(CoreRegisterManager.all_regs) * WORD - ofs += i * DOUBLE_WORD + base_ofs - self.load_reg(mc, vfpr, r.fp, ofs) + # Pop VFP regs + regs = VFPRegisterManager.all_regs + ofs = len(CoreRegisterManager.all_regs) * WORD + assert check_imm_arg(ofs+base_ofs) + mc.ADD_ri(r.ip.value, r.fp.value, imm=ofs+base_ofs) + mc.VLDM(r.ip.value, [vfpr.value for vfpr in regs]) def _build_failure_recovery(self, exc, withfloats=False): mc = InstrBuilder(self.cpu.cpuinfo.arch_version) diff --git a/rpython/jit/backend/arm/test/test_push_pop_frame.py b/rpython/jit/backend/arm/test/test_push_pop_frame.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/test/test_push_pop_frame.py @@ -0,0 +1,177 @@ +import py +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm.test.test_regalloc_mov import BaseMovTest, mi + +base_ofs = 23 +class MockCPU(object): + def get_baseofs_of_frame_field(self): + return base_ofs + + +class TestRegallocPush(BaseMovTest): + def setup_method(self, method): + BaseMovTest.setup_method(self, method) + self.asm.cpu = MockCPU() + + def test_callee_only(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('STM', r.ip.value, [r.r0.value, r.r1.value, + r.r2.value, r.r3.value]), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes(self): + expected = [ + mi('STR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('STR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[r.r1, r.r3], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes_in_front(self): + expected = [ + mi('STR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + mi('STR_ri', r.r3.value, r.fp.value, cond=c.AL, imm=base_ofs + 12), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[r.r0, r.r1], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_ignore_more_than_saved(self): + expected = [ + mi('STR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3, r.r4, r.r5], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_with_floats(self): + expected = [ + mi('STR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('ADD_ri', r.ip.value, r.fp.value, imm=base_ofs + len(r.all_regs) * WORD), + mi('VSTM', r.ip.value, [v.value for v in r.all_vfp_regs]) + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3], + withfloats=True, callee_only=True) + self.validate(expected) + + def test_try_ignore_vfp_reg(self): + py.test.raises(AssertionError, self.asm._push_all_regs_to_jitframe, self.asm.mc, + ignored_regs=[r.d0, r.r2, r.r3], withfloats=True, callee_only=True) + + def test_all_regs(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('STM', r.ip.value, [reg.value for reg in r.all_regs]), + ] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes(self): + ignored = [r.r1, r.r6] + expected = [mi('STR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes_in_front(self): + ignored = [r.r0, r.r1] + expected = [mi('STR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._push_all_regs_to_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) + + + +class TestRegallocPop(BaseMovTest): + def setup_method(self, method): + BaseMovTest.setup_method(self, method) + self.asm.cpu = MockCPU() + + def test_callee_only(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('LDM', r.ip.value, [r.r0.value, r.r1.value, + r.r2.value, r.r3.value]), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes(self): + expected = [ + mi('LDR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('LDR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[r.r1, r.r3], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_with_holes_in_front(self): + expected = [ + mi('LDR_ri', r.r2.value, r.fp.value, cond=c.AL, imm=base_ofs + 8), + mi('LDR_ri', r.r3.value, r.fp.value, cond=c.AL, imm=base_ofs + 12), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[r.r0, r.r1], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_callee_only_ignore_more_than_saved(self): + expected = [ + mi('LDR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3, r.r4, r.r5], + withfloats=False, callee_only=True) + self.validate(expected) + + def test_with_floats(self): + expected = [ + mi('LDR_ri', r.r0.value, r.fp.value, cond=c.AL, imm=base_ofs), + mi('ADD_ri', r.ip.value, r.fp.value, imm=base_ofs + len(r.all_regs) * WORD), + mi('VLDM', r.ip.value, [v.value for v in r.all_vfp_regs]) + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, + ignored_regs=[r.r1, r.r2, r.r3], + withfloats=True, callee_only=True) + self.validate(expected) + + def test_try_ignore_vfp_reg(self): + py.test.raises(AssertionError, self.asm._pop_all_regs_from_jitframe, self.asm.mc, + ignored_regs=[r.d0, r.r2, r.r3], withfloats=True, callee_only=True) + + def test_all_regs(self): + expected = [ + mi('ADD_ri', r.ip.value, r.fp.value, base_ofs), + mi('LDM', r.ip.value, [reg.value for reg in r.all_regs]), + ] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=[], + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes(self): + ignored = [r.r1, r.r6] + expected = [mi('LDR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) + + def test_all_regs_with_holes_in_front(self): + ignored = [r.r0, r.r1] + expected = [mi('LDR_ri', reg.value, r.fp.value, cond=c.AL, imm=base_ofs + reg.value * WORD) + for reg in r.all_regs if reg not in ignored] + self.asm._pop_all_regs_from_jitframe(self.asm.mc, ignored_regs=ignored, + withfloats=False, callee_only=False) + self.validate(expected) diff --git a/rpython/jit/backend/llgraph/test/test_llgraph.py b/rpython/jit/backend/llgraph/test/test_llgraph.py --- a/rpython/jit/backend/llgraph/test/test_llgraph.py +++ b/rpython/jit/backend/llgraph/test/test_llgraph.py @@ -15,6 +15,9 @@ def test_memoryerror(self): py.test.skip("does not make much sense on the llgraph backend") + def test_call_release_gil_variable_function_and_arguments(self): + py.test.skip("the arguments seem not correctly casted") + def test_cast_adr_to_int_and_back(): X = lltype.Struct('X', ('foo', lltype.Signed)) 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 @@ -108,8 +108,7 @@ self.malloc_slowpath_unicode = None self._build_stack_check_slowpath() - if gc_ll_descr.gcrootmap: - self._build_release_gil(gc_ll_descr.gcrootmap) + self._build_release_gil(gc_ll_descr.gcrootmap) if not self._debug: # if self._debug is already set it means that someone called # set_debug by hand before initializing the assembler. Leave it @@ -348,12 +347,19 @@ if after: after() + @staticmethod + def _no_op(): + pass + _NOARG_FUNC = lltype.Ptr(lltype.FuncType([], lltype.Void)) _CLOSESTACK_FUNC = lltype.Ptr(lltype.FuncType([rffi.LONGP], lltype.Void)) def _build_release_gil(self, gcrootmap): - if gcrootmap.is_shadow_stack: + if gcrootmap is None: + releasegil_func = llhelper(self._NOARG_FUNC, self._no_op) + reacqgil_func = llhelper(self._NOARG_FUNC, self._no_op) + elif gcrootmap.is_shadow_stack: releasegil_func = llhelper(self._NOARG_FUNC, self._release_gil_shadowstack) reacqgil_func = llhelper(self._NOARG_FUNC, diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -2532,6 +2532,219 @@ assert rffi.charp2strn(buffer, buflen) == cwd lltype.free(buffer, flavor='raw') + def test_call_release_gil_return_types(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + cpu = self.cpu + + for ffitype, result, TP in [ + (types.ulong, r_uint(sys.maxint + 10), lltype.Unsigned), + (types.slong, -4321, lltype.Signed), + (types.uint8, 200, rffi.UCHAR), + (types.sint8, -42, rffi.SIGNEDCHAR), + (types.uint16, 50000, rffi.USHORT), + (types.sint16, -20000, rffi.SHORT), + (types.uint32, r_uint(3000000000), rffi.UINT), + (types.sint32, -2000000000, rffi.INT), + (types.uint64, r_ulonglong(9999999999999999999), + lltype.UnsignedLongLong), + (types.sint64, r_longlong(-999999999999999999), + lltype.SignedLongLong), + (types.double, 12.3475226, rffi.DOUBLE), + (types.float, r_singlefloat(-592.75), rffi.FLOAT), + ]: + if sys.maxint < 2**32 and TP in (lltype.SignedLongLong, + lltype.UnsignedLongLong): + if not cpu.supports_longlong: + continue + if TP == rffi.DOUBLE: + if not cpu.supports_floats: + continue + if TP == rffi.FLOAT: + if not cpu.supports_singlefloats: + continue + # + result = rffi.cast(TP, result) + # + def pseudo_c_function(): + return result + # + FPTR = self.Ptr(self.FuncType([], TP)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests([], ffitype) + faildescr = BasicFailDescr(1) + kind = types.getkind(ffitype) + if kind in 'uis': + b3 = BoxInt() + elif kind in 'fUI': + b3 = BoxFloat() + else: + assert 0, kind + # + ops = [ + ResOperation(rop.CALL_RELEASE_GIL, [funcbox], b3, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [b3], None, descr=BasicFinalDescr(0)) + ] + ops[1].setfailargs([]) + looptoken = JitCellToken() + self.cpu.compile_loop([], ops, looptoken) + + deadframe = self.cpu.execute_token(looptoken) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + if isinstance(b3, BoxInt): + r = self.cpu.get_int_value(deadframe, 0) + if isinstance(result, r_singlefloat): + assert -sys.maxint-1 <= r <= 0xFFFFFFFF + r, = struct.unpack("f", struct.pack("I", r & 0xFFFFFFFF)) + result = float(result) + else: + r = rffi.cast(TP, r) + assert r == result + elif isinstance(b3, BoxFloat): + r = self.cpu.get_float_value(deadframe, 0) + if isinstance(result, float): + r = longlong.getrealfloat(r) + else: + r = rffi.cast(TP, r) + assert r == result + + def test_call_release_gil_variable_function_and_arguments(self): + from rpython.rlib.libffi import types + from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong + from rpython.rlib.rarithmetic import r_singlefloat + + cpu = self.cpu + rnd = random.Random(525) + + ALL_TYPES = [ + (types.ulong, lltype.Unsigned), + (types.slong, lltype.Signed), + (types.uint8, rffi.UCHAR), + (types.sint8, rffi.SIGNEDCHAR), + (types.uint16, rffi.USHORT), + (types.sint16, rffi.SHORT), + (types.uint32, rffi.UINT), + (types.sint32, rffi.INT), + ] + if sys.maxint < 2**32 and cpu.supports_longlong: + ALL_TYPES += [ + (types.uint64, lltype.UnsignedLongLong), + (types.sint64, lltype.SignedLongLong), + ] * 2 + if cpu.supports_floats: + ALL_TYPES += [ + (types.double, rffi.DOUBLE), + ] * 4 + if cpu.supports_singlefloats: + ALL_TYPES += [ + (types.float, rffi.FLOAT), + ] * 4 + + for k in range(100): + POSSIBLE_TYPES = [rnd.choice(ALL_TYPES) + for i in range(random.randrange(2, 5))] + load_factor = rnd.random() + keepalive_factor = rnd.random() + # + def pseudo_c_function(*args): + seen.append(list(args)) + # + ffitypes = [] + ARGTYPES = [] + for i in range(rnd.randrange(4, 20)): + ffitype, TP = rnd.choice(POSSIBLE_TYPES) + ffitypes.append(ffitype) + ARGTYPES.append(TP) + # + FPTR = self.Ptr(self.FuncType(ARGTYPES, lltype.Void)) + func_ptr = llhelper(FPTR, pseudo_c_function) + funcbox = self.get_funcbox(cpu, func_ptr) + calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void) + faildescr = BasicFailDescr(1) + # + argboxes = [BoxInt()] # for the function to call + codes = ['X'] + for ffitype in ffitypes: + kind = types.getkind(ffitype) + codes.append(kind) + if kind in 'uis': + b1 = BoxInt() + elif kind in 'fUI': + b1 = BoxFloat() + else: + assert 0, kind + argboxes.append(b1) + codes = ''.join(codes) # useful for pdb + print + print codes + # + argvalues = [funcbox.getint()] + for TP in ARGTYPES: + r = (rnd.random() - 0.5) * 999999999999.9 + r = rffi.cast(TP, r) + argvalues.append(r) + # + argvalues_normal = argvalues[:1] + for ffitype, r in zip(ffitypes, argvalues[1:]): + kind = types.getkind(ffitype) + if kind in 'ui': + r = rffi.cast(lltype.Signed, r) + elif kind in 's': + r, = struct.unpack("i", struct.pack("f", float(r))) + elif kind in 'f': + r = longlong.getfloatstorage(r) + elif kind in 'UI': # 32-bit only + r = rffi.cast(lltype.SignedLongLong, r) + else: + assert 0 + argvalues_normal.append(r) + # + ops = [] + loadcodes = [] + insideboxes = [] + for b1 in argboxes: + load = rnd.random() < load_factor + loadcodes.append(' ^'[load]) + if load: + b2 = b1.clonebox() + ops.insert(rnd.randrange(0, len(ops)+1), + ResOperation(rop.SAME_AS, [b1], b2)) + b1 = b2 + insideboxes.append(b1) + loadcodes = ''.join(loadcodes) + print loadcodes + ops += [ + ResOperation(rop.CALL_RELEASE_GIL, insideboxes, None, + descr=calldescr), + ResOperation(rop.GUARD_NOT_FORCED, [], None, descr=faildescr), + ResOperation(rop.FINISH, [], None, descr=BasicFinalDescr(0)) + ] + ops[-2].setfailargs([]) + # keep alive a random subset of the insideboxes + for b1 in insideboxes: + if rnd.random() < keepalive_factor: + ops.insert(-1, ResOperation(rop.SAME_AS, [b1], + b1.clonebox())) + looptoken = JitCellToken() + self.cpu.compile_loop(argboxes, ops, looptoken) + # + seen = [] + deadframe = self.cpu.execute_token(looptoken, *argvalues_normal) + fail = self.cpu.get_latest_descr(deadframe) + assert fail.identifier == 0 + expected = argvalues[1:] + [got] = seen + different_values = ['%r != %r' % (a, b) + for a, b in zip(got, expected) + if a != b] + assert got == expected, ', '.join(different_values) + + def test_guard_not_invalidated(self): cpu = self.cpu i0 = BoxInt() diff --git a/rpython/jit/backend/x86/arch.py b/rpython/jit/backend/x86/arch.py --- a/rpython/jit/backend/x86/arch.py +++ b/rpython/jit/backend/x86/arch.py @@ -40,4 +40,4 @@ PASS_ON_MY_FRAME = 12 JITFRAME_FIXED_SIZE = 28 # 13 GPR + 15 XMM -assert PASS_ON_MY_FRAME >= 11 # asmgcc needs at least JIT_USE_WORDS + 2 +assert PASS_ON_MY_FRAME >= 12 # asmgcc needs at least JIT_USE_WORDS + 3 diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -6,7 +6,7 @@ DEBUG_COUNTER, debug_bridge) from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.llsupport.gcmap import allocate_gcmap -from rpython.jit.metainterp.history import Const, Box +from rpython.jit.metainterp.history import Const, Box, VOID from rpython.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory from rpython.rtyper.lltypesystem.lloperation import llop @@ -25,28 +25,17 @@ RegLoc, FrameLoc, ConstFloatLoc, ImmedLoc, AddressLoc, imm, imm0, imm1, FloatImmedLoc, RawEbpLoc, RawEspLoc) from rpython.rlib.objectmodel import we_are_translated -from rpython.jit.backend.x86 import rx86, codebuf +from rpython.jit.backend.x86 import rx86, codebuf, callbuilder from rpython.jit.metainterp.resoperation import rop from rpython.jit.backend.x86 import support from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib import rgc -from rpython.rlib.clibffi import FFI_DEFAULT_ABI -from rpython.jit.backend.x86.jump import remap_frame_layout from rpython.jit.codewriter.effectinfo import EffectInfo from rpython.jit.codewriter import longlong from rpython.rlib.rarithmetic import intmask, r_uint from rpython.rlib.objectmodel import compute_unique_id -# darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0, -# better safe than sorry -CALL_ALIGN = 16 // WORD - - -def align_stack_words(words): - return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - - class Assembler386(BaseAssembler): _regalloc = None _output_loop_log = None @@ -131,10 +120,10 @@ mc.MOV_rs(esi.value, WORD*2) # push first arg mc.MOV_rr(edi.value, ebp.value) - align = align_stack_words(1) + align = callbuilder.align_stack_words(1) mc.SUB_ri(esp.value, (align - 1) * WORD) else: - align = align_stack_words(3) + align = callbuilder.align_stack_words(3) mc.MOV_rs(eax.value, WORD * 2) mc.SUB_ri(esp.value, (align - 1) * WORD) mc.MOV_sr(WORD, eax.value) @@ -1014,175 +1003,24 @@ gcrootmap = self.cpu.gc_ll_descr.gcrootmap return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def _emit_call(self, x, arglocs, start=0, tmp=eax, - argtypes=None, callconv=FFI_DEFAULT_ABI, - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True, - # max number of arguments we can pass on esp; if more, - # we need to decrease esp temporarily - stack_max=PASS_ON_MY_FRAME): - # - if IS_X86_64: - return self._emit_call_64(x, arglocs, start, argtypes, - can_collect, stack_max) - stack_depth = 0 - n = len(arglocs) - for i in range(start, n): - loc = arglocs[i] - stack_depth += loc.get_width() // WORD - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - self.mc.SUB_ri(esp.value, align * WORD) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) + def simple_call(self, fnloc, arglocs, result_loc=eax): + if result_loc is xmm0: + result_type = FLOAT + result_size = 8 + elif result_loc is None: + result_type = VOID + result_size = 0 else: - align = 0 - p = 0 - for i in range(start, n): - loc = arglocs[i] - if isinstance(loc, RegLoc): - if loc.is_xmm: - self.mc.MOVSD_sx(p, loc.value) - else: - self.mc.MOV_sr(p, loc.value) - p += loc.get_width() - p = 0 - for i in range(start, n): - loc = arglocs[i] - if not isinstance(loc, RegLoc): - if loc.get_width() == 8: - self.mc.MOVSD(xmm0, loc) - self.mc.MOVSD_sx(p, xmm0.value) - else: - self.mc.MOV(tmp, loc) - self.mc.MOV_sr(p, tmp.value) - p += loc.get_width() - # x is a location - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if callconv != FFI_DEFAULT_ABI: - self._fix_stdcall(callconv, p - align * WORD) - elif align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + result_type = INT + result_size = WORD + cb = callbuilder.CallBuilder(self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() - def _fix_stdcall(self, callconv, p): - from rpython.rlib.clibffi import FFI_STDCALL - assert callconv == FFI_STDCALL - # it's a bit stupid, but we're just going to cancel the fact that - # the called function just added 'p' to ESP, by subtracting it again. - self.mc.SUB_ri(esp.value, p) - - def _emit_call_64(self, x, arglocs, start, argtypes, - can_collect, stack_max): - src_locs = [] - dst_locs = [] - xmm_src_locs = [] - xmm_dst_locs = [] - singlefloats = None - - # In reverse order for use with pop() - unused_gpr = [r9, r8, ecx, edx, esi, edi] - unused_xmm = [xmm7, xmm6, xmm5, xmm4, xmm3, xmm2, xmm1, xmm0] - - on_stack = 0 - # count the stack depth - floats = 0 - for i in range(start, len(arglocs)): - arg = arglocs[i] - if arg.is_float() or argtypes and argtypes[i - start] == 'S': - floats += 1 - all_args = len(arglocs) - start - stack_depth = (max(all_args - floats - len(unused_gpr), 0) + - max(floats - len(unused_xmm), 0)) - align = 0 - if stack_depth > stack_max: - align = align_stack_words(stack_depth - stack_max) - if can_collect: - self.set_extra_stack_depth(self.mc, align * WORD) - self.mc.SUB_ri(esp.value, align * WORD) - for i in range(start, len(arglocs)): - loc = arglocs[i] - if loc.is_float(): - xmm_src_locs.append(loc) - if len(unused_xmm) > 0: - xmm_dst_locs.append(unused_xmm.pop()) - else: - xmm_dst_locs.append(RawEspLoc(on_stack * WORD, FLOAT)) - on_stack += 1 - elif argtypes is not None and argtypes[i-start] == 'S': - # Singlefloat argument - if singlefloats is None: - singlefloats = [] - if len(unused_xmm) > 0: - singlefloats.append((loc, unused_xmm.pop())) - else: - singlefloats.append((loc, RawEspLoc(on_stack * WORD, INT))) - on_stack += 1 - else: - src_locs.append(loc) - if len(unused_gpr) > 0: - dst_locs.append(unused_gpr.pop()) - else: - dst_locs.append(RawEspLoc(on_stack * WORD, INT)) - on_stack += 1 - - # Handle register arguments: first remap the xmm arguments - remap_frame_layout(self, xmm_src_locs, xmm_dst_locs, - X86_64_XMM_SCRATCH_REG) - # Load the singlefloat arguments from main regs or stack to xmm regs - if singlefloats is not None: - for src, dst in singlefloats: - if isinstance(dst, RawEspLoc): - # XXX too much special logic - if isinstance(src, RawEbpLoc): - self.mc.MOV32(X86_64_SCRATCH_REG, src) - self.mc.MOV32(dst, X86_64_SCRATCH_REG) - else: - self.mc.MOV32(dst, src) - continue - if isinstance(src, ImmedLoc): - self.mc.MOV(X86_64_SCRATCH_REG, src) - src = X86_64_SCRATCH_REG - self.mc.MOVD(dst, src) - # Finally remap the arguments in the main regs - # If x is a register and is in dst_locs, then oups, it needs to - # be moved away: - if x in dst_locs: - src_locs.append(x) - dst_locs.append(r10) - x = r10 - remap_frame_layout(self, src_locs, dst_locs, X86_64_SCRATCH_REG) - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([eax], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - # - self.mc.CALL(x) - if align: - self.mc.ADD_ri(esp.value, align * WORD) - # - if can_collect: - self._reload_frame_if_necessary(self.mc) - if align: - self.set_extra_stack_depth(self.mc, 0) - self.pop_gcmap(self.mc) + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.CallBuilder(self, fnloc, arglocs) + cb.emit_no_collect() def _reload_frame_if_necessary(self, mc, align_stack=False): gcrootmap = self.cpu.gc_ll_descr.gcrootmap @@ -1198,10 +1036,6 @@ self._write_barrier_fastpath(mc, wbdescr, [ebp], array=False, is_frame=True, align_stack=align_stack) - def call(self, addr, args, res): - self._emit_call(imm(addr), args) - assert res is eax - genop_int_neg = _unaryop("NEG") genop_int_invert = _unaryop("NOT") genop_int_add = _binaryop_or_lea("ADD", True) @@ -1446,7 +1280,7 @@ # ---------- def genop_call_malloc_gc(self, op, arglocs, result_loc): - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self.propagate_memoryerror_if_eax_is_null() def propagate_memoryerror_if_eax_is_null(self): @@ -1993,75 +1827,29 @@ self.pending_guard_tokens.append(guard_token) def genop_call(self, op, arglocs, resloc): - return self._genop_call(op, arglocs, resloc) + self._genop_call(op, arglocs, resloc) def _genop_call(self, op, arglocs, resloc, is_call_release_gil=False): from rpython.jit.backend.llsupport.descr import CallDescr - sizeloc = arglocs[0] - assert isinstance(sizeloc, ImmedLoc) - size = sizeloc.value - signloc = arglocs[1] - - x = arglocs[2] # the function address - if x is eax: - tmp = ecx - else: - tmp = eax + cb = callbuilder.CallBuilder(self, arglocs[2], arglocs[3:], resloc) descr = op.getdescr() assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[0] + assert isinstance(sizeloc, ImmedLoc) + cb.ressize = sizeloc.value + signloc = arglocs[1] + assert isinstance(signloc, ImmedLoc) + cb.ressign = signloc.value - stack_max = PASS_ON_MY_FRAME if is_call_release_gil: - if self._is_asmgcc(): - from rpython.memory.gctransform import asmgcroot - stack_max -= asmgcroot.JIT_USE_WORDS - can_collect = False + cb.emit_call_release_gil() else: - can_collect = True - - self._emit_call(x, arglocs, 3, tmp=tmp, - argtypes=descr.get_arg_types(), - callconv=descr.get_call_conv(), - can_collect=can_collect, - stack_max=stack_max) - - if IS_X86_32 and isinstance(resloc, FrameLoc) and resloc.type == FLOAT: - # a float or a long long return - if descr.get_result_type() == 'L': - self.mc.MOV_br(resloc.value, eax.value) # long long - self.mc.MOV_br(resloc.value + 4, edx.value) - # XXX should ideally not move the result on the stack, - # but it's a mess to load eax/edx into a xmm register - # and this way is simpler also because the result loc - # can just be always a stack location - else: - self.mc.FSTPL_b(resloc.value) # float return - elif descr.get_result_type() == 'S': - # singlefloat return - assert resloc is eax - if IS_X86_32: - # must convert ST(0) to a 32-bit singlefloat and load it into EAX - # mess mess mess - self.mc.SUB_ri(esp.value, 4) - self.mc.FSTPS_s(0) - self.mc.POP_r(eax.value) - elif IS_X86_64: - # must copy from the lower 32 bits of XMM0 into eax - self.mc.MOVD_rx(eax.value, xmm0.value) - elif size == WORD: - assert resloc is eax or resloc is xmm0 # a full word - elif size == 0: - pass # void return - else: - # use the code in load_from_mem to do the zero- or sign-extension - assert resloc is eax - if size == 1: - srcloc = eax.lowest8bits() - else: - srcloc = eax - self.load_from_mem(eax, srcloc, sizeloc, signloc) + cb.emit() def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() @@ -2077,64 +1865,15 @@ def genop_guard_call_may_force(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - self.genop_call(op, arglocs, result_loc) + self._genop_call(op, arglocs, result_loc) self._emit_guard_not_forced(guard_token) def genop_guard_call_release_gil(self, op, guard_op, guard_token, arglocs, result_loc): self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs) - # do the call self._genop_call(op, arglocs, result_loc, is_call_release_gil=True) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, result_loc) - self.pop_gcmap(self.mc) # remove the gcmap saved above - # finally, the guard_not_forced self._emit_guard_not_forced(guard_token) - def call_release_gil(self, gcrootmap, save_registers): - if gcrootmap.is_shadow_stack: - args = [] - else: - from rpython.memory.gctransform import asmgcroot - # build a 'css' structure on the stack: 2 words for the linkage, - # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a - # total size of JIT_USE_WORDS. This structure is found at - # [ESP+css]. - css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) - assert css >= 2 - # Save ebp - index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) - self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP - # Save the "return address": we pretend that it's css - if IS_X86_32: - reg = eax - elif IS_X86_64: - reg = edi - self.mc.LEA_rs(reg.value, css) # LEA reg, [css] - frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) - self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg - # Set up jf_extra_stack_depth to pretend that the return address - # was at css, and so our stack frame is supposedly shorter by - # (css+WORD) bytes - self.set_extra_stack_depth(self.mc, -css-WORD) - # Call the closestack() function (also releasing the GIL) - args = [reg] - # - self._emit_call(imm(self.releasegil_addr), args, can_collect=False) - def call_reacquire_gil(self, gcrootmap, save_loc): # save the previous result (eax/xmm0) into the stack temporarily. # XXX like with call_release_gil(), we assume that we don't need @@ -2186,11 +1925,11 @@ self.call_assembler(op, guard_op, argloc, vloc, result_loc, eax) self._emit_guard_not_forced(guard_token) - def _call_assembler_emit_call(self, addr, argloc, tmploc): - self._emit_call(addr, [argloc], 0, tmp=tmploc) + def _call_assembler_emit_call(self, addr, argloc, _): + self.simple_call(addr, [argloc]) - def _call_assembler_emit_helper_call(self, addr, arglocs, _): - self._emit_call(addr, arglocs, 0, tmp=self._second_tmp_reg) + def _call_assembler_emit_helper_call(self, addr, arglocs, result_loc): + self.simple_call(addr, arglocs, result_loc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/x86/callbuilder.py @@ -0,0 +1,577 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.backend.x86.arch import (WORD, IS_X86_64, IS_X86_32, + PASS_ON_MY_FRAME) +from rpython.jit.backend.x86.regloc import (eax, ecx, edx, ebx, esp, ebp, esi, + xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, r8, r9, r10, r11, edi, + r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, + RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) +from rpython.jit.backend.x86.jump import remap_frame_layout + + +# darwin requires the stack to be 16 bytes aligned on calls. +# Same for gcc 4.5.0, better safe than sorry +CALL_ALIGN = 16 // WORD + +def align_stack_words(words): + return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) + + + +class AbstractCallBuilder(object): + + # max number of words we have room in esp; if we need more for + # arguments, we need to decrease esp temporarily + stack_max = PASS_ON_MY_FRAME + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # set by save_result_value() + tmpresloc = None + + + def __init__(self, assembler, fnloc, arglocs, + resloc=eax, restype=INT, ressize=WORD): + # Avoid tons of issues with a non-immediate fnloc by sticking it + # as an extra argument if needed + self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) + if self.fnloc_is_immediate: + self.fnloc = fnloc + self.arglocs = arglocs + else: + self.arglocs = arglocs + [fnloc] + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + self.current_esp = 0 # 0 or (usually) negative, counted in bytes + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_esp() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_esp() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_esp() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + if self.asm._is_asmgcc(): + from rpython.memory.gctransform import asmgcroot + self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + assert self.stack_max >= 3 + + def emit_raw_call(self): + self.mc.CALL(self.fnloc) + if self.callconv != FFI_DEFAULT_ABI: + self.current_esp += self._fix_stdcall(self.callconv) + + def subtract_esp_aligned(self, count): + if count > 0: + align = align_stack_words(count) + self.current_esp -= align * WORD + self.mc.SUB_ri(esp.value, align * WORD) + + def restore_esp(self, target_esp=0): + if self.current_esp != target_esp: + self.mc.ADD_ri(esp.value, target_esp - self.current_esp) + self.current_esp = target_esp + + def load_result(self): + """Overridden in CallBuilder32 and CallBuilder64""" + if self.ressize == 0: + return # void result + # use the code in load_from_mem to do the zero- or sign-extension + srcloc = self.tmpresloc + if srcloc is None: + if self.restype == FLOAT: + srcloc = xmm0 + else: + srcloc = eax + if self.ressize >= WORD and self.resloc is srcloc: + return # no need for any MOV + if self.ressize == 1 and isinstance(srcloc, RegLoc): + srcloc = srcloc.lowest8bits() + self.asm.load_from_mem(self.resloc, srcloc, + imm(self.ressize), imm(self.ressign)) + + def push_gcmap(self): + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just before, ignoring the return + # value eax, if necessary + assert not self.is_call_release_gil + self.change_extra_stack_depth = (self.current_esp != 0) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, -self.current_esp) + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + if self.change_extra_stack_depth: + self.asm.set_extra_stack_depth(self.mc, 0) + self.asm.pop_gcmap(self.mc) + + def call_releasegil_addr_and_move_real_arguments(self): + initial_esp = self.current_esp + self.save_register_arguments() + # + if not self.asm._is_asmgcc(): + # the helper takes no argument + self.change_extra_stack_depth = False + else: + from rpython.memory.gctransform import asmgcroot + # build a 'css' structure on the stack: 2 words for the linkage, + # and 5/7 words as described for asmgcroot.ASM_FRAMEDATA, for a + # total size of JIT_USE_WORDS. This structure is found at + # [ESP+css]. + css = -self.current_esp + ( + WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS)) + assert css >= 2 * WORD + # Save ebp + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_sr(index_of_ebp, ebp.value) # MOV [css.ebp], EBP + # Save the "return address": we pretend that it's css + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) # LEA reg, [css] + frame_ptr = css + WORD * (2+asmgcroot.FRAME_PTR) + self.mc.MOV_sr(frame_ptr, reg.value) # MOV [css.frame], reg + # Set up jf_extra_stack_depth to pretend that the return address + # was at css, and so our stack frame is supposedly shorter by + # (PASS_ON_MY_FRAME-JIT_USE_WORDS+1) words + delta = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS + 1 + self.change_extra_stack_depth = True + self.asm.set_extra_stack_depth(self.mc, -delta * WORD) + # Call the closestack() function (also releasing the GIL) + # with 'reg' as argument + if IS_X86_32: + self.subtract_esp_aligned(1) + self.mc.MOV_sr(0, reg.value) + #else: + # on x86_64, reg is edi so that it is already correct + # + self.mc.CALL(imm(self.asm.releasegil_addr)) + # + if not we_are_translated(): # for testing: we should not access + self.mc.ADD(ebp, imm(1)) # ebp any more + # + self.restore_register_arguments() + self.restore_esp(initial_esp) + + def save_register_arguments(self): + """Overridden in CallBuilder64""" + + def restore_register_arguments(self): + """Overridden in CallBuilder64""" + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got (in eax/eax+edx/st(0)/xmm0) + self.save_result_value() + # call the reopenstack() function (also reacquiring the GIL) + if not self.asm._is_asmgcc(): + css = 0 # the helper takes no argument + else: + from rpython.memory.gctransform import asmgcroot + css = WORD * (PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS) + if IS_X86_32: + reg = eax + elif IS_X86_64: + reg = edi + self.mc.LEA_rs(reg.value, css) + if IS_X86_32: + self.mc.MOV_sr(0, reg.value) + # + self.mc.CALL(imm(self.asm.reacqgil_addr)) + # + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB(ebp, imm(1)) # ebp again + # + # Now that we required the GIL, we can reload a possibly modified ebp + if self.asm._is_asmgcc(): + # special-case: reload ebp from the css + from rpython.memory.gctransform import asmgcroot + index_of_ebp = css + WORD * (2+asmgcroot.INDEX_OF_EBP) + self.mc.MOV_rs(ebp.value, index_of_ebp) # MOV EBP, [css.ebp] + #else: + # for shadowstack, done for us by _reload_frame_if_necessary() + + def save_result_value(self): + """Overridden in CallBuilder32 and CallBuilder64""" + raise NotImplementedError + + +class CallBuilder32(AbstractCallBuilder): + + def prepare_arguments(self): + arglocs = self.arglocs + stack_depth = 0 + n = len(arglocs) + for i in range(n): + loc = arglocs[i] + stack_depth += loc.get_width() // WORD + self.subtract_esp_aligned(stack_depth - self.stack_max) + # + p = 0 + for i in range(n): + loc = arglocs[i] + if isinstance(loc, RegLoc): + if loc.is_xmm: + self.mc.MOVSD_sx(p, loc.value) + else: + self.mc.MOV_sr(p, loc.value) + p += loc.get_width() + p = 0 + for i in range(n): + loc = arglocs[i] + if not isinstance(loc, RegLoc): + if loc.get_width() == 8: + self.mc.MOVSD(xmm0, loc) + self.mc.MOVSD_sx(p, xmm0.value) + elif isinstance(loc, ImmedLoc): + self.mc.MOV_si(p, loc.value) + else: + self.mc.MOV(eax, loc) + self.mc.MOV_sr(p, eax.value) + p += loc.get_width() + self.total_stack_used_by_arguments = p + # + if not self.fnloc_is_immediate: # the last "argument" pushed above + self.fnloc = RawEspLoc(p - WORD, INT) + + + def _fix_stdcall(self, callconv): + from rpython.rlib.clibffi import FFI_STDCALL + assert callconv == FFI_STDCALL + return self.total_stack_used_by_arguments + + def load_result(self): + resloc = self.resloc + if resloc is not None and resloc.is_float(): + # a float or a long long return + if self.tmpresloc is None: + if self.restype == 'L': # long long + # move eax/edx -> xmm0 + self.mc.MOVD_xr(resloc.value^1, edx.value) + self.mc.MOVD_xr(resloc.value, eax.value) + self.mc.PUNPCKLDQ_xx(resloc.value, resloc.value^1) + else: + # float: we have to go via the stack + self.mc.FSTPL_s(0) + self.mc.MOVSD_xs(resloc.value, 0) + else: + self.mc.MOVSD(resloc, self.tmpresloc) + # + elif self.restype == 'S': + # singlefloat return: must convert ST(0) to a 32-bit singlefloat + # and load it into self.resloc. mess mess mess + if self.tmpresloc is None: + self.mc.FSTPS_s(0) + self.mc.MOV_rs(resloc.value, 0) + else: + self.mc.MOV(resloc, self.tmpresloc) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP+4]. We use "+4" + # in order to leave the word at [ESP+0] free, in case it's needed + if self.ressize == 0: # void return + return + if self.resloc.is_float(): + # a float or a long long return + self.tmpresloc = RawEspLoc(4, FLOAT) + if self.restype == 'L': + self.mc.MOV_sr(4, eax.value) # long long + self.mc.MOV_sr(8, edx.value) + else: + self.mc.FSTPL_s(4) # float return + else: + self.tmpresloc = RawEspLoc(4, INT) + if self.restype == 'S': + self.mc.FSTPS_s(4) + else: + assert self.restype == INT + assert self.ressize <= WORD + self.mc.MOV_sr(4, eax.value) + + +class CallBuilder64(AbstractCallBuilder): + + ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] + ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] + DONT_MOVE_GPR = [] + _ALL_CALLEE_SAVE_GPR = [ebx, r12, r13, r14, r15] + + next_arg_gpr = 0 + next_arg_xmm = 0 + + def _unused_gpr(self, hint): + i = self.next_arg_gpr + self.next_arg_gpr = i + 1 + try: + res = self.ARGUMENTS_GPR[i] + except IndexError: + return None + if hint in self.DONT_MOVE_GPR: + self.ARGUMENTS_GPR[i] = hint + res = hint + return res + + def _unused_xmm(self): + i = self.next_arg_xmm + self.next_arg_xmm = i + 1 + try: + return self.ARGUMENTS_XMM[i] + except IndexError: + return None + + def _permute_to_prefer_unused_registers(self, lst): + # permute 'lst' so that it starts with registers that are not + # in 'self.already_used', and ends with registers that are. + N = len(lst) + i = 0 + while i < N: + reg = lst[i] + if reg in self.already_used: + # move this reg to the end, and decrement N + N -= 1 + assert N >= i + lst[N], lst[i] = lst[i], lst[N] + else: + i += 1 + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + # We have to copy the arguments around a bit more in this mode, + # but on the other hand we don't need prepare_arguments() moving + # them in precisely the final registers. Here we look around for + # unused registers that may be more likely usable. + from rpython.jit.backend.x86.regalloc import X86_64_RegisterManager + from rpython.jit.backend.x86.regalloc import X86_64_XMMRegisterManager + self.already_used = {} + for loc in self.arglocs: + self.already_used[loc] = None + # + lst = X86_64_RegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + # + extra = [] + for reg in self.asm._regalloc.rm.free_regs: + if (reg not in self.already_used and + reg in self._ALL_CALLEE_SAVE_GPR): + extra.append(reg) + self.free_callee_save_gprs = extra + lst = extra + lst + # + self.ARGUMENTS_GPR = lst[:len(self.ARGUMENTS_GPR)] + self.DONT_MOVE_GPR = self._ALL_CALLEE_SAVE_GPR + # + lst = X86_64_XMMRegisterManager.save_around_call_regs[:] + self._permute_to_prefer_unused_registers(lst) + self.ARGUMENTS_XMM = lst[:len(self.ARGUMENTS_XMM)] + + def prepare_arguments(self): + src_locs = [] + dst_locs = [] + xmm_src_locs = [] + xmm_dst_locs = [] + singlefloats = None + + arglocs = self.arglocs + argtypes = self.argtypes + + on_stack = 0 + for i in range(len(arglocs)): + loc = arglocs[i] + if loc.is_float(): + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, FLOAT) + on_stack += 1 + xmm_src_locs.append(loc) + xmm_dst_locs.append(tgt) + elif i < len(argtypes) and argtypes[i] == 'S': + # Singlefloat argument + if singlefloats is None: + singlefloats = [] + tgt = self._unused_xmm() + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + singlefloats.append((loc, tgt)) + else: + tgt = self._unused_gpr(hint=loc) + if tgt is None: + tgt = RawEspLoc(on_stack * WORD, INT) + on_stack += 1 + src_locs.append(loc) + dst_locs.append(tgt) + + if not self.fnloc_is_immediate: + self.fnloc = dst_locs[-1] # the last "argument" prepared above + + if not we_are_translated(): # assert that we got the right stack depth + floats = 0 + for i in range(len(arglocs)): + arg = arglocs[i] + if arg.is_float() or (i < len(argtypes) and argtypes[i]=='S'): + floats += 1 + all_args = len(arglocs) + stack_depth = (max(all_args - floats - len(self.ARGUMENTS_GPR), 0) + + max(floats - len(self.ARGUMENTS_XMM), 0)) + assert stack_depth == on_stack + + self.subtract_esp_aligned(on_stack - self.stack_max) + + # Handle register arguments: first remap the xmm arguments + remap_frame_layout(self.asm, xmm_src_locs, xmm_dst_locs, + X86_64_XMM_SCRATCH_REG) + # Load the singlefloat arguments from main regs or stack to xmm regs + if singlefloats is not None: + for src, dst in singlefloats: + if isinstance(dst, RawEspLoc): + # XXX too much special logic + if isinstance(src, RawEbpLoc): + self.mc.MOV32(X86_64_SCRATCH_REG, src) + self.mc.MOV32(dst, X86_64_SCRATCH_REG) + else: + self.mc.MOV32(dst, src) + continue + if isinstance(src, ImmedLoc): + self.mc.MOV(X86_64_SCRATCH_REG, src) + src = X86_64_SCRATCH_REG + self.mc.MOVD(dst, src) + # Finally remap the arguments in the main regs + remap_frame_layout(self.asm, src_locs, dst_locs, X86_64_SCRATCH_REG) + + + def _fix_stdcall(self, callconv): + assert 0 # should not occur on 64-bit + + def load_result(self): + if self.restype == 'S' and self.tmpresloc is None: + # singlefloat return: use MOVD to load the target register + # from the lower 32 bits of XMM0 + self.mc.MOVD(self.resloc, xmm0) + else: + AbstractCallBuilder.load_result(self) + + def save_result_value(self): + # Temporarily save the result value into [ESP]. + if self.ressize == 0: # void return + return + # + if self.restype == FLOAT: # and not 'S' + self.mc.MOVSD_sx(0, xmm0.value) + self.tmpresloc = RawEspLoc(0, FLOAT) + return + # + if len(self.free_callee_save_gprs) == 0: + self.tmpresloc = RawEspLoc(0, INT) + else: + self.tmpresloc = self.free_callee_save_gprs[0] + # + if self.restype == 'S': + # singlefloat return: use MOVD to store the lower 32 bits + # of XMM0 into the tmpresloc (register or [ESP]) + self.mc.MOVD(self.tmpresloc, xmm0) + else: + assert self.restype == INT + self.mc.MOV(self.tmpresloc, eax) + + def save_register_arguments(self): + # Save the argument registers, which are given by self.ARGUMENTS_xxx. + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + n_saved_regs = n_gpr + n_xmm + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] in self._ALL_CALLEE_SAVE_GPR: + n_saved_regs -= 1 # don't need to save it + self.subtract_esp_aligned(n_saved_regs) + # + n = 0 + for i in range(n_gpr): + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_sr(n * WORD, self.ARGUMENTS_GPR[i].value) + n += 1 + for i in range(n_xmm): + self.mc.MOVSD_sx(n * WORD, self.ARGUMENTS_XMM[i].value) + n += 1 + assert n == n_saved_regs + self.n_saved_regs = n_saved_regs + + def restore_register_arguments(self): + # Restore the saved values into the *real* registers used for calls + # --- which are not self.ARGUMENTS_xxx! + n_gpr = min(self.next_arg_gpr, len(self.ARGUMENTS_GPR)) + n_xmm = min(self.next_arg_xmm, len(self.ARGUMENTS_XMM)) + # + n = 0 + for i in range(n_gpr): + tgtvalue = CallBuilder64.ARGUMENTS_GPR[i].value + if self.ARGUMENTS_GPR[i] not in self._ALL_CALLEE_SAVE_GPR: + self.mc.MOV_rs(tgtvalue, n * WORD) + n += 1 + else: + self.mc.MOV_rr(tgtvalue, self.ARGUMENTS_GPR[i].value) + for i in range(n_xmm): + self.mc.MOVSD_xs(CallBuilder64.ARGUMENTS_XMM[i].value, n * WORD) + n += 1 + assert n == self.n_saved_regs + # + if isinstance(self.fnloc, RegLoc): # fix this register + self.fnloc = CallBuilder64.ARGUMENTS_GPR[n_gpr - 1] + + +if IS_X86_32: + CallBuilder = CallBuilder32 +if IS_X86_64: + CallBuilder = CallBuilder64 diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -79,26 +79,14 @@ rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), adr)[1] = y return ConstFloatLoc(adr) - def after_call(self, v): - # the result is stored in st0, but we don't have this around, - # so genop_call will move it to some frame location immediately - # after the call - return self.frame_manager.loc(v) + def call_result_location(self, v): + return xmm0 class X86_64_XMMRegisterManager(X86XMMRegisterManager): # xmm15 reserved for scratch use all_regs = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14] save_around_call_regs = all_regs - def call_result_location(self, v): - return xmm0 - - def after_call(self, v): - # We use RegisterManager's implementation, since X86XMMRegisterManager - # places the result on the stack, which we don't need to do when the - # calling convention places the result in xmm0 - return RegisterManager.after_call(self, v) - class X86FrameManager(FrameManager): def __init__(self, base_ofs): FrameManager.__init__(self) @@ -799,14 +787,6 @@ self._consider_call(op, guard_op) def consider_call_release_gil(self, op, guard_op): - # We spill the arguments to the stack, because we need to do 3 calls: - # call_release_gil(), the_real_c_function(), and call_reacquire_gil(). - # The arguments are used on the second call only. XXX we assume - # that the XMM arguments won't be modified by call_release_gil(). - for i in range(op.numargs()): - loc = self.loc(op.getarg(i)) - if loc in self.rm.save_around_call_regs: - self.rm.force_spill_var(op.getarg(i)) assert guard_op is not None self._consider_call(op, guard_op) @@ -1151,9 +1131,8 @@ # call memcpy() self.rm.before_call() self.xrm.before_call() - self.assembler._emit_call(imm(self.assembler.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.assembler.simple_call_no_collect(imm(self.assembler.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) self.rm.possibly_free_var(length_box) self.rm.possibly_free_var(dstaddr_box) self.rm.possibly_free_var(srcaddr_box) diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -553,6 +553,7 @@ CALL_l = insn('\xE8', relative(1)) CALL_r = insn(rex_nw, '\xFF', register(1), chr(0xC0 | (2<<3))) CALL_b = insn('\xFF', orbyte(2<<3), stack_bp(1)) + CALL_s = insn('\xFF', orbyte(2<<3), stack_sp(1)) # XXX: Only here for testing purposes..."as" happens the encode the # registers in the opposite order that we would otherwise do in a @@ -583,6 +584,7 @@ # x87 instructions FSTPL_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) # rffi.DOUBLE ('as' wants L??) + FSTPL_s = insn('\xDD', orbyte(3<<3), stack_sp(1)) # rffi.DOUBLE ('as' wants L??) FSTPS_s = insn('\xD9', orbyte(3<<3), stack_sp(1)) # lltype.SingleFloat # ------------------------------ Random mess ----------------------- From noreply at buildbot.pypy.org Tue May 21 15:10:17 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 15:10:17 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: hg merge remove-list-smm-2 Message-ID: <20130521131017.579C21C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64385:2921742865a9 Date: 2013-05-21 14:54 +0200 http://bitbucket.org/pypy/pypy/changeset/2921742865a9/ Log: hg merge remove-list-smm-2 diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -8,7 +8,6 @@ getbytevalue, makebytearraydata_w, new_bytearray) from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.listobject import get_list_index, get_positive_index from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject @@ -17,6 +16,7 @@ from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -587,7 +587,7 @@ _setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00') def delitem__Bytearray_ANY(space, w_bytearray, w_idx): - idx = get_list_index(space, w_idx) + idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray index") try: del w_bytearray.data[idx] except IndexError: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -5,6 +5,7 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null @@ -41,19 +42,6 @@ w_dct.length() <= UNROLL_CUTOFF) -def negate(f): - def _negator(self, space, w_other): - # no need to use space.is_ / space.not_ - tmp = f(self, space, w_other) - if tmp is space.w_NotImplemented: - return space.w_NotImplemented - elif tmp is space.w_False: - return space.w_True - else: - return space.w_False - _negator.func_name = 'negate-%s' % f.func_name - return _negator - class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,27 +1,35 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement +import operator +from sys import maxint + +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import (WrappedDefault, unwrap_spec, applevel, + interp2app) from pypy.interpreter.generator import GeneratorIterator +from pypy.interpreter.signature import Signature +from pypy.objspace.std import slicetype +from pypy.objspace.std.floatobject import W_FloatObject +from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.iterobject import (W_FastListIterObject, + W_ReverseSeqIterObject) from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.interpreter.gateway import WrappedDefault, unwrap_spec, applevel,\ - interp2app -from pypy.interpreter import baseobjspace -from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject +from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.util import negate, get_positive_index +from rpython.rlib import rerased, jit, debug +from rpython.rlib.listsort import make_timsort_class from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) -from rpython.rlib.listsort import make_timsort_class -from rpython.rlib import rerased, jit, debug + resizelist_hint) from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from sys import maxint + +__all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] + UNROLL_CUTOFF = 5 -class W_AbstractListObject(W_Object): - __slots__ = () def make_range_list(space, start, step, length): if length <= 0: @@ -32,16 +40,19 @@ storage = strategy.erase((start, step, length)) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list(space): strategy = space.fromcache(EmptyListStrategy) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list_with_size(space, hint): strategy = SizeListStrategy(space, hint) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + @jit.look_inside_iff(lambda space, list_w, sizehint: jit.loop_unrolling_heuristic(list_w, len(list_w), UNROLL_CUTOFF)) def get_strategy_from_list_objects(space, list_w, sizehint): @@ -52,38 +63,40 @@ # check for ints for w_obj in list_w: - if not is_W_IntObject(w_obj): + if not type(w_obj) is W_IntObject: break else: return space.fromcache(IntegerListStrategy) # check for strings for w_obj in list_w: - if not is_W_StringObject(w_obj): + if not type(w_obj) is W_StringObject: break else: return space.fromcache(StringListStrategy) # check for unicode for w_obj in list_w: - if not is_W_UnicodeObject(w_obj): + if not type(w_obj) is W_UnicodeObject: break else: return space.fromcache(UnicodeListStrategy) # check for floats for w_obj in list_w: - if not is_W_FloatObject(w_obj): + if not type(w_obj) is W_FloatObject: break else: return space.fromcache(FloatListStrategy) return space.fromcache(ObjectListStrategy) + def _get_printable_location(w_type): return ('list__do_extend_from_iterable [w_type=%s]' % w_type.getname(w_type.space)) + _do_extend_jitdriver = jit.JitDriver( name='list__do_extend_from_iterable', greens=['w_type'], @@ -108,23 +121,15 @@ i += 1 return i -def is_W_IntObject(w_object): - from pypy.objspace.std.intobject import W_IntObject - return type(w_object) is W_IntObject -def is_W_StringObject(w_object): - from pypy.objspace.std.stringobject import W_StringObject - return type(w_object) is W_StringObject +def list_unroll_condition(w_list1, space, w_list2): + return (jit.loop_unrolling_heuristic(w_list1, w_list1.length(), + UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(w_list2, w_list2.length(), + UNROLL_CUTOFF)) -def is_W_UnicodeObject(w_object): - from pypy.objspace.std.unicodeobject import W_UnicodeObject - return type(w_object) is W_UnicodeObject -def is_W_FloatObject(w_object): - from pypy.objspace.std.floatobject import W_FloatObject - return type(w_object) is W_FloatObject - -class W_ListObject(W_AbstractListObject): +class W_ListObject(W_Root): def __init__(w_self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) w_self.space = space @@ -154,7 +159,8 @@ def __repr__(w_self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, w_self.lstorage._x) + return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, + w_self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -173,7 +179,8 @@ list_w = self.getitems() strategy = self.space.fromcache(ObjectListStrategy) storage = strategy.erase(list_w) - w_objectlist = W_ListObject.from_storage_and_strategy(self.space, storage, strategy) + w_objectlist = W_ListObject.from_storage_and_strategy( + self.space, storage, strategy) return w_objectlist # ___________________________________________________ @@ -209,13 +216,12 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) def append(self, w_item): - 'L.append(object) -- append object to end' + """L.append(object) -- append object to end""" self.strategy.append(self, w_item) def length(self): @@ -228,8 +234,8 @@ return self.strategy.getitem(self, index) def getslice(self, start, stop, step, length): - """Returns a slice of the list defined by the arguments. Arguments must be - normalized (i.e. using normalize_simple_slice or W_Slice.indices4). + """Returns a slice of the list defined by the arguments. Arguments must + be normalized (i.e. using normalize_simple_slice or W_Slice.indices4). May raise IndexError.""" return self.strategy.getslice(self, start, stop, step, length) @@ -246,7 +252,7 @@ def getitems_unroll(self): """Returns a fixed-size list of all items after wrapping them. The JIT - will fully unroll this function. """ + will fully unroll this function.""" l = self.strategy.getitems_unroll(self) debug.make_sure_not_resized(l) return l @@ -257,22 +263,21 @@ return self.strategy.getitems_copy(self) def getitems_str(self): - """ Return the items in the list as unwrapped strings. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped strings. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_str(self) def getitems_unicode(self): - """ Return the items in the list as unwrapped unicodes. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped unicodes. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_unicode(self) def getitems_int(self): - """ Return the items in the list as unwrapped ints. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped ints. If the list does not + use the list strategy, return None.""" return self.strategy.getitems_int(self) # ___________________________________________________ - def mul(self, times): """Returns a copy of the list, multiplied by times. Argument must be unwrapped.""" @@ -326,15 +331,222 @@ argument reverse. Argument must be unwrapped.""" self.strategy.sort(self, reverse) + # exposed to app-level + + @staticmethod + def descr_new(space, w_listtype, __args__): + w_obj = space.allocate_instance(W_ListObject, w_listtype) + w_obj.clear(space) + return w_obj + + def descr_init(self, space, __args__): + # this is on the silly side + w_iterable, = __args__.parse_obj( + None, 'list', init_signature, init_defaults) + self.clear(space) + if w_iterable is not None: + self.extend(w_iterable) + + def descr_repr(self, space): + if self.length() == 0: + return space.wrap('[]') + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return listrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_ListObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) + + @jit.look_inside_iff(list_unroll_condition) + def _descr_eq(self, space, w_other): + # needs to be safe against eq_w() mutating the w_lists behind our back + if self.length() != w_other.length(): + return space.w_False + + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now + i = 0 + while i < self.length() and i < w_other.length(): + if not space.eq_w(self.getitem(i), w_other.getitem(i)): + return space.w_False + i += 1 + return space.w_True + + descr_ne = negate(descr_eq) + + def _make_list_comparison(name): + op = getattr(operator, name) + + def compare_unwrappeditems(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented + return _compare_unwrappeditems(self, space, w_list2) + + @jit.look_inside_iff(list_unroll_condition) + def _compare_unwrappeditems(self, space, w_list2): + # needs to be safe against eq_w() mutating the w_lists behind our + # back + # Search for the first index where items are different + i = 0 + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now + while i < self.length() and i < w_list2.length(): + w_item1 = self.getitem(i) + w_item2 = w_list2.getitem(i) + if not space.eq_w(w_item1, w_item2): + return getattr(space, name)(w_item1, w_item2) + i += 1 + # No more items to compare -- compare sizes + return space.newbool(op(self.length(), w_list2.length())) + + return func_with_new_name(compare_unwrappeditems, name + '__List_List') + + descr_lt = _make_list_comparison('lt') + descr_le = _make_list_comparison('le') + descr_gt = _make_list_comparison('gt') + descr_ge = _make_list_comparison('ge') + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + + def descr_iter(self, space): + return W_FastListIterObject(self) + + def descr_contains(self, space, w_obj): + try: + self.find(w_obj) + return space.w_True + except ValueError: + return space.w_False + + def descr_add(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented + w_clone = self.clone() + w_clone.extend(w_list2) + return w_clone + + def descr_inplace_add(self, space, w_iterable): + if isinstance(w_iterable, W_ListObject): + self.extend(w_iterable) + return self + + try: + self.extend(w_iterable) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self.mul(times) + + def descr_inplace_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + self.inplace_mul(times) + return self + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + # XXX consider to extend rlist's functionality? + length = self.length() + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, step, slicelength) + + try: + index = space.getindex_w(w_index, space.w_IndexError, "list index") + return self.getitem(index) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + + slicelength = stop - start + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, 1, stop - start) + + def descr_setitem(self, space, w_index, w_any): + if isinstance(w_index, W_SliceObject): + oldsize = self.length() + start, stop, step, slicelength = w_index.indices4(space, oldsize) + if isinstance(w_any, W_ListObject): + self.setslice(start, step, slicelength, w_any) + else: + sequence_w = space.listview(w_any) + w_other = W_ListObject(space, sequence_w) + self.setslice(start, step, slicelength, w_other) + return + + idx = space.getindex_w(w_index, space.w_IndexError, "list index") + try: + self.setitem(idx, w_any) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_setslice(self, space, w_start, w_stop, w_iterable): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + + if isinstance(w_iterable, W_ListObject): + self.setslice(start, 1, stop - start, w_iterable) + else: + sequence_w = space.listview(w_iterable) + w_other = W_ListObject(space, sequence_w) + self.setslice(start, 1, stop - start, w_other) + + def descr_delitem(self, space, w_idx): + if isinstance(w_idx, W_SliceObject): + start, stop, step, slicelength = w_idx.indices4( + space, self.length()) + self.deleteslice(start, step, slicelength) + return + + idx = space.getindex_w(w_idx, space.w_IndexError, "list index") + if idx < 0: + idx += self.length() + try: + self.pop(idx) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_delslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + self.deleteslice(start, 1, stop - start) + def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject return W_ReverseSeqIterObject(space, self, -1) def descr_reverse(self, space): 'L.reverse() -- reverse *IN PLACE*' self.reverse() - return space.w_None def descr_count(self, space, w_value): '''L.count(value) -> integer -- return number of @@ -354,7 +566,6 @@ length = self.length() index = get_positive_index(index, length) self.insert(index, w_value) - return space.w_None @unwrap_spec(index=int) def descr_pop(self, space, index=-1): @@ -366,7 +577,7 @@ space.wrap("pop from empty list")) # clearly differentiate between list.pop() and list.pop(index) if index == -1: - return self.pop_end() # cannot raise because list is not empty + return self.pop_end() # cannot raise because list is not empty if index < 0: index += length try: @@ -383,9 +594,8 @@ except ValueError: raise OperationError(space.w_ValueError, space.wrap("list.remove(x): x not in list")) - if i < self.length(): # otherwise list was mutated + if i < self.length(): # otherwise list was mutated self.pop(i) - return space.w_None @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(maxint)) def descr_index(self, space, w_value, w_start, w_stop): @@ -424,7 +634,7 @@ sorterclass = SimpleSort else: self.sort(reverse) - return space.w_None + return sorter = sorterclass(self.getitems(), self.length()) sorter.space = space @@ -474,10 +684,6 @@ raise OperationError(space.w_ValueError, space.wrap("list modified during sort")) - return space.w_None - -registerimplementation(W_ListObject) - class ListStrategy(object): sizehint = -1 @@ -602,7 +808,8 @@ The storage is None. When items are added to the W_List a new RPython list is created and the strategy and storage of the W_List are changed depending to the added item. - W_Lists do not switch back to EmptyListStrategy when becoming empty again.""" + W_Lists do not switch back to EmptyListStrategy when becoming empty again. + """ _applevel_repr = "empty" @@ -621,7 +828,8 @@ unerase = staticmethod(unerase) def clone(self, w_list): - return W_ListObject.from_storage_and_strategy(self.space, w_list.lstorage, self) + return W_ListObject.from_storage_and_strategy( + self.space, w_list.lstorage, self) def copy_into(self, w_list, w_other): pass @@ -650,20 +858,21 @@ def getitems_copy(self, w_list): return [] - getitems_fixedsize = func_with_new_name(getitems_copy, "getitems_fixedsize") + getitems_fixedsize = func_with_new_name(getitems_copy, + "getitems_fixedsize") getitems_unroll = getitems_fixedsize def getstorage_copy(self, w_list): return self.erase(None) def switch_to_correct_strategy(self, w_list, w_item): - if is_W_IntObject(w_item): + if type(w_item) is W_IntObject: strategy = self.space.fromcache(IntegerListStrategy) - elif is_W_StringObject(w_item): + elif type(w_item) is W_StringObject: strategy = self.space.fromcache(StringListStrategy) - elif is_W_UnicodeObject(w_item): + elif type(w_item) is W_UnicodeObject: strategy = self.space.fromcache(UnicodeListStrategy) - elif is_W_FloatObject(w_item): + elif type(w_item) is W_FloatObject: strategy = self.space.fromcache(FloatListStrategy) else: strategy = self.space.fromcache(ObjectListStrategy) @@ -707,7 +916,6 @@ w_other.copy_into(w_list) def _extend_from_iterable(self, w_list, w_iterable): - from pypy.objspace.std.tupleobject import W_AbstractTupleObject space = self.space if isinstance(w_iterable, W_AbstractTupleObject): w_list.__init__(space, w_iterable.getitems_copy()) @@ -742,9 +950,9 @@ def is_empty_strategy(self): return True + class SizeListStrategy(EmptyListStrategy): - """ Like empty, but when modified it'll preallocate the size to sizehint - """ + """Like empty, but when modified it'll preallocate the size to sizehint.""" def __init__(self, space, sizehint): self.sizehint = sizehint ListStrategy.__init__(self, space) @@ -753,12 +961,13 @@ assert hint >= 0 self.sizehint = hint + class RangeListStrategy(ListStrategy): """RangeListStrategy is used when a list is created using the range method. - The storage is a tuple containing only three integers start, step and length - and elements are calculated based on these values. - On any operation destroying the range (inserting, appending non-ints) - the strategy is switched to IntegerListStrategy.""" + The storage is a tuple containing only three integers start, step and + length and elements are calculated based on these values. On any operation + destroying the range (inserting, appending non-ints) the strategy is + switched to IntegerListStrategy.""" _applevel_repr = "range" @@ -781,8 +990,9 @@ unerase = staticmethod(unerase) def clone(self, w_list): - storage = w_list.lstorage # lstorage is tuple, no need to clone - w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self) + storage = w_list.lstorage # lstorage is tuple, no need to clone + w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, + self) return w_clone def _resize_hint(self, w_list, hint): @@ -794,11 +1004,13 @@ w_other.lstorage = w_list.lstorage def find(self, w_list, w_obj, startindex, stopindex): - if is_W_IntObject(w_obj): + if type(w_obj) is W_IntObject: obj = self.unwrap(w_obj) start, step, length = self.unerase(w_list.lstorage) - if ((step > 0 and start <= obj <= start + (length - 1) * step and (start - obj) % step == 0) or - (step < 0 and start + (length - 1) * step <= obj <= start and (start - obj) % step == 0)): + if ((step > 0 and start <= obj <= start + (length - 1) * step and + (start - obj) % step == 0) or + (step < 0 and start + (length - 1) * step <= obj <= start and + (start - obj) % step == 0)): index = (obj - start) // step else: raise ValueError @@ -861,16 +1073,18 @@ @jit.dont_look_inside def getitems_fixedsize(self, w_list): return self._getitems_range_unroll(w_list, True) + def getitems_unroll(self, w_list): return self._getitems_range_unroll(w_list, True) - _getitems_range_unroll = jit.unroll_safe(func_with_new_name(_getitems_range, "_getitems_range_unroll")) + _getitems_range_unroll = jit.unroll_safe( + func_with_new_name(_getitems_range, "_getitems_range_unroll")) def getslice(self, w_list, start, stop, step, length): self.switch_to_integer_strategy(w_list) return w_list.getslice(start, stop, step, length) def append(self, w_list, w_item): - if is_W_IntObject(w_item): + if type(w_item) is W_IntObject: self.switch_to_integer_strategy(w_list) else: w_list.switch_to_object_strategy() @@ -933,6 +1147,7 @@ self.switch_to_integer_strategy(w_list) w_list.reverse() + class AbstractUnwrappedStrategy(object): _mixin_ = True @@ -970,7 +1185,8 @@ def clone(self, w_list): l = self.unerase(w_list.lstorage) storage = self.erase(l[:]) - w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self) + w_clone = W_ListObject.from_storage_and_strategy( + self.space, storage, self) return w_clone def _resize_hint(self, w_list, hint): @@ -1001,12 +1217,13 @@ l = self.unerase(w_list.lstorage) try: r = l[index] - except IndexError: # make RPython raise the exception + except IndexError: # make RPython raise the exception raise return self.wrap(r) @jit.look_inside_iff(lambda self, w_list: - jit.loop_unrolling_heuristic(w_list, w_list.length(), UNROLL_CUTOFF)) + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF)) def getitems_copy(self, w_list): return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @@ -1015,7 +1232,8 @@ return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @jit.look_inside_iff(lambda self, w_list: - jit.loop_unrolling_heuristic(w_list, w_list.length(), UNROLL_CUTOFF)) + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF)) def getitems_fixedsize(self, w_list): return self.getitems_unroll(w_list) @@ -1030,7 +1248,8 @@ assert stop >= 0 sublist = l[start:stop] storage = self.erase(sublist) - return W_ListObject.from_storage_and_strategy(self.space, storage, self) + return W_ListObject.from_storage_and_strategy( + self.space, storage, self) else: subitems_w = [self._none_value] * length l = self.unerase(w_list.lstorage) @@ -1041,9 +1260,10 @@ except IndexError: raise storage = self.erase(subitems_w) - return W_ListObject.from_storage_and_strategy(self.space, storage, self) + return W_ListObject.from_storage_and_strategy( + self.space, storage, self) - def append(self, w_list, w_item): + def append(self, w_list, w_item): if self.is_correct_type(w_item): self.unerase(w_list.lstorage).append(self.unwrap(w_item)) return @@ -1092,11 +1312,11 @@ if self is self.space.fromcache(ObjectListStrategy): w_other = w_other._temporarily_as_objects() - elif (not self.list_is_correct_type(w_other) and - w_other.length() != 0): + elif not self.list_is_correct_type(w_other) and w_other.length() != 0: w_list.switch_to_object_strategy() w_other_as_object = w_other._temporarily_as_objects() - assert w_other_as_object.strategy is self.space.fromcache(ObjectListStrategy) + assert (w_other_as_object.strategy is + self.space.fromcache(ObjectListStrategy)) w_list.setslice(start, step, slicelength, w_other_as_object) return @@ -1112,13 +1332,14 @@ lim = start + len2 i = newsize - 1 while i >= lim: - items[i] = items[i-delta] + items[i] = items[i - delta] i -= 1 elif delta == 0: pass else: - assert start >= 0 # start<0 is only possible with slicelength==0 - del items[start:start+delta] + # start < 0 is only possible with slicelength == 0 + assert start >= 0 + del items[start:start + delta] elif len2 != slicelength: # No resize for extended slices raise operationerrfmt(self.space.w_ValueError, "attempt to " "assign sequence of size %d to extended slice of size %d", @@ -1163,7 +1384,7 @@ if step == 1: assert start >= 0 if slicelength > 0: - del items[start:start+slicelength] + del items[start:start + slicelength] else: n = len(items) i = start @@ -1172,15 +1393,15 @@ j = i + 1 i += step while j < i: - items[j-discard] = items[j] + items[j - discard] = items[j] j += 1 j = i + 1 while j < n: - items[j-slicelength] = items[j] + items[j - slicelength] = items[j] j += 1 start = n - slicelength - assert start >= 0 # annotator hint + assert start >= 0 # annotator hint del items[start:] def pop_end(self, w_list): @@ -1213,6 +1434,7 @@ def reverse(self, w_list): self.unerase(w_list.lstorage).reverse() + class ObjectListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "object" @@ -1245,6 +1467,7 @@ def getitems(self, w_list): return self.unerase(w_list.lstorage) + class IntegerListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = 0 _applevel_repr = "int" @@ -1260,7 +1483,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_IntObject(w_obj) + return type(w_obj) is W_IntObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(IntegerListStrategy) @@ -1275,6 +1498,7 @@ def getitems_int(self, w_list): return self.unerase(w_list.lstorage) + class FloatListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = 0.0 _applevel_repr = "float" @@ -1290,7 +1514,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_FloatObject(w_obj) + return type(w_obj) is W_FloatObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(FloatListStrategy) @@ -1302,6 +1526,7 @@ if reverse: l.reverse() + class StringListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "str" @@ -1317,7 +1542,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_StringObject(w_obj) + return type(w_obj) is W_StringObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(StringListStrategy) @@ -1348,7 +1573,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_UnicodeObject(w_obj) + return type(w_obj) is W_UnicodeObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(UnicodeListStrategy) @@ -1368,196 +1593,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def init__List(space, w_list, __args__): - # this is on the silly side - w_iterable, = __args__.parse_obj( - None, 'list', init_signature, init_defaults) - w_list.clear(space) - if w_iterable is not None: - w_list.extend(w_iterable) - -def len__List(space, w_list): - result = w_list.length() - return wrapint(space, result) - -def getitem__List_ANY(space, w_list, w_index): - try: - return w_list.getitem(get_list_index(space, w_index)) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - -def getitem__List_Slice(space, w_list, w_slice): - # XXX consider to extend rlist's functionality? - length = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - if slicelength == 0: - return make_empty_list(space) - return w_list.getslice(start, stop, step, slicelength) - -def getslice__List_ANY_ANY(space, w_list, w_start, w_stop): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - - slicelength = stop - start - if slicelength == 0: - return make_empty_list(space) - return w_list.getslice(start, stop, 1, stop - start) - -def setslice__List_ANY_ANY_List(space, w_list, w_start, w_stop, w_other): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - w_list.setslice(start, 1, stop-start, w_other) - -def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - sequence_w = space.listview(w_iterable) - w_other = W_ListObject(space, sequence_w) - w_list.setslice(start, 1, stop-start, w_other) - -def delslice__List_ANY_ANY(space, w_list, w_start, w_stop): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - w_list.deleteslice(start, 1, stop-start) - -def contains__List_ANY(space, w_list, w_obj): - try: - w_list.find(w_obj) - return space.w_True - except ValueError: - return space.w_False - -def iter__List(space, w_list): - from pypy.objspace.std import iterobject - return iterobject.W_FastListIterObject(w_list) - -def add__List_List(space, w_list1, w_list2): - w_clone = w_list1.clone() - w_clone.extend(w_list2) - return w_clone - -def inplace_add__List_ANY(space, w_list1, w_iterable2): - try: - w_list1.extend(w_iterable2) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - return w_list1 - -def inplace_add__List_List(space, w_list1, w_list2): - w_list1.extend(w_list2) - return w_list1 - -def mul_list_times(space, w_list, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - return w_list.mul(times) - -def mul__List_ANY(space, w_list, w_times): - return mul_list_times(space, w_list, w_times) - -def mul__ANY_List(space, w_times, w_list): - return mul_list_times(space, w_list, w_times) - -def inplace_mul__List_ANY(space, w_list, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - w_list.inplace_mul(times) - return w_list - -def list_unroll_condition(space, w_list1, w_list2): - return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) - - at jit.look_inside_iff(list_unroll_condition) -def eq__List_List(space, w_list1, w_list2): - # needs to be safe against eq_w() mutating the w_lists behind our back - if w_list1.length() != w_list2.length(): - return space.w_False - - # XXX in theory, this can be implemented more efficiently as well. let's - # not care for now - i = 0 - while i < w_list1.length() and i < w_list2.length(): - if not space.eq_w(w_list1.getitem(i), w_list2.getitem(i)): - return space.w_False - i += 1 - return space.w_True - -def _make_list_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(list_unroll_condition) - def compare_unwrappeditems(space, w_list1, w_list2): - # needs to be safe against eq_w() mutating the w_lists behind our back - # Search for the first index where items are different - i = 0 - # XXX in theory, this can be implemented more efficiently as well. - # let's not care for now - while i < w_list1.length() and i < w_list2.length(): - w_item1 = w_list1.getitem(i) - w_item2 = w_list2.getitem(i) - if not space.eq_w(w_item1, w_item2): - return getattr(space, name)(w_item1, w_item2) - i += 1 - # No more items to compare -- compare sizes - return space.newbool(op(w_list1.length(), w_list2.length())) - return func_with_new_name(compare_unwrappeditems, name + '__List_List') - -lt__List_List = _make_list_comparison('lt') -le__List_List = _make_list_comparison('le') -gt__List_List = _make_list_comparison('gt') -ge__List_List = _make_list_comparison('ge') - -def delitem__List_ANY(space, w_list, w_idx): - idx = get_list_index(space, w_idx) - if idx < 0: - idx += w_list.length() - try: - w_list.pop(idx) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list deletion index out of range")) - return space.w_None - - -def delitem__List_Slice(space, w_list, w_slice): - start, stop, step, slicelength = w_slice.indices4(space, w_list.length()) - w_list.deleteslice(start, step, slicelength) - -def setitem__List_ANY_ANY(space, w_list, w_index, w_any): - idx = get_list_index(space, w_index) - try: - w_list.setitem(idx, w_any) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - return space.w_None - -def setitem__List_Slice_List(space, w_list, w_slice, w_other): - oldsize = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, oldsize) - w_list.setslice(start, step, slicelength, w_other) - -def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable): - oldsize = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, oldsize) - sequence_w = space.listview(w_iterable) - w_other = W_ListObject(space, sequence_w) - w_list.setslice(start, step, slicelength, w_other) - app = applevel(""" def listrepr(currently_in_repr, l): 'The app-level part of repr().' @@ -1576,25 +1611,6 @@ listrepr = app.interphook("listrepr") -def repr__List(space, w_list): - if w_list.length() == 0: - return space.wrap('[]') - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return listrepr(space, w_currently_in_repr, w_list) - -def get_positive_index(where, length): - if where < 0: - where += length - if where < 0: - where = 0 - elif where > length: - where = length - assert where >= 0 - return where - # ____________________________________________________________ # Sorting @@ -1607,11 +1623,13 @@ StringBaseTimSort = make_timsort_class() UnicodeBaseTimSort = make_timsort_class() -class KeyContainer(baseobjspace.W_Root): + +class KeyContainer(W_Root): def __init__(self, w_key, w_item): self.w_key = w_key self.w_item = w_item + # NOTE: all the subclasses of TimSort should inherit from a common subclass, # so make sure that only SimpleSort inherits directly from TimSort. # This is necessary to hide the parent method TimSort.lt() from the @@ -1621,22 +1639,27 @@ space = self.space return space.is_true(space.lt(a, b)) + class IntSort(IntBaseTimSort): def lt(self, a, b): return a < b + class FloatSort(FloatBaseTimSort): def lt(self, a, b): return a < b + class StringSort(StringBaseTimSort): def lt(self, a, b): return a < b + class UnicodeSort(UnicodeBaseTimSort): def lt(self, a, b): return a < b + class CustomCompareSort(SimpleSort): def lt(self, a, b): space = self.space @@ -1651,6 +1674,7 @@ raise return result < 0 + class CustomKeySort(SimpleSort): def lt(self, a, b): assert isinstance(a, KeyContainer) @@ -1658,33 +1682,46 @@ space = self.space return space.is_true(space.lt(a.w_key, b.w_key)) + class CustomKeyCompareSort(CustomCompareSort): def lt(self, a, b): assert isinstance(a, KeyContainer) assert isinstance(b, KeyContainer) return CustomCompareSort.lt(self, a.w_key, b.w_key) -# ____________________________________________________________ - -def descr_new(space, w_listtype, __args__): - w_obj = space.allocate_instance(W_ListObject, w_listtype) - w_obj.clear(space) - return w_obj - -# ____________________________________________________________ - -# ____________________________________________________________ - -def get_list_index(space, w_index): - return space.getindex_w(w_index, space.w_IndexError, "list index") - -register_all(vars(), globals()) W_ListObject.typedef = StdTypeDef("list", __doc__ = """list() -> new list list(sequence) -> new list initialized from sequence's items""", - __new__ = interp2app(descr_new), + __new__ = interp2app(W_ListObject.descr_new), + __init__ = interp2app(W_ListObject.descr_init), + __repr__ = interp2app(W_ListObject.descr_repr), __hash__ = None, + + __eq__ = interp2app(W_ListObject.descr_eq), + __ne__ = interp2app(W_ListObject.descr_ne), + __lt__ = interp2app(W_ListObject.descr_lt), + __le__ = interp2app(W_ListObject.descr_le), + __gt__ = interp2app(W_ListObject.descr_gt), + __ge__ = interp2app(W_ListObject.descr_ge), + + __len__ = interp2app(W_ListObject.descr_len), + __iter__ = interp2app(W_ListObject.descr_iter), + __contains__ = interp2app(W_ListObject.descr_contains), + + __add__ = interp2app(W_ListObject.descr_add), + __iadd__ = interp2app(W_ListObject.descr_inplace_add), + __mul__ = interp2app(W_ListObject.descr_mul), + __rmul__ = interp2app(W_ListObject.descr_mul), + __imul__ = interp2app(W_ListObject.descr_inplace_mul), + + __getitem__ = interp2app(W_ListObject.descr_getitem), + __getslice__ = interp2app(W_ListObject.descr_getslice), + __setitem__ = interp2app(W_ListObject.descr_setitem), + __setslice__ = interp2app(W_ListObject.descr_setslice), + __delitem__ = interp2app(W_ListObject.descr_delitem), + __delslice__ = interp2app(W_ListObject.descr_delslice), + sort = interp2app(W_ListObject.descr_sort), index = interp2app(W_ListObject.descr_index), append = interp2app(W_ListObject.append), @@ -1695,7 +1732,4 @@ extend = interp2app(W_ListObject.extend), insert = interp2app(W_ListObject.descr_insert), remove = interp2app(W_ListObject.descr_remove), - ) -W_ListObject.typedef.registermethods(globals()) - -list_typedef = W_ListObject.typedef +) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -297,17 +297,17 @@ return space.newtuple(items_w) register(TYPE_TUPLE, unmarshal_Tuple) -def marshal_w__List(space, w_list, m): +def marshal_list(space, w_list, m): + if not isinstance(w_list, W_ListObject): + raise_exception(space, "unmarshallable object") items = w_list.getitems()[:] m.put_tuple_w(TYPE_LIST, items) +handled_by_any.append(('list', marshal_list)) -def unmarshal_List(space, u, tc): +def unmarshal_list(space, u, tc): items_w = u.get_list_w() return space.newlist(items_w) - -def finish_List(space, items_w, typecode): - return space.newlist(items_w) -register(TYPE_LIST, unmarshal_List) +register(TYPE_LIST, unmarshal_list) def marshal_w_dict(space, w_dict, m): if not isinstance(w_dict, W_DictMultiObject): diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -39,7 +39,6 @@ from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef - from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -80,6 +79,7 @@ # not-multimethod based types + self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -91,7 +91,6 @@ intobject.W_IntObject: [], floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], - listobject.W_ListObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -109,11 +108,6 @@ } self.imported_but_not_registered = { - dictmultiobject.W_DictMultiObject: True, # XXXXXX - dictmultiobject.W_DictMultiIterKeysObject: True, - dictmultiobject.W_DictMultiIterValuesObject: True, - dictmultiobject.W_DictMultiIterItemsObject: True, - listobject.W_ListObject: True, stringobject.W_StringObject: True, tupleobject.W_TupleObject: True, } diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -783,6 +783,8 @@ assert l == [1,2,3,4,5] def test_iadd_subclass(self): + #XXX + skip("Maybe there is something wrong in descroperation?") class Bar(object): def __radd__(self, other): return ('radd', self, other) @@ -1306,6 +1308,12 @@ def test_use_method_for_wrong_object(self): raises(TypeError, list.append.im_func, 1, 2) + def test_ne_NotImplemented(self): + class NonList(object): + pass + non_list = NonList() + assert [] != non_list + class AppTestForRangeLists(AppTestW_ListObject): spaceconfig = {"objspace.std.withrangelist": True} diff --git a/pypy/objspace/std/test/test_liststrategies.py b/pypy/objspace/std/test/test_liststrategies.py --- a/pypy/objspace/std/test/test_liststrategies.py +++ b/pypy/objspace/std/test/test_liststrategies.py @@ -488,15 +488,13 @@ def test_weird_rangelist_bug(self): l = make_range_list(self.space, 1, 1, 3) - from pypy.objspace.std.listobject import getslice__List_ANY_ANY # should not raise - assert getslice__List_ANY_ANY(self.space, l, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy) + assert l.descr_getslice(self.space, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy) def test_add_to_rangelist(self): l1 = make_range_list(self.space, 1, 1, 3) l2 = W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5)]) - from pypy.objspace.std.listobject import add__List_List - l3 = add__List_List(self.space, l1, l2) + l3 = l1.descr_add(self.space, l2) assert self.space.eq_w(l3, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3), self.space.wrap(4), self.space.wrap(5)])) def test_unicode(self): diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py --- a/pypy/objspace/std/test/test_stdobjspace.py +++ b/pypy/objspace/std/test/test_stdobjspace.py @@ -23,19 +23,6 @@ raises(OperationError,self.space.uint_w,self.space.wrap(None)) raises(OperationError,self.space.uint_w,self.space.wrap("")) - def test_multimethods_defined_on(self): - from pypy.objspace.std.stdtypedef import multimethods_defined_on - from pypy.objspace.std.listobject import W_ListObject - res = multimethods_defined_on(W_ListObject) - res = [(m.name, local) for (m, local) in res] - assert ('add', False) in res - assert ('lt', False) in res - assert ('setitem', False) in res - assert ('mod', False) not in res - assert ('pop', True) not in res - assert ('reverse', True) not in res - assert ('popitem', True) not in res - def test_sliceindices(self): space = self.space w_obj = space.appexec([], """(): diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/util.py @@ -0,0 +1,27 @@ +def negate(f): + """Create a function which calls `f` and negates its result. When the + result is ``space.w_NotImplemented``, ``space.w_NotImplemented`` is + returned. This is useful for complementing e.g. the __ne__ descriptor if + your type already defines a __eq__ descriptor. + """ + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator + +def get_positive_index(where, length): + if where < 0: + where += length + if where < 0: + where = 0 + elif where > length: + where = length + assert where >= 0 + return where From noreply at buildbot.pypy.org Tue May 21 15:10:18 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 15:10:18 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Return space.w_NotImplemented instead of raising FailedToImplement. Message-ID: <20130521131018.CA3451C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64386:dcc83031be74 Date: 2013-05-21 14:57 +0200 http://bitbucket.org/pypy/pypy/changeset/dcc83031be74/ Log: Return space.w_NotImplemented instead of raising FailedToImplement. diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -3,7 +3,6 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement from rpython.rlib.rarithmetic import intmask from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std import slicetype @@ -153,7 +152,7 @@ times = space.getindex_w(w_times, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - raise FailedToImplement + return space.w_NotImplemented raise if times == 1 and space.type(self) == space.w_tuple: return self From noreply at buildbot.pypy.org Tue May 21 15:10:20 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 15:10:20 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Document branch remove-list-smm-2. Message-ID: <20130521131020.60A1C1C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64387:a26cd36bc793 Date: 2013-05-21 15:07 +0200 http://bitbucket.org/pypy/pypy/changeset/a26cd36bc793/ Log: Document branch remove-list-smm-2. 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 @@ -22,3 +22,6 @@ .. branch: remove-dict-smm Remove multi-methods on dict + +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list From noreply at buildbot.pypy.org Tue May 21 15:10:21 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 15:10:21 +0200 (CEST) Subject: [pypy-commit] pypy remove-list-smm-2: Close to-be-merged branch. Message-ID: <20130521131021.BF1F21C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-list-smm-2 Changeset: r64388:daca18c6c8ad Date: 2013-05-21 15:07 +0200 http://bitbucket.org/pypy/pypy/changeset/daca18c6c8ad/ Log: Close to-be-merged branch. From noreply at buildbot.pypy.org Tue May 21 15:10:23 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 15:10:23 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge remove-list-smm-2 Message-ID: <20130521131023.45BAA1C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64389:93322cb79586 Date: 2013-05-21 15:07 +0200 http://bitbucket.org/pypy/pypy/changeset/93322cb79586/ Log: hg merge remove-list-smm-2 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 @@ -22,3 +22,6 @@ .. branch: remove-dict-smm Remove multi-methods on dict + +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -8,7 +8,6 @@ getbytevalue, makebytearraydata_w, new_bytearray) from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.listobject import get_list_index, get_positive_index from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject @@ -17,6 +16,7 @@ from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -587,7 +587,7 @@ _setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00') def delitem__Bytearray_ANY(space, w_bytearray, w_idx): - idx = get_list_index(space, w_idx) + idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray index") try: del w_bytearray.data[idx] except IndexError: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -5,6 +5,7 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null @@ -41,19 +42,6 @@ w_dct.length() <= UNROLL_CUTOFF) -def negate(f): - def _negator(self, space, w_other): - # no need to use space.is_ / space.not_ - tmp = f(self, space, w_other) - if tmp is space.w_NotImplemented: - return space.w_NotImplemented - elif tmp is space.w_False: - return space.w_True - else: - return space.w_False - _negator.func_name = 'negate-%s' % f.func_name - return _negator - class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,27 +1,35 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement +import operator +from sys import maxint + +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import (WrappedDefault, unwrap_spec, applevel, + interp2app) from pypy.interpreter.generator import GeneratorIterator +from pypy.interpreter.signature import Signature +from pypy.objspace.std import slicetype +from pypy.objspace.std.floatobject import W_FloatObject +from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.iterobject import (W_FastListIterObject, + W_ReverseSeqIterObject) from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.interpreter.gateway import WrappedDefault, unwrap_spec, applevel,\ - interp2app -from pypy.interpreter import baseobjspace -from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject +from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.util import negate, get_positive_index +from rpython.rlib import rerased, jit, debug +from rpython.rlib.listsort import make_timsort_class from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) -from rpython.rlib.listsort import make_timsort_class -from rpython.rlib import rerased, jit, debug + resizelist_hint) from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from sys import maxint + +__all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] + UNROLL_CUTOFF = 5 -class W_AbstractListObject(W_Object): - __slots__ = () def make_range_list(space, start, step, length): if length <= 0: @@ -32,16 +40,19 @@ storage = strategy.erase((start, step, length)) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list(space): strategy = space.fromcache(EmptyListStrategy) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list_with_size(space, hint): strategy = SizeListStrategy(space, hint) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + @jit.look_inside_iff(lambda space, list_w, sizehint: jit.loop_unrolling_heuristic(list_w, len(list_w), UNROLL_CUTOFF)) def get_strategy_from_list_objects(space, list_w, sizehint): @@ -52,38 +63,40 @@ # check for ints for w_obj in list_w: - if not is_W_IntObject(w_obj): + if not type(w_obj) is W_IntObject: break else: return space.fromcache(IntegerListStrategy) # check for strings for w_obj in list_w: - if not is_W_StringObject(w_obj): + if not type(w_obj) is W_StringObject: break else: return space.fromcache(StringListStrategy) # check for unicode for w_obj in list_w: - if not is_W_UnicodeObject(w_obj): + if not type(w_obj) is W_UnicodeObject: break else: return space.fromcache(UnicodeListStrategy) # check for floats for w_obj in list_w: - if not is_W_FloatObject(w_obj): + if not type(w_obj) is W_FloatObject: break else: return space.fromcache(FloatListStrategy) return space.fromcache(ObjectListStrategy) + def _get_printable_location(w_type): return ('list__do_extend_from_iterable [w_type=%s]' % w_type.getname(w_type.space)) + _do_extend_jitdriver = jit.JitDriver( name='list__do_extend_from_iterable', greens=['w_type'], @@ -108,23 +121,15 @@ i += 1 return i -def is_W_IntObject(w_object): - from pypy.objspace.std.intobject import W_IntObject - return type(w_object) is W_IntObject -def is_W_StringObject(w_object): - from pypy.objspace.std.stringobject import W_StringObject - return type(w_object) is W_StringObject +def list_unroll_condition(w_list1, space, w_list2): + return (jit.loop_unrolling_heuristic(w_list1, w_list1.length(), + UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(w_list2, w_list2.length(), + UNROLL_CUTOFF)) -def is_W_UnicodeObject(w_object): - from pypy.objspace.std.unicodeobject import W_UnicodeObject - return type(w_object) is W_UnicodeObject -def is_W_FloatObject(w_object): - from pypy.objspace.std.floatobject import W_FloatObject - return type(w_object) is W_FloatObject - -class W_ListObject(W_AbstractListObject): +class W_ListObject(W_Root): def __init__(w_self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) w_self.space = space @@ -154,7 +159,8 @@ def __repr__(w_self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, w_self.lstorage._x) + return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, + w_self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -173,7 +179,8 @@ list_w = self.getitems() strategy = self.space.fromcache(ObjectListStrategy) storage = strategy.erase(list_w) - w_objectlist = W_ListObject.from_storage_and_strategy(self.space, storage, strategy) + w_objectlist = W_ListObject.from_storage_and_strategy( + self.space, storage, strategy) return w_objectlist # ___________________________________________________ @@ -209,13 +216,12 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) def append(self, w_item): - 'L.append(object) -- append object to end' + """L.append(object) -- append object to end""" self.strategy.append(self, w_item) def length(self): @@ -228,8 +234,8 @@ return self.strategy.getitem(self, index) def getslice(self, start, stop, step, length): - """Returns a slice of the list defined by the arguments. Arguments must be - normalized (i.e. using normalize_simple_slice or W_Slice.indices4). + """Returns a slice of the list defined by the arguments. Arguments must + be normalized (i.e. using normalize_simple_slice or W_Slice.indices4). May raise IndexError.""" return self.strategy.getslice(self, start, stop, step, length) @@ -246,7 +252,7 @@ def getitems_unroll(self): """Returns a fixed-size list of all items after wrapping them. The JIT - will fully unroll this function. """ + will fully unroll this function.""" l = self.strategy.getitems_unroll(self) debug.make_sure_not_resized(l) return l @@ -257,22 +263,21 @@ return self.strategy.getitems_copy(self) def getitems_str(self): - """ Return the items in the list as unwrapped strings. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped strings. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_str(self) def getitems_unicode(self): - """ Return the items in the list as unwrapped unicodes. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped unicodes. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_unicode(self) def getitems_int(self): - """ Return the items in the list as unwrapped ints. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped ints. If the list does not + use the list strategy, return None.""" return self.strategy.getitems_int(self) # ___________________________________________________ - def mul(self, times): """Returns a copy of the list, multiplied by times. Argument must be unwrapped.""" @@ -326,15 +331,222 @@ argument reverse. Argument must be unwrapped.""" self.strategy.sort(self, reverse) + # exposed to app-level + + @staticmethod + def descr_new(space, w_listtype, __args__): + w_obj = space.allocate_instance(W_ListObject, w_listtype) + w_obj.clear(space) + return w_obj + + def descr_init(self, space, __args__): + # this is on the silly side + w_iterable, = __args__.parse_obj( + None, 'list', init_signature, init_defaults) + self.clear(space) + if w_iterable is not None: + self.extend(w_iterable) + + def descr_repr(self, space): + if self.length() == 0: + return space.wrap('[]') + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return listrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_ListObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) + + @jit.look_inside_iff(list_unroll_condition) + def _descr_eq(self, space, w_other): + # needs to be safe against eq_w() mutating the w_lists behind our back + if self.length() != w_other.length(): + return space.w_False + + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now + i = 0 + while i < self.length() and i < w_other.length(): + if not space.eq_w(self.getitem(i), w_other.getitem(i)): + return space.w_False + i += 1 + return space.w_True + + descr_ne = negate(descr_eq) + + def _make_list_comparison(name): + op = getattr(operator, name) + + def compare_unwrappeditems(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented + return _compare_unwrappeditems(self, space, w_list2) + + @jit.look_inside_iff(list_unroll_condition) + def _compare_unwrappeditems(self, space, w_list2): + # needs to be safe against eq_w() mutating the w_lists behind our + # back + # Search for the first index where items are different + i = 0 + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now + while i < self.length() and i < w_list2.length(): + w_item1 = self.getitem(i) + w_item2 = w_list2.getitem(i) + if not space.eq_w(w_item1, w_item2): + return getattr(space, name)(w_item1, w_item2) + i += 1 + # No more items to compare -- compare sizes + return space.newbool(op(self.length(), w_list2.length())) + + return func_with_new_name(compare_unwrappeditems, name + '__List_List') + + descr_lt = _make_list_comparison('lt') + descr_le = _make_list_comparison('le') + descr_gt = _make_list_comparison('gt') + descr_ge = _make_list_comparison('ge') + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + + def descr_iter(self, space): + return W_FastListIterObject(self) + + def descr_contains(self, space, w_obj): + try: + self.find(w_obj) + return space.w_True + except ValueError: + return space.w_False + + def descr_add(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented + w_clone = self.clone() + w_clone.extend(w_list2) + return w_clone + + def descr_inplace_add(self, space, w_iterable): + if isinstance(w_iterable, W_ListObject): + self.extend(w_iterable) + return self + + try: + self.extend(w_iterable) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self.mul(times) + + def descr_inplace_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + self.inplace_mul(times) + return self + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + # XXX consider to extend rlist's functionality? + length = self.length() + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, step, slicelength) + + try: + index = space.getindex_w(w_index, space.w_IndexError, "list index") + return self.getitem(index) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + + slicelength = stop - start + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, 1, stop - start) + + def descr_setitem(self, space, w_index, w_any): + if isinstance(w_index, W_SliceObject): + oldsize = self.length() + start, stop, step, slicelength = w_index.indices4(space, oldsize) + if isinstance(w_any, W_ListObject): + self.setslice(start, step, slicelength, w_any) + else: + sequence_w = space.listview(w_any) + w_other = W_ListObject(space, sequence_w) + self.setslice(start, step, slicelength, w_other) + return + + idx = space.getindex_w(w_index, space.w_IndexError, "list index") + try: + self.setitem(idx, w_any) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_setslice(self, space, w_start, w_stop, w_iterable): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + + if isinstance(w_iterable, W_ListObject): + self.setslice(start, 1, stop - start, w_iterable) + else: + sequence_w = space.listview(w_iterable) + w_other = W_ListObject(space, sequence_w) + self.setslice(start, 1, stop - start, w_other) + + def descr_delitem(self, space, w_idx): + if isinstance(w_idx, W_SliceObject): + start, stop, step, slicelength = w_idx.indices4( + space, self.length()) + self.deleteslice(start, step, slicelength) + return + + idx = space.getindex_w(w_idx, space.w_IndexError, "list index") + if idx < 0: + idx += self.length() + try: + self.pop(idx) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_delslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + self.deleteslice(start, 1, stop - start) + def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject return W_ReverseSeqIterObject(space, self, -1) def descr_reverse(self, space): 'L.reverse() -- reverse *IN PLACE*' self.reverse() - return space.w_None def descr_count(self, space, w_value): '''L.count(value) -> integer -- return number of @@ -354,7 +566,6 @@ length = self.length() index = get_positive_index(index, length) self.insert(index, w_value) - return space.w_None @unwrap_spec(index=int) def descr_pop(self, space, index=-1): @@ -366,7 +577,7 @@ space.wrap("pop from empty list")) # clearly differentiate between list.pop() and list.pop(index) if index == -1: - return self.pop_end() # cannot raise because list is not empty + return self.pop_end() # cannot raise because list is not empty if index < 0: index += length try: @@ -383,9 +594,8 @@ except ValueError: raise OperationError(space.w_ValueError, space.wrap("list.remove(x): x not in list")) - if i < self.length(): # otherwise list was mutated + if i < self.length(): # otherwise list was mutated self.pop(i) - return space.w_None @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(maxint)) def descr_index(self, space, w_value, w_start, w_stop): @@ -424,7 +634,7 @@ sorterclass = SimpleSort else: self.sort(reverse) - return space.w_None + return sorter = sorterclass(self.getitems(), self.length()) sorter.space = space @@ -474,10 +684,6 @@ raise OperationError(space.w_ValueError, space.wrap("list modified during sort")) - return space.w_None - -registerimplementation(W_ListObject) - class ListStrategy(object): sizehint = -1 @@ -602,7 +808,8 @@ The storage is None. When items are added to the W_List a new RPython list is created and the strategy and storage of the W_List are changed depending to the added item. - W_Lists do not switch back to EmptyListStrategy when becoming empty again.""" + W_Lists do not switch back to EmptyListStrategy when becoming empty again. + """ _applevel_repr = "empty" @@ -621,7 +828,8 @@ unerase = staticmethod(unerase) def clone(self, w_list): - return W_ListObject.from_storage_and_strategy(self.space, w_list.lstorage, self) + return W_ListObject.from_storage_and_strategy( + self.space, w_list.lstorage, self) def copy_into(self, w_list, w_other): pass @@ -650,20 +858,21 @@ def getitems_copy(self, w_list): return [] - getitems_fixedsize = func_with_new_name(getitems_copy, "getitems_fixedsize") + getitems_fixedsize = func_with_new_name(getitems_copy, + "getitems_fixedsize") getitems_unroll = getitems_fixedsize def getstorage_copy(self, w_list): return self.erase(None) def switch_to_correct_strategy(self, w_list, w_item): - if is_W_IntObject(w_item): + if type(w_item) is W_IntObject: strategy = self.space.fromcache(IntegerListStrategy) - elif is_W_StringObject(w_item): + elif type(w_item) is W_StringObject: strategy = self.space.fromcache(StringListStrategy) - elif is_W_UnicodeObject(w_item): + elif type(w_item) is W_UnicodeObject: strategy = self.space.fromcache(UnicodeListStrategy) - elif is_W_FloatObject(w_item): + elif type(w_item) is W_FloatObject: strategy = self.space.fromcache(FloatListStrategy) else: strategy = self.space.fromcache(ObjectListStrategy) @@ -707,7 +916,6 @@ w_other.copy_into(w_list) def _extend_from_iterable(self, w_list, w_iterable): - from pypy.objspace.std.tupleobject import W_AbstractTupleObject space = self.space if isinstance(w_iterable, W_AbstractTupleObject): w_list.__init__(space, w_iterable.getitems_copy()) @@ -742,9 +950,9 @@ def is_empty_strategy(self): return True + class SizeListStrategy(EmptyListStrategy): - """ Like empty, but when modified it'll preallocate the size to sizehint - """ + """Like empty, but when modified it'll preallocate the size to sizehint.""" def __init__(self, space, sizehint): self.sizehint = sizehint ListStrategy.__init__(self, space) @@ -753,12 +961,13 @@ assert hint >= 0 self.sizehint = hint + class RangeListStrategy(ListStrategy): """RangeListStrategy is used when a list is created using the range method. - The storage is a tuple containing only three integers start, step and length - and elements are calculated based on these values. - On any operation destroying the range (inserting, appending non-ints) - the strategy is switched to IntegerListStrategy.""" + The storage is a tuple containing only three integers start, step and + length and elements are calculated based on these values. On any operation + destroying the range (inserting, appending non-ints) the strategy is + switched to IntegerListStrategy.""" _applevel_repr = "range" @@ -781,8 +990,9 @@ unerase = staticmethod(unerase) def clone(self, w_list): - storage = w_list.lstorage # lstorage is tuple, no need to clone - w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self) + storage = w_list.lstorage # lstorage is tuple, no need to clone + w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, + self) return w_clone def _resize_hint(self, w_list, hint): @@ -794,11 +1004,13 @@ w_other.lstorage = w_list.lstorage def find(self, w_list, w_obj, startindex, stopindex): - if is_W_IntObject(w_obj): + if type(w_obj) is W_IntObject: obj = self.unwrap(w_obj) start, step, length = self.unerase(w_list.lstorage) - if ((step > 0 and start <= obj <= start + (length - 1) * step and (start - obj) % step == 0) or - (step < 0 and start + (length - 1) * step <= obj <= start and (start - obj) % step == 0)): + if ((step > 0 and start <= obj <= start + (length - 1) * step and + (start - obj) % step == 0) or + (step < 0 and start + (length - 1) * step <= obj <= start and + (start - obj) % step == 0)): index = (obj - start) // step else: raise ValueError @@ -861,16 +1073,18 @@ @jit.dont_look_inside def getitems_fixedsize(self, w_list): return self._getitems_range_unroll(w_list, True) + def getitems_unroll(self, w_list): return self._getitems_range_unroll(w_list, True) - _getitems_range_unroll = jit.unroll_safe(func_with_new_name(_getitems_range, "_getitems_range_unroll")) + _getitems_range_unroll = jit.unroll_safe( + func_with_new_name(_getitems_range, "_getitems_range_unroll")) def getslice(self, w_list, start, stop, step, length): self.switch_to_integer_strategy(w_list) return w_list.getslice(start, stop, step, length) def append(self, w_list, w_item): - if is_W_IntObject(w_item): + if type(w_item) is W_IntObject: self.switch_to_integer_strategy(w_list) else: w_list.switch_to_object_strategy() @@ -933,6 +1147,7 @@ self.switch_to_integer_strategy(w_list) w_list.reverse() + class AbstractUnwrappedStrategy(object): _mixin_ = True @@ -970,7 +1185,8 @@ def clone(self, w_list): l = self.unerase(w_list.lstorage) storage = self.erase(l[:]) - w_clone = W_ListObject.from_storage_and_strategy(self.space, storage, self) + w_clone = W_ListObject.from_storage_and_strategy( + self.space, storage, self) return w_clone def _resize_hint(self, w_list, hint): @@ -1001,12 +1217,13 @@ l = self.unerase(w_list.lstorage) try: r = l[index] - except IndexError: # make RPython raise the exception + except IndexError: # make RPython raise the exception raise return self.wrap(r) @jit.look_inside_iff(lambda self, w_list: - jit.loop_unrolling_heuristic(w_list, w_list.length(), UNROLL_CUTOFF)) + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF)) def getitems_copy(self, w_list): return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @@ -1015,7 +1232,8 @@ return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @jit.look_inside_iff(lambda self, w_list: - jit.loop_unrolling_heuristic(w_list, w_list.length(), UNROLL_CUTOFF)) + jit.loop_unrolling_heuristic(w_list, w_list.length(), + UNROLL_CUTOFF)) def getitems_fixedsize(self, w_list): return self.getitems_unroll(w_list) @@ -1030,7 +1248,8 @@ assert stop >= 0 sublist = l[start:stop] storage = self.erase(sublist) - return W_ListObject.from_storage_and_strategy(self.space, storage, self) + return W_ListObject.from_storage_and_strategy( + self.space, storage, self) else: subitems_w = [self._none_value] * length l = self.unerase(w_list.lstorage) @@ -1041,9 +1260,10 @@ except IndexError: raise storage = self.erase(subitems_w) - return W_ListObject.from_storage_and_strategy(self.space, storage, self) + return W_ListObject.from_storage_and_strategy( + self.space, storage, self) - def append(self, w_list, w_item): + def append(self, w_list, w_item): if self.is_correct_type(w_item): self.unerase(w_list.lstorage).append(self.unwrap(w_item)) return @@ -1092,11 +1312,11 @@ if self is self.space.fromcache(ObjectListStrategy): w_other = w_other._temporarily_as_objects() - elif (not self.list_is_correct_type(w_other) and - w_other.length() != 0): + elif not self.list_is_correct_type(w_other) and w_other.length() != 0: w_list.switch_to_object_strategy() w_other_as_object = w_other._temporarily_as_objects() - assert w_other_as_object.strategy is self.space.fromcache(ObjectListStrategy) + assert (w_other_as_object.strategy is + self.space.fromcache(ObjectListStrategy)) w_list.setslice(start, step, slicelength, w_other_as_object) return @@ -1112,13 +1332,14 @@ lim = start + len2 i = newsize - 1 while i >= lim: - items[i] = items[i-delta] + items[i] = items[i - delta] i -= 1 elif delta == 0: pass else: - assert start >= 0 # start<0 is only possible with slicelength==0 - del items[start:start+delta] + # start < 0 is only possible with slicelength == 0 + assert start >= 0 + del items[start:start + delta] elif len2 != slicelength: # No resize for extended slices raise operationerrfmt(self.space.w_ValueError, "attempt to " "assign sequence of size %d to extended slice of size %d", @@ -1163,7 +1384,7 @@ if step == 1: assert start >= 0 if slicelength > 0: - del items[start:start+slicelength] + del items[start:start + slicelength] else: n = len(items) i = start @@ -1172,15 +1393,15 @@ j = i + 1 i += step while j < i: - items[j-discard] = items[j] + items[j - discard] = items[j] j += 1 j = i + 1 while j < n: - items[j-slicelength] = items[j] + items[j - slicelength] = items[j] j += 1 start = n - slicelength - assert start >= 0 # annotator hint + assert start >= 0 # annotator hint del items[start:] def pop_end(self, w_list): @@ -1213,6 +1434,7 @@ def reverse(self, w_list): self.unerase(w_list.lstorage).reverse() + class ObjectListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "object" @@ -1245,6 +1467,7 @@ def getitems(self, w_list): return self.unerase(w_list.lstorage) + class IntegerListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = 0 _applevel_repr = "int" @@ -1260,7 +1483,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_IntObject(w_obj) + return type(w_obj) is W_IntObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(IntegerListStrategy) @@ -1275,6 +1498,7 @@ def getitems_int(self, w_list): return self.unerase(w_list.lstorage) + class FloatListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = 0.0 _applevel_repr = "float" @@ -1290,7 +1514,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_FloatObject(w_obj) + return type(w_obj) is W_FloatObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(FloatListStrategy) @@ -1302,6 +1526,7 @@ if reverse: l.reverse() + class StringListStrategy(AbstractUnwrappedStrategy, ListStrategy): _none_value = None _applevel_repr = "str" @@ -1317,7 +1542,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_StringObject(w_obj) + return type(w_obj) is W_StringObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(StringListStrategy) @@ -1348,7 +1573,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return is_W_UnicodeObject(w_obj) + return type(w_obj) is W_UnicodeObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(UnicodeListStrategy) @@ -1368,196 +1593,6 @@ init_signature = Signature(['sequence'], None, None) init_defaults = [None] -def init__List(space, w_list, __args__): - # this is on the silly side - w_iterable, = __args__.parse_obj( - None, 'list', init_signature, init_defaults) - w_list.clear(space) - if w_iterable is not None: - w_list.extend(w_iterable) - -def len__List(space, w_list): - result = w_list.length() - return wrapint(space, result) - -def getitem__List_ANY(space, w_list, w_index): - try: - return w_list.getitem(get_list_index(space, w_index)) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - -def getitem__List_Slice(space, w_list, w_slice): - # XXX consider to extend rlist's functionality? - length = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - if slicelength == 0: - return make_empty_list(space) - return w_list.getslice(start, stop, step, slicelength) - -def getslice__List_ANY_ANY(space, w_list, w_start, w_stop): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - - slicelength = stop - start - if slicelength == 0: - return make_empty_list(space) - return w_list.getslice(start, stop, 1, stop - start) - -def setslice__List_ANY_ANY_List(space, w_list, w_start, w_stop, w_other): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - w_list.setslice(start, 1, stop-start, w_other) - -def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_iterable): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - sequence_w = space.listview(w_iterable) - w_other = W_ListObject(space, sequence_w) - w_list.setslice(start, 1, stop-start, w_other) - -def delslice__List_ANY_ANY(space, w_list, w_start, w_stop): - length = w_list.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - w_list.deleteslice(start, 1, stop-start) - -def contains__List_ANY(space, w_list, w_obj): - try: - w_list.find(w_obj) - return space.w_True - except ValueError: - return space.w_False - -def iter__List(space, w_list): - from pypy.objspace.std import iterobject - return iterobject.W_FastListIterObject(w_list) - -def add__List_List(space, w_list1, w_list2): - w_clone = w_list1.clone() - w_clone.extend(w_list2) - return w_clone - -def inplace_add__List_ANY(space, w_list1, w_iterable2): - try: - w_list1.extend(w_iterable2) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - return w_list1 - -def inplace_add__List_List(space, w_list1, w_list2): - w_list1.extend(w_list2) - return w_list1 - -def mul_list_times(space, w_list, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - return w_list.mul(times) - -def mul__List_ANY(space, w_list, w_times): - return mul_list_times(space, w_list, w_times) - -def mul__ANY_List(space, w_times, w_list): - return mul_list_times(space, w_list, w_times) - -def inplace_mul__List_ANY(space, w_list, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - w_list.inplace_mul(times) - return w_list - -def list_unroll_condition(space, w_list1, w_list2): - return jit.loop_unrolling_heuristic(w_list1, w_list1.length(), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_list2, w_list2.length(), UNROLL_CUTOFF) - - at jit.look_inside_iff(list_unroll_condition) -def eq__List_List(space, w_list1, w_list2): - # needs to be safe against eq_w() mutating the w_lists behind our back - if w_list1.length() != w_list2.length(): - return space.w_False - - # XXX in theory, this can be implemented more efficiently as well. let's - # not care for now - i = 0 - while i < w_list1.length() and i < w_list2.length(): - if not space.eq_w(w_list1.getitem(i), w_list2.getitem(i)): - return space.w_False - i += 1 - return space.w_True - -def _make_list_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(list_unroll_condition) - def compare_unwrappeditems(space, w_list1, w_list2): - # needs to be safe against eq_w() mutating the w_lists behind our back - # Search for the first index where items are different - i = 0 - # XXX in theory, this can be implemented more efficiently as well. - # let's not care for now - while i < w_list1.length() and i < w_list2.length(): - w_item1 = w_list1.getitem(i) - w_item2 = w_list2.getitem(i) - if not space.eq_w(w_item1, w_item2): - return getattr(space, name)(w_item1, w_item2) - i += 1 - # No more items to compare -- compare sizes - return space.newbool(op(w_list1.length(), w_list2.length())) - return func_with_new_name(compare_unwrappeditems, name + '__List_List') - -lt__List_List = _make_list_comparison('lt') -le__List_List = _make_list_comparison('le') -gt__List_List = _make_list_comparison('gt') -ge__List_List = _make_list_comparison('ge') - -def delitem__List_ANY(space, w_list, w_idx): - idx = get_list_index(space, w_idx) - if idx < 0: - idx += w_list.length() - try: - w_list.pop(idx) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list deletion index out of range")) - return space.w_None - - -def delitem__List_Slice(space, w_list, w_slice): - start, stop, step, slicelength = w_slice.indices4(space, w_list.length()) - w_list.deleteslice(start, step, slicelength) - -def setitem__List_ANY_ANY(space, w_list, w_index, w_any): - idx = get_list_index(space, w_index) - try: - w_list.setitem(idx, w_any) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("list index out of range")) - return space.w_None - -def setitem__List_Slice_List(space, w_list, w_slice, w_other): - oldsize = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, oldsize) - w_list.setslice(start, step, slicelength, w_other) - -def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable): - oldsize = w_list.length() - start, stop, step, slicelength = w_slice.indices4(space, oldsize) - sequence_w = space.listview(w_iterable) - w_other = W_ListObject(space, sequence_w) - w_list.setslice(start, step, slicelength, w_other) - app = applevel(""" def listrepr(currently_in_repr, l): 'The app-level part of repr().' @@ -1576,25 +1611,6 @@ listrepr = app.interphook("listrepr") -def repr__List(space, w_list): - if w_list.length() == 0: - return space.wrap('[]') - ec = space.getexecutioncontext() - w_currently_in_repr = ec._py_repr - if w_currently_in_repr is None: - w_currently_in_repr = ec._py_repr = space.newdict() - return listrepr(space, w_currently_in_repr, w_list) - -def get_positive_index(where, length): - if where < 0: - where += length - if where < 0: - where = 0 - elif where > length: - where = length - assert where >= 0 - return where - # ____________________________________________________________ # Sorting @@ -1607,11 +1623,13 @@ StringBaseTimSort = make_timsort_class() UnicodeBaseTimSort = make_timsort_class() -class KeyContainer(baseobjspace.W_Root): + +class KeyContainer(W_Root): def __init__(self, w_key, w_item): self.w_key = w_key self.w_item = w_item + # NOTE: all the subclasses of TimSort should inherit from a common subclass, # so make sure that only SimpleSort inherits directly from TimSort. # This is necessary to hide the parent method TimSort.lt() from the @@ -1621,22 +1639,27 @@ space = self.space return space.is_true(space.lt(a, b)) + class IntSort(IntBaseTimSort): def lt(self, a, b): return a < b + class FloatSort(FloatBaseTimSort): def lt(self, a, b): return a < b + class StringSort(StringBaseTimSort): def lt(self, a, b): return a < b + class UnicodeSort(UnicodeBaseTimSort): def lt(self, a, b): return a < b + class CustomCompareSort(SimpleSort): def lt(self, a, b): space = self.space @@ -1651,6 +1674,7 @@ raise return result < 0 + class CustomKeySort(SimpleSort): def lt(self, a, b): assert isinstance(a, KeyContainer) @@ -1658,33 +1682,46 @@ space = self.space return space.is_true(space.lt(a.w_key, b.w_key)) + class CustomKeyCompareSort(CustomCompareSort): def lt(self, a, b): assert isinstance(a, KeyContainer) assert isinstance(b, KeyContainer) return CustomCompareSort.lt(self, a.w_key, b.w_key) -# ____________________________________________________________ - -def descr_new(space, w_listtype, __args__): - w_obj = space.allocate_instance(W_ListObject, w_listtype) - w_obj.clear(space) - return w_obj - -# ____________________________________________________________ - -# ____________________________________________________________ - -def get_list_index(space, w_index): - return space.getindex_w(w_index, space.w_IndexError, "list index") - -register_all(vars(), globals()) W_ListObject.typedef = StdTypeDef("list", __doc__ = """list() -> new list list(sequence) -> new list initialized from sequence's items""", - __new__ = interp2app(descr_new), + __new__ = interp2app(W_ListObject.descr_new), + __init__ = interp2app(W_ListObject.descr_init), + __repr__ = interp2app(W_ListObject.descr_repr), __hash__ = None, + + __eq__ = interp2app(W_ListObject.descr_eq), + __ne__ = interp2app(W_ListObject.descr_ne), + __lt__ = interp2app(W_ListObject.descr_lt), + __le__ = interp2app(W_ListObject.descr_le), + __gt__ = interp2app(W_ListObject.descr_gt), + __ge__ = interp2app(W_ListObject.descr_ge), + + __len__ = interp2app(W_ListObject.descr_len), + __iter__ = interp2app(W_ListObject.descr_iter), + __contains__ = interp2app(W_ListObject.descr_contains), + + __add__ = interp2app(W_ListObject.descr_add), + __iadd__ = interp2app(W_ListObject.descr_inplace_add), + __mul__ = interp2app(W_ListObject.descr_mul), + __rmul__ = interp2app(W_ListObject.descr_mul), + __imul__ = interp2app(W_ListObject.descr_inplace_mul), + + __getitem__ = interp2app(W_ListObject.descr_getitem), + __getslice__ = interp2app(W_ListObject.descr_getslice), + __setitem__ = interp2app(W_ListObject.descr_setitem), + __setslice__ = interp2app(W_ListObject.descr_setslice), + __delitem__ = interp2app(W_ListObject.descr_delitem), + __delslice__ = interp2app(W_ListObject.descr_delslice), + sort = interp2app(W_ListObject.descr_sort), index = interp2app(W_ListObject.descr_index), append = interp2app(W_ListObject.append), @@ -1695,7 +1732,4 @@ extend = interp2app(W_ListObject.extend), insert = interp2app(W_ListObject.descr_insert), remove = interp2app(W_ListObject.descr_remove), - ) -W_ListObject.typedef.registermethods(globals()) - -list_typedef = W_ListObject.typedef +) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -297,17 +297,17 @@ return space.newtuple(items_w) register(TYPE_TUPLE, unmarshal_Tuple) -def marshal_w__List(space, w_list, m): +def marshal_list(space, w_list, m): + if not isinstance(w_list, W_ListObject): + raise_exception(space, "unmarshallable object") items = w_list.getitems()[:] m.put_tuple_w(TYPE_LIST, items) +handled_by_any.append(('list', marshal_list)) -def unmarshal_List(space, u, tc): +def unmarshal_list(space, u, tc): items_w = u.get_list_w() return space.newlist(items_w) - -def finish_List(space, items_w, typecode): - return space.newlist(items_w) -register(TYPE_LIST, unmarshal_List) +register(TYPE_LIST, unmarshal_list) def marshal_w_dict(space, w_dict, m): if not isinstance(w_dict, W_DictMultiObject): diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -39,7 +39,6 @@ from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.tupletype import tuple_typedef - from pypy.objspace.std.listobject import list_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -80,6 +79,7 @@ # not-multimethod based types + self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) @@ -91,7 +91,6 @@ intobject.W_IntObject: [], floatobject.W_FloatObject: [], tupleobject.W_TupleObject: [], - listobject.W_ListObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -109,11 +108,6 @@ } self.imported_but_not_registered = { - dictmultiobject.W_DictMultiObject: True, # XXXXXX - dictmultiobject.W_DictMultiIterKeysObject: True, - dictmultiobject.W_DictMultiIterValuesObject: True, - dictmultiobject.W_DictMultiIterItemsObject: True, - listobject.W_ListObject: True, stringobject.W_StringObject: True, tupleobject.W_TupleObject: True, } diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -783,6 +783,8 @@ assert l == [1,2,3,4,5] def test_iadd_subclass(self): + #XXX + skip("Maybe there is something wrong in descroperation?") class Bar(object): def __radd__(self, other): return ('radd', self, other) @@ -1306,6 +1308,12 @@ def test_use_method_for_wrong_object(self): raises(TypeError, list.append.im_func, 1, 2) + def test_ne_NotImplemented(self): + class NonList(object): + pass + non_list = NonList() + assert [] != non_list + class AppTestForRangeLists(AppTestW_ListObject): spaceconfig = {"objspace.std.withrangelist": True} diff --git a/pypy/objspace/std/test/test_liststrategies.py b/pypy/objspace/std/test/test_liststrategies.py --- a/pypy/objspace/std/test/test_liststrategies.py +++ b/pypy/objspace/std/test/test_liststrategies.py @@ -488,15 +488,13 @@ def test_weird_rangelist_bug(self): l = make_range_list(self.space, 1, 1, 3) - from pypy.objspace.std.listobject import getslice__List_ANY_ANY # should not raise - assert getslice__List_ANY_ANY(self.space, l, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy) + assert l.descr_getslice(self.space, self.space.wrap(15), self.space.wrap(2222)).strategy == self.space.fromcache(EmptyListStrategy) def test_add_to_rangelist(self): l1 = make_range_list(self.space, 1, 1, 3) l2 = W_ListObject(self.space, [self.space.wrap(4), self.space.wrap(5)]) - from pypy.objspace.std.listobject import add__List_List - l3 = add__List_List(self.space, l1, l2) + l3 = l1.descr_add(self.space, l2) assert self.space.eq_w(l3, W_ListObject(self.space, [self.space.wrap(1), self.space.wrap(2), self.space.wrap(3), self.space.wrap(4), self.space.wrap(5)])) def test_unicode(self): diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py --- a/pypy/objspace/std/test/test_stdobjspace.py +++ b/pypy/objspace/std/test/test_stdobjspace.py @@ -23,19 +23,6 @@ raises(OperationError,self.space.uint_w,self.space.wrap(None)) raises(OperationError,self.space.uint_w,self.space.wrap("")) - def test_multimethods_defined_on(self): - from pypy.objspace.std.stdtypedef import multimethods_defined_on - from pypy.objspace.std.listobject import W_ListObject - res = multimethods_defined_on(W_ListObject) - res = [(m.name, local) for (m, local) in res] - assert ('add', False) in res - assert ('lt', False) in res - assert ('setitem', False) in res - assert ('mod', False) not in res - assert ('pop', True) not in res - assert ('reverse', True) not in res - assert ('popitem', True) not in res - def test_sliceindices(self): space = self.space w_obj = space.appexec([], """(): diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/util.py @@ -0,0 +1,27 @@ +def negate(f): + """Create a function which calls `f` and negates its result. When the + result is ``space.w_NotImplemented``, ``space.w_NotImplemented`` is + returned. This is useful for complementing e.g. the __ne__ descriptor if + your type already defines a __eq__ descriptor. + """ + def _negator(self, space, w_other): + # no need to use space.is_ / space.not_ + tmp = f(self, space, w_other) + if tmp is space.w_NotImplemented: + return space.w_NotImplemented + elif tmp is space.w_False: + return space.w_True + else: + return space.w_False + _negator.func_name = 'negate-%s' % f.func_name + return _negator + +def get_positive_index(where, length): + if where < 0: + where += length + if where < 0: + where = 0 + elif where > length: + where = length + assert where >= 0 + return where From noreply at buildbot.pypy.org Tue May 21 15:10:24 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 15:10:24 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge Message-ID: <20130521131024.AC5E21C0217@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64390:d03bb47c8b07 Date: 2013-05-21 15:08 +0200 http://bitbucket.org/pypy/pypy/changeset/d03bb47c8b07/ Log: hg merge 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 @@ -344,7 +344,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1, external=False) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -132,7 +132,7 @@ # ---------- Linux2 ---------- def get_L2cache_linux2(): - arch = platform.machine() + arch = os.uname()[4] # machine if arch.endswith('86') or arch == 'x86_64': return get_L2cache_linux2_cpuinfo() if arch in ('alpha', 'ppc', 'ppc64'): From noreply at buildbot.pypy.org Tue May 21 15:56:06 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 21 May 2013 15:56:06 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changed context part shadow to raise an SendersChainManipulated-Exception when assigning to _s_sender Message-ID: <20130521135606.409861C0698@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r398:db177965782f Date: 2013-05-21 15:55 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/db177965782f/ Log: changed context part shadow to raise an SendersChainManipulated- Exception when assigning to _s_sender that error need be catched in different places, and only when caught by the doubleExtendedDoAnything bytecode, drop the c-stack... tested diff --git a/spyvm/constants.py b/spyvm/constants.py --- a/spyvm/constants.py +++ b/spyvm/constants.py @@ -97,7 +97,7 @@ SO_A_POINT = 33 SO_CANNOT_INTERPRET = 34 SO_A_METHODCONTEXT = 35 # deprecated in closure images -SO_BLOCKCLOSURE_CLASS = 36 +SO_BLOCKCLOSURE_CLASS = 36 SO_A_BLOCKCONTEXT = 37 # deprecated in closure images SO_EXTERNAL_OBJECTS_ARRAY = 38 SO_PSEUDOCONTEXT_CLASS = 39 diff --git a/spyvm/error.py b/spyvm/error.py --- a/spyvm/error.py +++ b/spyvm/error.py @@ -29,3 +29,7 @@ class Exit(Exception): def __init__(self, msg): self.msg = msg + +class SenderChainManipulation(Exception): + def __init__(self, manipulated_context): + self.s_context = manipulated_context diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -503,6 +503,7 @@ return self._sendSelfSelector(w_selector, argcount, interp) def doubleExtendedDoAnythingBytecode(self, interp, current_bytecode): + from spyvm import error second = self.getbytecode() third = self.getbytecode() opType = second >> 5 @@ -526,9 +527,15 @@ association = wrapper.AssociationWrapper(self.space, w_association) self.push(association.value()) elif opType == 5: - self.w_receiver().store(self.space, third, self.top()) + try: + self.w_receiver().store(self.space, third, self.top()) + except error.SenderChainManipulation, e: + raise StackOverflow(self) elif opType == 6: - self.w_receiver().store(self.space, third, self.pop()) + try: + self.w_receiver().store(self.space, third, self.pop()) + except error.SenderChainManipulation, e: + raise StackOverflow(self) elif opType == 7: w_association = self.s_method().getliteral(third) association = wrapper.AssociationWrapper(self.space, w_association) diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -1144,9 +1144,13 @@ return s_new_context.w_self() def finalize_block_ctx(interp, s_block_ctx, s_frame): + from spyvm.error import SenderChainManipulation # Set some fields s_block_ctx.store_pc(s_block_ctx.initialip()) - s_block_ctx.store_s_sender(s_frame) + try: + s_block_ctx.store_s_sender(s_frame) + except SenderChainManipulation, e: + assert e.s_context == s_block_ctx return s_block_ctx @expose_primitive(VALUE, result_is_new_frame=True) diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -417,7 +417,10 @@ w_self = self.w_self() assert isinstance(w_self, model.W_PointersObject) for i in range(self._w_self_size): - self.copy_from_w_self(i) + try: + self.copy_from_w_self(i) + except error.SenderChainManipulation, e: + assert e.s_context == self w_self._vars = None # def detach_shadow(self): @@ -530,13 +533,14 @@ def store_s_sender(self, s_sender): assert s_sender is None or isinstance(s_sender, ContextPartShadow) self._s_sender = s_sender + raise error.SenderChainManipulation(self) def store_w_sender(self, w_sender): assert isinstance(w_sender, model.W_PointersObject) if w_sender.is_same_object(self.space.w_nil): self._s_sender = None else: - self._s_sender = w_sender.as_context_get_shadow(self.space) + self.store_s_sender(w_sender.as_context_get_shadow(self.space)) def w_sender(self): if self._s_sender is None: @@ -572,7 +576,10 @@ def mark_returned(self): self.store_pc(-1) - self.store_s_sender(None) + try: + self.store_s_sender(None) + except error.SenderChainManipulation, e: + assert self == e.s_context def is_returned(self): return self.pc() == -1 and self.w_sender is self.space.w_nil @@ -851,7 +858,10 @@ s_new_context.store_w_method(s_method.w_self()) if s_sender: - s_new_context.store_s_sender(s_sender) + try: + s_new_context.store_s_sender(s_sender) + except error.SenderChainManipulation, e: + assert s_new_context == e.s_context s_new_context.store_w_receiver(w_receiver) s_new_context.store_pc(pc) s_new_context.init_stack_and_temps() diff --git a/spyvm/test/test_interpreter.py b/spyvm/test/test_interpreter.py --- a/spyvm/test/test_interpreter.py +++ b/spyvm/test/test_interpreter.py @@ -1041,3 +1041,11 @@ assert space.unwrap_int(e.object) == 68 except interpreter.StackOverflow, e: assert False + +def test_c_stack_reset_on_sender_chain_manipulation(): + import operator + bytes = reduce(operator.add, map(chr, [0x84, 0xc0, 0x00])) + w_frame, s_frame = new_frame(bytes) + s_frame.store_w_receiver(w_frame) + s_frame.push(w_frame) + py.test.raises(interpreter.StackOverflow, step_in_interp, s_frame) From noreply at buildbot.pypy.org Tue May 21 15:57:38 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 21 May 2013 15:57:38 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: renamed squeak45 tests to be automatically executed, and be executed last... Message-ID: <20130521135738.C67B21C0698@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r399:68afab2a56e9 Date: 2013-05-21 15:57 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/68afab2a56e9/ Log: renamed squeak45 tests to be automatically executed, and be executed last... diff --git a/spyvm/test/testsin_squeak_4_5_image.py b/spyvm/test/test_zin_squeak_4_5_image.py rename from spyvm/test/testsin_squeak_4_5_image.py rename to spyvm/test/test_zin_squeak_4_5_image.py From noreply at buildbot.pypy.org Tue May 21 16:18:20 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 21 May 2013 16:18:20 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: updated the Squeak artefacts (Filetree-repo and a cs-file) to reflect my changes to alleviate debugging Message-ID: <20130521141820.B50FA1C0217@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r400:e5452d166391 Date: 2013-05-21 16:18 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/e5452d166391/ Log: updated the Squeak artefacts (Filetree-repo and a cs-file) to reflect my changes to alleviate debugging diff --git a/SPy-Debugging.package/SPyVM.class/class/print..st b/SPy-Debugging.package/SPyVM.class/class/print..st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/class/print..st @@ -0,0 +1,3 @@ +as yet unclassified +print: aString + \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/methodProperties.json b/SPy-Debugging.package/SPyVM.class/methodProperties.json --- a/SPy-Debugging.package/SPyVM.class/methodProperties.json +++ b/SPy-Debugging.package/SPyVM.class/methodProperties.json @@ -1,6 +1,7 @@ { "class" : { "halt" : "lw 4/30/2013 12:44", + "print:" : "lw 5/21/2013 11:00", "trace" : "lw 4/30/2013 12:44", "untrace" : "lw 4/30/2013 12:44" }, "instance" : { diff --git a/SPy-Debugging.package/monticello.meta/version b/SPy-Debugging.package/monticello.meta/version --- a/SPy-Debugging.package/monticello.meta/version +++ b/SPy-Debugging.package/monticello.meta/version @@ -1,1 +1,1 @@ -(name 'SPy-Debugging-lw.1' message 'added class for starting vm-tracing, etc.' id 'e6eeab78-6e5c-43bf-9dbc-dfdad29756bd' date '30 April 2013' time '3:54:48.262 pm' author 'lw' ancestors () stepChildren ()) \ No newline at end of file +(name 'SPy-Debugging-lw.2' message 'added printing' id '26ffba4f-b747-480c-b7de-2517367fad07' date '21 May 2013' time '4:12:24.874 pm' author 'lw' ancestors ((name 'SPy-Debugging-lw.1' message 'added class for starting vm-tracing, etc.' id 'e6eeab78-6e5c-43bf-9dbc-dfdad29756bd' date '30 April 2013' time '3:54:48.262 pm' author 'lw' ancestors () stepChildren ())) stepChildren ()) \ No newline at end of file diff --git a/kernel changes.1.cs b/kernel changes.1.cs new file mode 100644 --- /dev/null +++ b/kernel changes.1.cs @@ -0,0 +1,1 @@ +'From Squeak4.4 of 31 December 2012 [latest update: #12332] on 21 May 2013 at 4:15:40 pm'! !Object methodsFor: 'error handling' stamp: 'lw 5/21/2013 11:55'! doesNotUnderstand: aMessage "Handle the fact that there was an attempt to send the given message to the receiver but the receiver does not understand this message (typically sent from the machine when a message is sent to the receiver and no method is defined for that selector)." "Testing: (3 activeProcess)" | exception resumeValue | SPyVM halt. (exception := MessageNotUnderstood new) message: aMessage; receiver: self. resumeValue := exception signal. ^exception reachedDefaultHandler ifTrue: [aMessage sentTo: self] ifFalse: [resumeValue]! ! !Object methodsFor: 'error handling' stamp: 'lw 5/21/2013 16:14'! error: aString "Throw a generic Error exception." SPyVM halt. ^Error new signal: aString! ! !ContextPart class methodsFor: 'special context creation' stamp: 'lw 5/17/2013 18:36'! contextEnsure: block "Create an #ensure: context that is ready to return from executing its receiver" | ctxt chain | ctxt := thisContext. [chain := thisContext sender cut: ctxt. ctxt push: nil. ctxt jump] ensure: block. "jump above will resume here without unwinding chain" ^ chain! ! !ContextPart class methodsFor: 'special context creation' stamp: 'lw 5/17/2013 14:37'! contextOn: exceptionClass do: block "Create an #on:do: context that is ready to return from executing its receiver" | ctxt chain | ctxt := thisContext. [chain := thisContext sender cut: ctxt. ctxt push: nil. ctxt jump] on: exceptionClass do: block. "jump above will resume here without unwinding chain" ^ chain! ! \ No newline at end of file From noreply at buildbot.pypy.org Tue May 21 17:06:29 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 17:06:29 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: Reference 2.0.2-osx64 Message-ID: <20130521150629.53E681C0698@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r438:ba7881cae9af Date: 2013-05-21 17:06 +0200 http://bitbucket.org/pypy/pypy.org/changeset/ba7881cae9af/ Log: Reference 2.0.2-osx64 diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -91,7 +91,7 @@
    • Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS) (see [1] below)
    • Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS) (see [1] below)
    • -
    • Mac OS/X binary (64bit) (STILL POINTS TO 2.0.1, UPDATED SOON)
    • +
    • Mac OS/X binary (64bit)
    • Windows binary (32bit) (you might need the VS 2008 runtime library installer vcredist_x86.exe.)
    • Source (tar.bz2)
    • @@ -222,7 +222,7 @@
       51ac0aa37a8255acbc71eca23ea29609  pypy-2.0.2-linux.tar.bz2
       9d9f512ab2f114bfb4f165c71181a511  pypy-2.0.2-linux64.tar.bz2
      -e666450bcfbd936b016a2dd7312f9853  pypy-2.0.1-osx64.tar.bz2
      +a7da45a3161c198de6f662e3c40629ff  pypy-2.0.2-osx64.tar.bz2
       3e51dce7ecfc8fb069d65d95e8de6fb2  pypy-2.0.2-win32.zip
       b9c36b99296c85a590c3e480b05d5a13  pypy-2.0-alpha-arm-armel.tar.bz2
       2565ce68b4032eb306d998e722495694  pypy-2.0-alpha-arm-armhf.tar.bz2
      @@ -233,7 +233,7 @@
       4da8c6dfbe7d2044d892c9bc20a649b0  pypy-2.0.2-src.zip
       c8ec9872fe823f4f7574620a5303c5b0f4576393  pypy-2.0.2-linux.tar.bz2
       3d045ab7871bc478604cf1f16a3c4ec46c950e70  pypy-2.0.2-linux64.tar.bz2
      -811fd377ab2eda9233a0c34340f981f9aba1ba9a  pypy-2.0.1-osx64.tar.bz2
      +a53de7bc88b9caa635d9d679c6e63813881ea7e9  pypy-2.0.2-osx64.tar.bz2
       4ae8a35dd8043312199aacdbe3abb1a666fc9312  pypy-2.0.2-win32.zip
       dc09a293b85ab4f0032f6943815aaf5bbbceb645  pypy-2.0-alpha-arm-armel.tar.bz2
       0971c4b668bfd2fcd52aa35087aa995e03bd5842  pypy-2.0-alpha-arm-armhf.tar.bz2
      diff --git a/source/download.txt b/source/download.txt
      --- a/source/download.txt
      +++ b/source/download.txt
      @@ -76,7 +76,7 @@
       
       * `Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS)`__ (see ``[1]`` below)
       * `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ (see ``[1]`` below)
      -* `Mac OS/X binary (64bit)`__ (STILL POINTS TO 2.0.1, UPDATED SOON)
      +* `Mac OS/X binary (64bit)`__
       * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library
         installer vcredist_x86.exe`_.)
       * `Source (tar.bz2)`__
      @@ -84,7 +84,7 @@
       
       .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux.tar.bz2
       .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux64.tar.bz2
      -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.1-osx64.tar.bz2
      +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-osx64.tar.bz2
       .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-win32.zip
       .. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582
       .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.tar.bz2
      @@ -244,7 +244,7 @@
       
          51ac0aa37a8255acbc71eca23ea29609  pypy-2.0.2-linux.tar.bz2
          9d9f512ab2f114bfb4f165c71181a511  pypy-2.0.2-linux64.tar.bz2
      -   e666450bcfbd936b016a2dd7312f9853  pypy-2.0.1-osx64.tar.bz2
      +   a7da45a3161c198de6f662e3c40629ff  pypy-2.0.2-osx64.tar.bz2
          3e51dce7ecfc8fb069d65d95e8de6fb2  pypy-2.0.2-win32.zip
          b9c36b99296c85a590c3e480b05d5a13  pypy-2.0-alpha-arm-armel.tar.bz2
          2565ce68b4032eb306d998e722495694  pypy-2.0-alpha-arm-armhf.tar.bz2
      @@ -256,7 +256,7 @@
       
          c8ec9872fe823f4f7574620a5303c5b0f4576393  pypy-2.0.2-linux.tar.bz2
          3d045ab7871bc478604cf1f16a3c4ec46c950e70  pypy-2.0.2-linux64.tar.bz2
      -   811fd377ab2eda9233a0c34340f981f9aba1ba9a  pypy-2.0.1-osx64.tar.bz2
      +   a53de7bc88b9caa635d9d679c6e63813881ea7e9  pypy-2.0.2-osx64.tar.bz2
          4ae8a35dd8043312199aacdbe3abb1a666fc9312  pypy-2.0.2-win32.zip
          dc09a293b85ab4f0032f6943815aaf5bbbceb645  pypy-2.0-alpha-arm-armel.tar.bz2
          0971c4b668bfd2fcd52aa35087aa995e03bd5842  pypy-2.0-alpha-arm-armhf.tar.bz2
      
      From noreply at buildbot.pypy.org  Tue May 21 17:26:33 2013
      From: noreply at buildbot.pypy.org (rguillebert)
      Date: Tue, 21 May 2013 17:26:33 +0200 (CEST)
      Subject: [pypy-commit] pypy numpy-subarrays: Fix multidimensional subarrays
      Message-ID: <20130521152633.9E2271C0698@cobra.cs.uni-duesseldorf.de>
      
      Author: Romain Guillebert 
      Branch: numpy-subarrays
      Changeset: r64391:905b68f9d7c3
      Date: 2013-05-21 17:25 +0200
      http://bitbucket.org/pypy/pypy/changeset/905b68f9d7c3/
      
      Log:	Fix multidimensional subarrays
      
      diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
      --- a/pypy/module/micronumpy/arrayimpl/concrete.py
      +++ b/pypy/module/micronumpy/arrayimpl/concrete.py
      @@ -357,13 +357,13 @@
               self.strides = strides
               self.backstrides = backstrides
               self.shape = shape
      +        if dtype is None:
      +            dtype = parent.dtype
               if isinstance(parent, SliceArray):
                   parent = parent.parent # one level only
               self.parent = parent
               self.storage = parent.storage
               self.order = parent.order
      -        if dtype is None:
      -            dtype = parent.dtype
               self.dtype = dtype
               self.size = support.product(shape) * self.dtype.itemtype.get_element_size()
               self.start = start
      diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
      --- a/pypy/module/micronumpy/test/test_numarray.py
      +++ b/pypy/module/micronumpy/test/test_numarray.py
      @@ -2718,8 +2718,11 @@
               d = dtype([("x", "int", (2, 3))])
               a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d)
       
      +        assert a[0]["x"].dtype == dtype("int64")
      +        assert a[0]["x"][0].dtype == dtype("int64")
      +
      +        assert (a[0]["x"][0] == [1, 2, 3]).all()
               assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all()
      -        assert (a[0]["x"][0] == [1, 2, 3]).all()
       
               d = dtype((float, (10, 10)))
               a = zeros((3,3), dtype=d)
      @@ -2729,6 +2732,18 @@
               assert (a[0, 0, 0] == 500).all()
               assert a[0, 0, 0].shape == (10,)
       
      +    def test_multidim_subarray(self):
      +        from numpypy import dtype, array, zeros
      +
      +        d = dtype([("x", "int", (2, 3))])
      +        a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d)
      +
      +        assert a[0]["x"].dtype == dtype("int64")
      +        assert a[0]["x"][0].dtype == dtype("int64")
      +
      +        assert (a[0]["x"][0] == [1, 2, 3]).all()
      +        assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all()
      +
           def test_list_record(self):
               from numpypy import dtype, array
       
      diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
      --- a/pypy/module/micronumpy/types.py
      +++ b/pypy/module/micronumpy/types.py
      @@ -1733,13 +1733,12 @@
                       itemtype.store(arr, 0, ofs, w_box)
                       ofs += itemtype.get_element_size()
               else:
      -            for i in range(len(items_w)):
      +            for w_item in items_w:
                       size = 1
                       for dimension in shape[1:]:
                           size *= dimension
                       size *= itemtype.get_element_size()
      -                for w_item in items_w:
      -                    self._coerce(space, arr, ofs, dtype, w_item, shape[1:])
      +                self._coerce(space, arr, ofs, dtype, w_item, shape[1:])
                       ofs += size
       
           def coerce(self, space, dtype, w_items):
      
      From noreply at buildbot.pypy.org  Tue May 21 17:30:16 2013
      From: noreply at buildbot.pypy.org (arigo)
      Date: Tue, 21 May 2013 17:30:16 +0200 (CEST)
      Subject: [pypy-commit] pypy.org extradoc: Add a link to this bitbucket page
      Message-ID: <20130521153016.A47811C0334@cobra.cs.uni-duesseldorf.de>
      
      Author: Armin Rigo 
      Branch: extradoc
      Changeset: r439:8d42a6abd108
      Date: 2013-05-21 17:30 +0200
      http://bitbucket.org/pypy/pypy.org/changeset/8d42a6abd108/
      
      Log:	Add a link to this bitbucket page
      
      diff --git a/download.html b/download.html
      --- a/download.html
      +++ b/download.html
      @@ -96,6 +96,7 @@
       installer vcredist_x86.exe.)
       
    • Source (tar.bz2)
    • Source (zip)
    • +
    • All our downloads, including previous versions

    If your CPU is really old, it may not have SSE2. In this case, you need to translate yourself with the option --jit-backend=x86-without-sse2.

    diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -81,6 +81,7 @@ installer vcredist_x86.exe`_.) * `Source (tar.bz2)`__ * `Source (zip)`__ +* `All our downloads,`__ including previous versions .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux64.tar.bz2 @@ -89,6 +90,7 @@ .. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/ If your CPU is really old, it may not have SSE2. In this case, you need to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. From noreply at buildbot.pypy.org Tue May 21 19:20:53 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 19:20:53 +0200 (CEST) Subject: [pypy-commit] pypy default: Swithed to declraing the type of this function in a more idiomatic way. Message-ID: <20130521172053.A47531C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64392:3788a2c016e0 Date: 2013-05-21 10:20 -0700 http://bitbucket.org/pypy/pypy/changeset/3788a2c016e0/ Log: Swithed to declraing the type of this function in a more idiomatic way. diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -9,8 +9,8 @@ # ____________________________________________________________ - at unwrap_spec(w_depth = WrappedDefault(0)) -def _getframe(space, w_depth): + at unwrap_spec(depth=int) +def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default @@ -18,7 +18,6 @@ This function should be used for internal and specialized purposes only.""" - depth = space.int_w(w_depth) if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) From noreply at buildbot.pypy.org Tue May 21 19:28:19 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 19:28:19 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: start playing with unrolling sys._getframe(depth) if depth is constant. Message-ID: <20130521172819.15C061C1361@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64393:4fcf8acb6131 Date: 2013-05-21 10:27 -0700 http://bitbucket.org/pypy/pypy/changeset/4fcf8acb6131/ Log: start playing with unrolling sys._getframe(depth) if depth is constant. diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -1,14 +1,18 @@ """ Implementation of interpreter-level 'sys' routines. """ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import unwrap_spec, WrappedDefault + from rpython.rlib import jit from rpython.rlib.runicode import MAXUNICODE +from pypy.interpreter import gateway +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec + + # ____________________________________________________________ + @unwrap_spec(depth=int) def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is @@ -21,6 +25,11 @@ if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) + return getframe(space, depth) + + + at jit.look_inside_iff(lambda space, depth: jit.isconstant(depth)) +def getframe(space, depth): ec = space.getexecutioncontext() f = ec.gettopframe_nohidden() while True: @@ -34,6 +43,7 @@ f.mark_as_escaped() return space.wrap(f) + @unwrap_spec(new_limit="c_int") def setrecursionlimit(space, new_limit): """setrecursionlimit() sets the maximum number of nested calls that From noreply at buildbot.pypy.org Tue May 21 20:17:13 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 21 May 2013 20:17:13 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: merge default Message-ID: <20130521181713.0ABC81C1361@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64394:6ea12384cdbb Date: 2013-05-21 16:34 +0200 http://bitbucket.org/pypy/pypy/changeset/6ea12384cdbb/ Log: merge default diff too long, truncating to 2000 out of 18492 lines diff --git a/lib-python/2.7/distutils/command/install.py b/lib-python/2.7/distutils/command/install.py --- a/lib-python/2.7/distutils/command/install.py +++ b/lib-python/2.7/distutils/command/install.py @@ -474,8 +474,8 @@ def select_scheme (self, name): # it's the caller's problem if they supply a bad name! - if hasattr(sys, 'pypy_version_info') and not ( - name.endswith('_user') or name.endswith('_home')): + if (hasattr(sys, 'pypy_version_info') and + not name.endswith(('_user', '_home'))): name = 'pypy' scheme = INSTALL_SCHEMES[name] for key in SCHEME_KEYS: diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp @@ -119,13 +128,13 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: - cflags = os.environ["CFLAGS"] - compiler.compiler.append(cflags) - compiler.compiler_so.append(cflags) - compiler.linker_so.append(cflags) + cflags = os.environ["CFLAGS"].split() + compiler.compiler.extend(cflags) + compiler.compiler_so.extend(cflags) + compiler.linker_so.extend(cflags) from sysconfig_cpython import ( diff --git a/lib-python/2.7/pydoc.py b/lib-python/2.7/pydoc.py --- a/lib-python/2.7/pydoc.py +++ b/lib-python/2.7/pydoc.py @@ -1953,7 +1953,11 @@ if key is None: callback(None, modname, '') else: - desc = split(__import__(modname).__doc__ or '', '\n')[0] + try: + module_doc = __import__(modname).__doc__ + except ImportError: + module_doc = None + desc = split(module_doc or '', '\n')[0] if find(lower(modname + ' - ' + desc), key) >= 0: callback(None, modname, desc) diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -324,7 +324,12 @@ if self._close: self._sock.close() else: - self._sock._decref_socketios() + try: + self._sock._decref_socketios() + except AttributeError: + pass # bah, someone built a _fileobject manually + # with some unexpected replacement of the + # _socketobject class self._sock = None def __del__(self): diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -2,7 +2,11 @@ import unittest import codecs import locale -import sys, StringIO, _testcapi +import sys, StringIO +try: + import _testcapi +except ImportError: + _testcapi = None class Queue(object): """ @@ -1387,7 +1391,7 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if encoding not in broken_incremental_coders and _testcapi: # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_fileio.py b/lib-python/2.7/test/test_fileio.py --- a/lib-python/2.7/test/test_fileio.py +++ b/lib-python/2.7/test/test_fileio.py @@ -318,7 +318,6 @@ self.assertRaises(ValueError, _FileIO, -10) self.assertRaises(OSError, _FileIO, make_bad_fd()) if sys.platform == 'win32': - raise unittest.SkipTest('Set _invalid_parameter_handler for low level io') import msvcrt self.assertRaises(IOError, msvcrt.get_osfhandle, make_bad_fd()) diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -7,7 +7,8 @@ import subprocess from copy import copy, deepcopy -from test.test_support import run_unittest, TESTFN, unlink, get_attribute +from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, + import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -236,7 +237,10 @@ def test_get_config_h_filename(self): config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print +try: + from _testcapi import traceback_print +except ImportError: + traceback_print = None from StringIO import StringIO import sys import unittest @@ -176,6 +179,8 @@ class TracebackFormatTests(unittest.TestCase): def test_traceback_format(self): + if traceback_print is None: + raise unittest.SkipTest('Requires _testcapi') try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1609,7 +1609,10 @@ self.assertEqual("{}".format(u), '__unicode__ overridden') def test_encode_decimal(self): - from _testcapi import unicode_encodedecimal + try: + from _testcapi import unicode_encodedecimal + except ImportError: + raise unittest.SkipTest('Requires _testcapi') self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -130,7 +130,7 @@ RegrTest('test_bz2.py', usemodules='bz2'), RegrTest('test_calendar.py'), RegrTest('test_call.py', core=True), - RegrTest('test_capi.py'), + RegrTest('test_capi.py', usemodules='cpyext'), RegrTest('test_cd.py'), RegrTest('test_cfgparser.py'), RegrTest('test_cgi.py'), @@ -177,7 +177,7 @@ RegrTest('test_cprofile.py'), RegrTest('test_crypt.py', usemodules='crypt'), RegrTest('test_csv.py', usemodules='_csv'), - RegrTest('test_ctypes.py', usemodules="_rawffi thread"), + RegrTest('test_ctypes.py', usemodules="_rawffi thread cpyext"), RegrTest('test_curses.py'), RegrTest('test_datetime.py', usemodules='binascii struct'), RegrTest('test_dbm.py'), diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -167,7 +167,6 @@ return if '_fields_' not in self.__dict__: self._fields_ = [] - self._names = [] _set_shape(self, [], self._is_union) __setattr__ = struct_setattr diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -54,4 +54,9 @@ fp, filename, description = imp.find_module('_testcapi', path=[output_dir]) imp.load_module('_testcapi', fp, filename, description) -compile_shared() +try: + import cpyext +except ImportError: + raise ImportError("No module named '_testcapi'") +else: + compile_shared() 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 @@ -370,7 +370,10 @@ if key in ffi._parser._declarations: tp = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) - value = backendlib.load_function(BType, name) + try: + value = backendlib.load_function(BType, name) + except KeyError: + raise AttributeError(name) library.__dict__[name] = value return # diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -1,25 +1,21 @@ -import os +import sys, os from ctypes_configure import dumpcache -from rpython.jit.backend import detect_cpu def dumpcache2(basename, config): - model = detect_cpu.autodetect_main_model_and_size() - filename = '_%s_%s_.py' % (basename, model) + size = 32 if sys.maxint <= 2**32 else 64 + filename = '_%s_%s_.py' % (basename, size) dumpcache.dumpcache(__file__, filename, config) # filename = os.path.join(os.path.dirname(__file__), '_%s_cache.py' % (basename,)) g = open(filename, 'w') print >> g, '''\ -try: - from __pypy__ import cpumodel -except ImportError: - from rpython.jit.backend import detect_cpu - cpumodel = detect_cpu.autodetect_main_model_and_size() +import sys +_size = 32 if sys.maxint <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib -mod = __import__("_%s_%%s_" %% (cpumodel,), - globals(), locals(), ["*"]) -globals().update(mod.__dict__)\ +_mod = __import__("_%s_%%s_" %% (_size,), + globals(), locals(), ["*"]) +globals().update(_mod.__dict__)\ ''' % (basename,) g.close() diff --git a/lib_pypy/ctypes_config_cache/rebuild.py b/lib_pypy/ctypes_config_cache/rebuild.py --- a/lib_pypy/ctypes_config_cache/rebuild.py +++ b/lib_pypy/ctypes_config_cache/rebuild.py @@ -25,13 +25,12 @@ sys.path[:] = path def try_rebuild(): - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - # remove the files '_*_model_.py' + size = 32 if sys.maxint <= 2**32 else 64 + # remove the files '_*_size_.py' left = {} for p in os.listdir(_dirpath): - if p.startswith('_') and (p.endswith('_%s_.py' % model) or - p.endswith('_%s_.pyc' % model)): + if p.startswith('_') and (p.endswith('_%s_.py' % size) or + p.endswith('_%s_.pyc' % size)): os.unlink(os.path.join(_dirpath, p)) elif p.startswith('_') and (p.endswith('_.py') or p.endswith('_.pyc')): diff --git a/lib_pypy/msvcrt.py b/lib_pypy/msvcrt.py --- a/lib_pypy/msvcrt.py +++ b/lib_pypy/msvcrt.py @@ -8,25 +8,37 @@ # PAC: 2010/08 added MS locking for Whoosh import ctypes +import errno from ctypes_support import standard_c_lib as _c from ctypes_support import get_errno -import errno try: open_osfhandle = _c._open_osfhandle except AttributeError: # we are not on windows raise ImportError -try: from __pypy__ import builtinify -except ImportError: builtinify = lambda f: f +try: from __pypy__ import builtinify, validate_fd +except ImportError: builtinify = validate_fd = lambda f: f open_osfhandle.argtypes = [ctypes.c_int, ctypes.c_int] open_osfhandle.restype = ctypes.c_int -get_osfhandle = _c._get_osfhandle -get_osfhandle.argtypes = [ctypes.c_int] -get_osfhandle.restype = ctypes.c_int +_get_osfhandle = _c._get_osfhandle +_get_osfhandle.argtypes = [ctypes.c_int] +_get_osfhandle.restype = ctypes.c_int + + at builtinify +def get_osfhandle(fd): + """"get_osfhandle(fd) -> file handle + + Return the file handle for the file descriptor fd. Raises IOError if + fd is not recognized.""" + try: + validate_fd(fd) + except OSError as e: + raise IOError(*e.args) + return _get_osfhandle(fd) setmode = _c._setmode setmode.argtypes = [ctypes.c_int, ctypes.c_int] diff --git a/py/_path/local.py b/py/_path/local.py --- a/py/_path/local.py +++ b/py/_path/local.py @@ -655,7 +655,8 @@ mkdtemp = classmethod(mkdtemp) def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3, - lock_timeout = 172800): # two days + lock_timeout = 172800, # two days + min_timeout = 300): # five minutes """ return unique directory with a number greater than the current maximum one. The number is assumed to start directly after prefix. if keep is true directories with a number less than (maxnum-keep) @@ -723,6 +724,20 @@ for path in rootdir.listdir(): num = parse_num(path) if num is not None and num <= (maxnum - keep): + if min_timeout: + # NB: doing this is needed to prevent (or reduce + # a lot the chance of) the following situation: + # 'keep+1' processes call make_numbered_dir() at + # the same time, they create dirs, but then the + # last process notices the first dir doesn't have + # (yet) a .lock in it and kills it. + try: + t1 = path.lstat().mtime + t2 = lockfile.lstat().mtime + if abs(t2-t1) < min_timeout: + continue # skip directories too recent + except py.error.Error: + continue # failure to get a time, better skip lf = path.join('.lock') try: t1 = lf.lstat().mtime diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,10 +32,11 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", - "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", + "thread", "itertools", "pyexpat", "_ssl", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_ffi", - "_continuation", "_cffi_backend", "_csv"] + "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"] +# disabled until problems are fixed )) translation_modules = default_modules.copy() @@ -64,6 +65,8 @@ del working_modules["termios"] del working_modules["_minimal_curses"] + del working_modules["cppyy"] # not tested on win32 + # The _locale module is needed by site.py on Windows default_modules["_locale"] = None @@ -75,20 +78,21 @@ del working_modules["_minimal_curses"] del working_modules["termios"] del working_modules["_multiprocessing"] # depends on rctime - + del working_modules["cppyy"] # depends on ctypes module_dependencies = { '_multiprocessing': [('objspace.usemodules.rctime', True), ('objspace.usemodules.thread', True)], 'cpyext': [('objspace.usemodules.array', True)], + 'cppyy': [('objspace.usemodules.cpyext', True)], } module_suggests = { # the reason you want _rawffi is for ctypes, which # itself needs the interp-level struct module # because 'P' is missing from the app-level one "_rawffi": [("objspace.usemodules.struct", True)], - "cpyext": [("translation.secondaryentrypoints", "cpyext"), + "cpyext": [("translation.secondaryentrypoints", "cpyext,main"), ("translation.shared", sys.platform == "win32")], } @@ -117,12 +121,10 @@ __import__(name) except (ImportError, CompilationError, py.test.skip.Exception), e: errcls = e.__class__.__name__ - config.add_warning( + raise Exception( "The module %r is disabled\n" % (modname,) + "because importing %s raised %s\n" % (name, errcls) + str(e)) - raise ConflictConfigError("--withmod-%s: %s" % (modname, - errcls)) return validator else: return None @@ -361,6 +363,9 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + + if config.translation.platform == 'arm' and '_continuation' in modules: + modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0-beta1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -2,94 +2,128 @@ cppyy: C++ bindings for PyPy ============================ -The cppyy module provides C++ bindings for PyPy by using the reflection -information extracted from C++ header files by means of the -`Reflex package`_. -For this to work, you have to both install Reflex and build PyPy from source, -as the cppyy module is not enabled by default. -Note that the development version of cppyy lives in the reflex-support -branch. -As indicated by this being a branch, support for Reflex is still -experimental. -However, it is functional enough to put it in the hands of those who want -to give it a try. -In the medium term, cppyy will move away from Reflex and instead use -`cling`_ as its backend, which is based on `llvm`_. -Although that will change the logistics on the generation of reflection -information, it will not change the python-side interface. +The cppyy module creates, at run-time, Python-side classes and functions for +C++, by querying a C++ reflection system. +The default system used is `Reflex`_, which extracts the needed information +from C++ header files. +Another current backend is based on `CINT`_, and yet another, more important +one for the medium- to long-term will be based on `cling`_. +The latter sits on top of `llvm`_'s `clang`_, and will therefore allow the use +of C++11. +The work on the cling backend has so far been done only for CPython, but +bringing it to PyPy is a lot less work than developing it in the first place. -.. _`Reflex package`: http://root.cern.ch/drupal/content/reflex +.. _`Reflex`: http://root.cern.ch/drupal/content/reflex +.. _`CINT`: http://root.cern.ch/drupal/content/cint .. _`cling`: http://root.cern.ch/drupal/content/cling .. _`llvm`: http://llvm.org/ +.. _`clang`: http://clang.llvm.org/ + +This document describes the version of cppyy that lives in the main branch of +PyPy. +The development of cppyy happens in the "reflex-support" branch. Motivation ========== -The cppyy module offers two unique features, which result in great -performance as well as better functionality and cross-language integration -than would otherwise be possible. -First, cppyy is written in RPython and therefore open to optimizations by the -JIT up until the actual point of call into C++. -This means that there are no conversions necessary between a garbage collected -and a reference counted environment, as is needed for the use of existing -extension modules written or generated for CPython. -It also means that if variables are already unboxed by the JIT, they can be -passed through directly to C++. -Second, Reflex (and cling far more so) adds dynamic features to C++, thus -greatly reducing impedance mismatches between the two languages. -In fact, Reflex is dynamic enough that you could write the runtime bindings +To provide bindings to another language in CPython, you program to a +generic C-API that exposes many of the interpreter features. +With PyPy, however, there is no such generic C-API, because several of the +interpreter features (e.g. the memory model) are pluggable and therefore +subject to change. +Furthermore, a generic API does not allow any assumptions about the calls +into another language, forcing the JIT to behave conservatively around these +calls and with the objects that cross language boundaries. +In contrast, cppyy does not expose an API, but expects one to be implemented +by a backend. +It makes strong assumptions about the semantics of the API that it uses and +that in turn allows the JIT to make equally strong assumptions. +This is possible, because the expected API is only for providing C++ language +bindings, and does not provide generic programmability. + +The cppyy module further offers two features, which result in improved +performance as well as better functionality and cross-language integration. +First, cppyy itself is written in RPython and therefore open to optimizations +by the JIT up until the actual point of call into C++. +This means for example, that if variables are already unboxed by the JIT, they +can be passed through directly to C++. +Second, a backend such as Reflex (and cling far more so) adds dynamic features +to C++, thus greatly reducing impedance mismatches between the two languages. +For example, Reflex is dynamic enough to allow writing runtime bindings generation in python (as opposed to RPython) and this is used to create very natural "pythonizations" of the bound code. +As another example, cling allows automatic instantiations of templates. + +See this description of the `cppyy architecture`_ for further details. + +.. _`cppyy architecture`: http://morepypy.blogspot.com/2012/06/architecture-of-cppyy.html Installation ============ -For now, the easiest way of getting the latest version of Reflex, is by -installing the ROOT package. -Besides getting the latest version of Reflex, another advantage is that with -the full ROOT package, you can also use your Reflex-bound code on `CPython`_. -`Download`_ a binary or install from `source`_. -Some Linux and Mac systems may have ROOT provided in the list of scientific -software of their packager. -If, however, you prefer a standalone version of Reflex, the best is to get -this `recent snapshot`_, and install like so:: +There are two ways of using cppyy, and the choice depends on how pypy-c was +built: the backend can be builtin, or dynamically loadable. +The former has the disadvantage of requiring pypy-c to be linked with external +C++ libraries (e.g. libReflex.so), but has the advantage of being faster in +some cases. +That advantage will disappear over time, however, with improvements in the +JIT. +Therefore, this document assumes that the dynamically loadable backend is +chosen (it is, by default). +See the `backend documentation`_. - $ tar jxf reflex-2012-05-02.tar.bz2 - $ cd reflex-2012-05-02 - $ build/autogen +.. _`backend documentation`: cppyy_backend.html + +A standalone version of Reflex that also provides the dynamically loadable +backend is available for `download`_. +That version, as well as any other distribution of Reflex (e.g. the one that +comes with `ROOT`_, which may be part of your Linux distribution as part of +the selection of scientific software) will also work for a build with the +builtin backend. + +.. _`download`: http://cern.ch/wlav/reflex-2013-04-23.tar.bz2 +.. _`ROOT`: http://root.cern.ch/ + +Besides Reflex, you probably need a version of `gccxml`_ installed, which is +most easily provided by the packager of your system. +If you read up on gccxml, you will probably notice that it is no longer being +developed and hence will not provide C++11 support. +That's why the medium term plan is to move to cling. +Note that gccxml is only needed to generate reflection libraries. +It is not needed to use them. + +.. _`gccxml`: http://www.gccxml.org + +To install the standalone version of Reflex, after download:: + + $ tar jxf reflex-2013-04-23.tar.bz2 + $ cd reflex-2013-04-23 + $ ./build/autogen $ ./configure $ make && make install -Also, make sure you have a version of `gccxml`_ installed, which is most -easily provided by the packager of your system. -If you read up on gccxml, you'll probably notice that it is no longer being -developed and hence will not provide C++11 support. -That's why the medium term plan is to move to `cling`_. +The usual rules apply: /bin needs to be added to the ``PATH`` and +/lib to the ``LD_LIBRARY_PATH`` environment variable. +For convenience, this document will assume that there is a ``REFLEXHOME`` +variable that points to . +If you downloaded or built the whole of ROOT, ``REFLEXHOME`` should be equal +to ``ROOTSYS``. -.. _`Download`: http://root.cern.ch/drupal/content/downloading-root -.. _`source`: http://root.cern.ch/drupal/content/installing-root-source -.. _`recent snapshot`: http://cern.ch/wlav/reflex-2012-05-02.tar.bz2 -.. _`gccxml`: http://www.gccxml.org +The following is optional, and is only to show how pypy-c can be build +`from source`_, for example to get at the main development branch of cppyy. +The `backend documentation`_ has more details on the backend-specific +prerequisites. -Next, get the `PyPy sources`_, optionally select the reflex-support branch, -and build it. -For the build to succeed, the ``$ROOTSYS`` environment variable must point to -the location of your ROOT (or standalone Reflex) installation, or the -``root-config`` utility must be accessible through ``PATH`` (e.g. by adding -``$ROOTSYS/bin`` to ``PATH``). -In case of the former, include files are expected under ``$ROOTSYS/include`` -and libraries under ``$ROOTSYS/lib``. Then run the translation to build ``pypy-c``:: $ hg clone https://bitbucket.org/pypy/pypy $ cd pypy $ hg up reflex-support # optional - $ cd pypy/goal # This example shows python, but using pypy-c is faster and uses less memory - $ python ../../rpython/bin/rpython.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy + $ python rpython/translator/goal/translate.py --opt=jit pypy/goal/targetpypystandalone --withmod-cppyy This will build a ``pypy-c`` that includes the cppyy module, and through that, Reflex support. @@ -98,12 +132,12 @@ If not, you may want `to obtain a binary distribution`_ to speed up the translation step. -.. _`PyPy sources`: https://bitbucket.org/pypy/pypy/overview +.. _`from source`: https://bitbucket.org/pypy/pypy/overview .. _`to obtain a binary distribution`: http://doc.pypy.org/en/latest/getting-started.html#download-a-pre-built-pypy -Basic example -============= +Basic bindings example +====================== Now test with a trivial example whether all packages are properly installed and functional. @@ -127,7 +161,7 @@ code:: $ genreflex MyClass.h - $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex + $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex Now you're ready to use the bindings. Since the bindings are designed to look pythonistic, it should be @@ -176,7 +210,7 @@ For example:: $ genreflex MyClass.h --rootmap=libMyClassDict.rootmap --rootmap-lib=libMyClassDict.so - $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex + $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex where the first option (``--rootmap``) specifies the output file name, and the second option (``--rootmap-lib``) the name of the reflection library where @@ -277,7 +311,7 @@ Now the reflection info can be generated and compiled:: $ genreflex MyAdvanced.h --selection=MyAdvanced.xml - $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp -o libAdvExDict.so -L$ROOTSYS/lib -lReflex + $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyAdvanced_rflx.cpp -o libAdvExDict.so -L$REFLEXHOME/lib -lReflex and subsequently be used from PyPy:: @@ -336,7 +370,7 @@ bound using:: $ genreflex example.h --deep --rootmap=libexampleDict.rootmap --rootmap-lib=libexampleDict.so - $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include example_rflx.cpp -o libexampleDict.so -L$ROOTSYS/lib -lReflex + $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include example_rflx.cpp -o libexampleDict.so -L$REFLEXHOME/lib -lReflex .. _`example code`: cppyy_example.html @@ -595,6 +629,16 @@ All template classes must already exist in the loaded reflection info, they do not work (yet) with the class loader. + For compatibility with other bindings generators, use of square brackets + instead of parenthesis to instantiate templates is supported as well. + +* **templated functions**: Automatically participate in overloading and are + used in the same way as other global functions. + +* **templated methods**: For now, require an explicit selection of the + template parameters. + This will be changed to allow them to participate in overloads as expected. + * **typedefs**: Are simple python references to the actual classes to which they refer. @@ -692,7 +736,7 @@ Run the normal ``genreflex`` and compilation steps:: $ genreflex MyTemplate.h --selection=MyTemplate.xml - $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp -o libTemplateDict.so -L$ROOTSYS/lib -lReflex + $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyTemplate_rflx.cpp -o libTemplateDict.so -L$REFLEXHOME/lib -lReflex Note: this is a dirty corner that clearly could do with some automation, even if the macro already helps. @@ -727,18 +771,18 @@ The fast lane ============= -The following is an experimental feature of cppyy, and that makes it doubly -experimental, so caveat emptor. +The following is an experimental feature of cppyy. +It mostly works, but there are some known issues (e.g. with return-by-value). +Soon it should be the default mode, however. + With a slight modification of Reflex, it can provide function pointers for C++ methods, and hence allow PyPy to call those pointers directly, rather than calling C++ through a Reflex stub. -This results in a rather significant speed-up. -Mind you, the normal stub path is not exactly slow, so for now only use this -out of curiosity or if you really need it. -To install this patch of Reflex, locate the file genreflex-methptrgetter.patch -in pypy/module/cppyy and apply it to the genreflex python scripts found in -``$ROOTSYS/lib``:: +The standalone version of Reflex `provided`_ has been patched, but if you get +Reflex from another source (most likely with a ROOT distribution), locate the +file `genreflex-methptrgetter.patch`_ in pypy/module/cppyy and apply it to +the genreflex python scripts found in ``$ROOTSYS/lib``:: $ cd $ROOTSYS/lib $ patch -p2 < genreflex-methptrgetter.patch @@ -749,8 +793,10 @@ ``-Wno-pmf-conversions`` option to ``g++`` when compiling. The rest works the same way: the fast path will be used transparently (which also means that you can't actually find out whether it is in use, other than -by running a micro-benchmark). +by running a micro-benchmark or a JIT test). +.. _`provided`: http://cern.ch/wlav/reflex-2013-04-23.tar.bz2 +.. _`genreflex-methptrgetter.patch`: https://bitbucket.org/pypy/pypy/src/default/pypy/module/cppyy/genreflex-methptrgetter.patch CPython ======= diff --git a/pypy/doc/cppyy_backend.rst b/pypy/doc/cppyy_backend.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/cppyy_backend.rst @@ -0,0 +1,53 @@ +================== +Backends for cppyy +================== + +The cppyy module needs a backend to provide the C++ reflection information on +which the Python bindings are build. +The backend is called through a C-API, which can be found in the PyPy sources +in: `pypy/module/cppyy/include/capi.h`_. +There are two kinds of API calls: querying about reflection information, which +are used during the creation of Python-side constructs, and making the actual +calls into C++. +The objects passed around are all opaque: cppyy does not make any assumptions +about them, other than that the opaque handles can be copied. +Their definition, however, appears in two places: in the C code (in capi.h), +and on the RPython side (in `capi_types.py`_), so if they are changed, they +need to be changed on both sides. + +.. _`pypy/module/cppyy/include/capi.h`: https://bitbucket.org/pypy/pypy/src/default/pypy/module/cppyy/include/capi.h +.. _`capi_types.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/module/cppyy/capi/capi_types.py + +There are two places where selections in the RPython code affect the choice +(and use) of the backend. +The first is in `pypy/module/cppyy/capi/__init__.py`_:: + + # choose C-API access method: + from pypy.module.cppyy.capi.loadable_capi import * + #from pypy.module.cppyy.capi.builtin_capi import * + +The default is the loadable C-API. +Comment it and uncomment the builtin C-API line, to use the builtin version. + +.. _`pypy/module/cppyy/capi/__init__.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/module/cppyy/capi/__init__.py + +Next, if the builtin C-API is chosen, the specific backend needs to be set as +well (default is Reflex). +This second choice is in `pypy/module/cppyy/capi/builtin_capi.py`_:: + + import reflex_capi as backend + #import cint_capi as backend + +After those choices have been made, built pypy-c as usual. + +.. _`pypy/module/cppyy/capi/builtin_capi.py`: https://bitbucket.org/pypy/pypy/src/default/pypy/module/cppyy/capi/builtin_capi.py + +When building pypy-c from source, keep the following in mind. +If the loadable_capi is chosen, no further prerequisites are needed. +However, for the build of the builtin_capi to succeed, the ``ROOTSYS`` +environment variable must point to the location of your ROOT (or standalone +Reflex in the case of the Reflex backend) installation, or the ``root-config`` +utility must be accessible through ``$PATH`` (e.g. by adding ``$ROOTSYS/bin`` +to ``PATH``). +In case of the former, include files are expected under ``$ROOTSYS/include`` +and libraries under ``$ROOTSYS/lib``. diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -46,7 +46,7 @@ 2. Install build-time dependencies. On a Debian box these are:: [user at debian-box ~]$ sudo apt-get install \ - gcc make python-dev libffi-dev lib-sqlite3-dev pkg-config \ + gcc make python-dev libffi-dev libsqlite3-dev pkg-config \ libz-dev libbz2-dev libncurses-dev libexpat1-dev \ libssl-dev libgc-dev python-sphinx python-greenlet @@ -105,7 +105,7 @@ $ ./pypy-c Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``RPython magically makes you rich and famous (says so on the tin)'' @@ -235,7 +235,7 @@ the ``bin/pypy`` executable. To install PyPy system wide on unix-like systems, it is recommended to put the -whole hierarchy alone (e.g. in ``/opt/pypy2.0-beta1``) and put a symlink to the +whole hierarchy alone (e.g. in ``/opt/pypy2.0``) and put a symlink to the ``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -53,10 +53,10 @@ PyPy is ready to be executed as soon as you unpack the tarball or the zip file, with no need to install it in any specific location:: - $ tar xf pypy-2.0-beta1-linux.tar.bz2 - $ ./pypy-2.0-beta1/bin/pypy + $ tar xf pypy-2.0.tar.bz2 + $ ./pypy-2.0/bin/pypy Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``PyPy is an exciting technology that lets you to write fast, portable, multi-platform interpreters with less @@ -75,14 +75,14 @@ $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.0-beta1/bin/pypy distribute_setup.py + $ ./pypy-2.0/bin/pypy distribute_setup.py - $ ./pypy-2.0-beta1/bin/pypy get-pip.py + $ ./pypy-2.0/bin/pypy get-pip.py - $ ./pypy-2.0-beta1/bin/pip install pygments # for example + $ ./pypy-2.0/bin/pip install pygments # for example -3rd party libraries will be installed in ``pypy-2.0-beta1/site-packages``, and -the scripts in ``pypy-2.0-beta1/bin``. +3rd party libraries will be installed in ``pypy-2.0/site-packages``, and +the scripts in ``pypy-2.0/bin``. Installing using virtualenv --------------------------- diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0 beta 2`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0 beta 2`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.0.rst @@ -0,0 +1,71 @@ +============================ +PyPy 2.0 - Einstein Sandwich +============================ + +We're pleased to announce PyPy 2.0. This is a stable release that brings +a swath of bugfixes, small performance improvements and compatibility fixes. +PyPy 2.0 is a big step for us and we hope in the future we'll be able to +provide stable releases more often. + +You can download the PyPy 2.0 release here: + + http://pypy.org/download.html + +The two biggest changes since PyPy 1.9 are: + +* stackless is now supported including greenlets, which means eventlet + and gevent should work (but read below about gevent) + +* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which + is preferred way of calling C from Python that works well on PyPy + +.. _`cffi`: http://cffi.readthedocs.org + +If you're using PyPy for anything, it would help us immensely if you fill out +the following survey: http://bit.ly/pypysurvey This is for the developers +eyes and we will not make any information public without your agreement. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Windows 64 work is still stalling, we would welcome a volunteer +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +* Stackless including greenlets should work. For gevent, you need to check + out `pypycore`_ and use the `pypy-hacks`_ branch of gevent. + +* cffi is now a module included with PyPy. (`cffi`_ also exists for + CPython; the two versions should be fully compatible.) It is the + preferred way of calling C from Python that works on PyPy. + +* Callbacks from C are now JITted, which means XML parsing is much faster. + +* A lot of speed improvements in various language corners, most of them small, + but speeding up some particular corners a lot. + +* The JIT was refactored to emit machine code which manipulates a "frame" + that lives on the heap rather than on the stack. This is what makes + Stackless work, and it could bring another future speed-up (not done yet). + +* A lot of stability issues fixed. + +* Refactoring much of the numpypy array classes, which resulted in removal of + lazy expression evaluation. On the other hand, we now have more complete + dtype support and support more array attributes. + +.. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ +.. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks + +Cheers, +fijal, arigo and the PyPy team diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.1.rst @@ -0,0 +1,46 @@ +============================== +PyPy 2.0.1 - Bohr Smørrebrød +============================== + +We're pleased to announce PyPy 2.0.1. This is a stable bugfix release +over `2.0`_. You can download it here: + + http://pypy.org/download.html + +The fixes are mainly about fatal errors or crashes in our stdlib. See +below for more details. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +- fix an occasional crash in the JIT that ends in `RPython Fatal error: + NotImplementedError`__. + +- `id(x)` is now always a positive number (except on int/float/long/complex). + This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux). + +- fix crashes of callback-from-C-functions (with cffi) when used together + with Stackless features, on asmgcc (i.e. Linux only). Now `gevent should + work better`__. + +- work around an eventlet issue with `socket._decref_socketios()`__. + +.. __: https://bugs.pypy.org/issue1482 +.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html +.. __: https://bugs.pypy.org/issue1468 +.. _2.0: release-2.0.0.html + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,46 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-2.0.rst copy from pypy/doc/whatsnew-head.rst copy to pypy/doc/whatsnew-2.0.rst diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -1,140 +1,27 @@ ====================== -What's new in PyPy 2.0 +What's new in PyPy 2.1 ====================== -.. this is a revision shortly after release-2.0-beta1 -.. startrev: 0e6161a009c6 +.. this is a revision shortly after release-2.0 +.. startrev: a13c07067613 -.. branch: split-rpython -Split rpython and pypy into seperate directories +.. branch: numpy-pickle +Pickling of numpy arrays and dtypes (including record dtypes) -.. branch: callback-jit -Callbacks from C are now better JITted +.. branch: remove-array-smm +Remove multimethods in the arraymodule -.. branch: fix-jit-logs +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback -.. branch: remove-globals-in-jit +.. branch: remove-set-smm +Remove multi-methods on sets -.. branch: length-hint -Implement __lenght_hint__ according to PEP 424 +.. branch: numpy-subarrays +Implement subarrays for numpy -.. branch: numpypy-longdouble -Long double support for numpypy +.. branch: remove-dict-smm +Remove multi-methods on dict -.. branch: numpypy-disable-longdouble -Since r_longdouble support is missing, disable all longdouble and derivative -dtypes using ENABLED_LONG_DOUBLE = False - -.. branch: numpypy-real-as-view -Convert real, imag from ufuncs to views. This involves the beginning of -view() functionality - -.. branch: indexing-by-array -Adds indexing by scalar, adds int conversion from scalar and single element array, -fixes compress, indexing by an array with a smaller shape and the indexed object. - -.. branch: str-dtype-improvement -Allow concatenation of str and numeric arrays - -.. branch: signatures -Improved RPython typing - -.. branch: rpython-bytearray -Rudimentary support for bytearray in RPython - -.. branch: refactor-call_release_gil -Fix a bug which caused cffi to return the wrong result when calling a C -function which calls a Python callback which forces the frames - -.. branch: virtual-raw-mallocs -JIT optimizations which make cffi calls even faster, by removing the need to -allocate a temporary buffer where to store the arguments. - -.. branch: improve-docs-2 -Improve documents and straighten out links - -.. branch: fast-newarray -Inline the fast path of newarray in the assembler. -Disabled on ARM until we fix issues. - -.. branch: reflex-support -Allow dynamic loading of a (Reflex) backend that implements the C-API needed -to provide reflection information - -.. branches we don't care about -.. branch: autoreds -.. branch: kill-faking -.. branch: improved_ebnfparse_error -.. branch: task-decorator -.. branch: fix-e4fa0b2 -.. branch: win32-fixes -.. branch: numpy-unify-methods -.. branch: fix-version-tool -.. branch: popen2-removal -.. branch: pickle-dumps -.. branch: scalar_get_set - -.. branch: release-2.0-beta1 - -.. branch: remove-PYPY_NOT_MAIN_FILE - -.. branch: missing-jit-operations - -.. branch: fix-lookinside-iff-oopspec -Fixed the interaction between two internal tools for controlling the JIT. - -.. branch: inline-virtualref-2 -Better optimized certain types of frame accesses in the JIT, particularly -around exceptions that escape the function they were raised in. - -.. branch: missing-ndarray-attributes -Some missing attributes from ndarrays - -.. branch: cleanup-tests -Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into -one directory for reduced confusion and so they all run nightly. - -.. branch: unquote-faster -.. branch: urlparse-unquote-faster - -.. branch: signal-and-thread -Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a -non-main thread to enable the processing of signal handlers in that thread. - -.. branch: coding-guide-update-rlib-refs -.. branch: rlib-doc-rpython-refs -.. branch: clean-up-remaining-pypy-rlib-refs - -.. branch: enumerate-rstr -Support enumerate() over rstr types. - -.. branch: cleanup-numpypy-namespace -Cleanup _numpypy and numpypy namespaces to more closely resemble numpy. - -.. branch: kill-flowobjspace -Random cleanups to hide FlowObjSpace from public view. - -.. branch: vendor-rename - -.. branch: jitframe-on-heap -Moves optimized JIT frames from stack to heap. As a side effect it enables -stackless to work well with the JIT on PyPy. Also removes a bunch of code from -the GC which fixes cannot find gc roots. - -.. branch: pycon2013-doc-fixes -Documentation fixes after going through the docs at PyCon 2013 sprint. - -.. branch: extregistry-refactor - -.. branch: remove-list-smm -.. branch: bridge-logging -.. branch: curses_cffi -cffi implementation of _curses - -.. branch: sqlite-cffi -cffi implementation of sqlite3 - -.. branch: release-2.0-beta2 -.. branch: unbreak-freebsd - -.. branch: virtualref-virtualizable +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -6,8 +6,16 @@ if sys.platform.startswith('linux'): arch = 'linux' + cmd = 'wget "%s"' + tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" + if os.uname()[-1].startswith('arm'): + arch += '-armhf-raspbian' +elif sys.platform.startswith('darwin'): + arch = 'osx' + cmd = 'curl -O "%s"' + tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" else: - print 'Cannot determine the platform, please update this scrip' + print 'Cannot determine the platform, please update this script' sys.exit(1) if sys.maxint == 2**63 - 1: @@ -23,10 +31,9 @@ tmp = py.path.local.mkdtemp() mydir = tmp.chdir() print 'Downloading pypy to', tmp -if os.system('wget "%s"' % url) != 0: +if os.system(cmd % url) != 0: sys.exit(1) print 'Extracting pypy binary' mydir.chdir() -os.system("tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" % tmp.join(filename)) - +os.system(tar % tmp.join(filename)) diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -2,6 +2,7 @@ import os, sys +import pypy from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.tool.ann_override import PyPyAnnotatorPolicy @@ -9,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -22,20 +25,22 @@ # __________ Entry point __________ + def create_entry_point(space, w_dict): - w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) - w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) - w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) - w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) - withjit = space.config.objspace.usemodules.pypyjit + if w_dict is not None: # for tests + w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) + w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) + w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) + w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) + withjit = space.config.objspace.usemodules.pypyjit def entry_point(argv): if withjit: from rpython.jit.backend.hlinfo import highleveljitinfo highleveljitinfo.sys_executable = argv[0] - #debug("entry point starting") - #for arg in argv: + #debug("entry point starting") + #for arg in argv: # debug(" argv -> " + arg) if len(argv) > 2 and argv[1] == '--heapsize': # Undocumented option, handled at interp-level. @@ -71,7 +76,81 @@ debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 return exitcode - return entry_point + + # register the minimal equivalent of running a small piece of code. This + # should be used as sparsely as possible, just to register callbacks + + from rpython.rlib.entrypoint import entrypoint + from rpython.rtyper.lltypesystem import rffi, lltype + + w_pathsetter = space.appexec([], """(): + def f(path): + import sys + sys.path[:] = path + return f + """) + + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') + def pypy_setup_home(ll_home, verbose): + from pypy.module.sys.initpath import pypy_find_stdlib + if ll_home: + home = rffi.charp2str(ll_home) + else: + home = pypydir + w_path = pypy_find_stdlib(space, home) + if space.is_none(w_path): + if verbose: + debug("Failed to find library based on pypy_find_stdlib") + return 1 + space.startup() + space.call_function(w_pathsetter, w_path) + # import site + try: + import_ = space.getattr(space.getbuiltinmodule('__builtin__'), + space.wrap('__import__')) + space.call_function(import_, space.wrap('site')) + return 0 + except OperationError, e: + if verbose: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + + @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') + def pypy_execute_source(ll_source): + source = rffi.charp2str(ll_source) + return _pypy_execute_source(source) + + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + rthread.gc_thread_start() + + w_globals = space.newdict() + space.setitem(w_globals, space.wrap('__builtins__'), + space.builtin_modules['__builtin__']) + + def _pypy_execute_source(source): + try: + compiler = space.createcompiler() + stmt = compiler.compile(source, 'c callback', 'exec', 0) + stmt.exec_code(space, w_globals, w_globals) + except OperationError, e: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + return 0 + + return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, + 'pypy_setup_home': pypy_setup_home} def call_finish(space): space.finish() @@ -219,7 +298,7 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy, pypy_hooks return PyPyJitPolicy(pypy_hooks) - + def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy rebuild = import_from_lib_pypy('ctypes_config_cache/rebuild') @@ -232,7 +311,7 @@ app = gateway.applevel(open(filename).read(), 'app_main.py', 'app_main') app.hidden_applevel = False w_dict = app.getwdict(space) - entry_point = create_entry_point(space, w_dict) + entry_point, _ = create_entry_point(space, w_dict) return entry_point, None, PyPyAnnotatorPolicy(single_space = space) diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -1,20 +1,40 @@ #! /usr/bin/env python # App-level version of py.py. # See test/test_app_main. + +# Missing vs CPython: -d, -OO, -t, -v, -x, -3 +"""\ +Options and arguments (and corresponding environment variables): +-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x +-c cmd : program passed in as string (terminates option list) +-E : ignore PYTHON* environment variables (such as PYTHONPATH) +-h : print this help message and exit (also --help) +-i : inspect interactively after running script; forces a prompt even + if stdin does not appear to be a terminal; also PYTHONINSPECT=x +-m mod : run library module as a script (terminates option list) +-O : dummy optimization flag for compatibility with CPython +-R : ignored (see http://bugs.python.org/issue14621) +-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew +-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE +-S : don't imply 'import site' on initialization +-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x +-V : print the Python version number and exit (also --version) +-W arg : warning control; arg is action:message:category:module:lineno + also PYTHONWARNINGS=arg +file : program read from script file +- : program read from stdin (default; interactive mode if a tty) +arg ...: arguments passed to program in sys.argv[1:] +PyPy options and arguments: +--info : print translation information about this PyPy executable """ -options: - -i inspect interactively after running script - -O dummy optimization flag for compatibility with C Python - -c cmd program passed in as CMD (terminates option list) - -S do not 'import site' on initialization - -u unbuffered binary stdout and stderr - -h, --help show this help message and exit - -m mod library module to be run as a script (terminates option list) - -W arg warning control (arg is action:message:category:module:lineno) - -E ignore environment variables (such as PYTHONPATH) - -R ignored (see http://bugs.python.org/issue14621) - --version print the PyPy version - --info print translation information about this PyPy executable +USAGE1 = __doc__ +# Missing vs CPython: PYTHONHOME, PYTHONCASEOK +USAGE2 = """ +Other environment variables: +PYTHONSTARTUP: file executed on interactive startup (no default) +PYTHONPATH : %r-separated list of directories prefixed to the + default module search path. The result is sys.path. +PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr. """ import sys @@ -136,12 +156,13 @@ raise SystemExit def print_help(*args): - print 'usage: %s [options] [-c cmd|-m mod|file.py|-] [arg...]' % ( + import os + print 'usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...' % ( sys.executable,) - print __doc__.rstrip() + print USAGE1, if 'pypyjit' in sys.builtin_module_names: - print " --jit OPTIONS advanced JIT options: try 'off' or 'help'" - print + print "--jit options: advanced JIT options: try 'off' or 'help'" + print (USAGE2 % (os.pathsep,)), raise SystemExit def _print_jit_help(): diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -853,9 +853,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -864,6 +865,37 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists/sets of constants in the context of "in"/"not in". + + lists are folded into tuples, sets into frozensets, otherwise + returns False + """ + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/consts.py b/pypy/interpreter/astcompiler/consts.py --- a/pypy/interpreter/astcompiler/consts.py +++ b/pypy/interpreter/astcompiler/consts.py @@ -15,8 +15,6 @@ CO_FUTURE_WITH_STATEMENT = 0x8000 CO_FUTURE_PRINT_FUNCTION = 0x10000 CO_FUTURE_UNICODE_LITERALS = 0x20000 -CO_CONTAINSGLOBALS = 0x80000 # pypy-specific: need to check that it's not used - # by any other flag PyCF_SOURCE_IS_UTF8 = 0x0100 PyCF_DONT_IMPLY_DEDENT = 0x0200 diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -973,3 +973,30 @@ counts = self.count_instructions(source3) assert counts[ops.BUILD_LIST] == 1 assert ops.BUILD_LIST_FROM_ARG not in counts + + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): @@ -666,7 +671,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -803,7 +803,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -812,11 +811,13 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = {} + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -27,7 +27,7 @@ new_inst = mod.get('generator_new') w = space.wrap if self.frame: - w_frame = w(self.frame) + w_frame = self.frame._reduce_state(space) else: w_frame = space.w_None @@ -36,7 +36,20 @@ w(self.running), ] - return space.newtuple([new_inst, space.newtuple(tup)]) + return space.newtuple([new_inst, space.newtuple([]), + space.newtuple(tup)]) + + def descr__setstate__(self, space, w_args): + from rpython.rlib.objectmodel import instantiate + args_w = space.unpackiterable(w_args) + w_framestate, w_running = args_w + if space.is_w(w_framestate, space.w_None): + self.frame = None + else: + frame = instantiate(space.FrameClass) # XXX fish + frame.descr__setstate__(space, w_framestate) + GeneratorIterator.__init__(self, frame) + self.running = self.space.is_true(w_running) def descr__iter__(self): """x.__iter__() <==> iter(x)""" diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -13,6 +13,7 @@ # imported yet, and when it has been, it is mod.__dict__.items() just # after startup(). w_initialdict = None + lazy = False def __init__(self, space, w_name): """ NOT_RPYTHON """ diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -12,7 +12,7 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.astcompiler.consts import ( CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED, - CO_GENERATOR, CO_CONTAINSGLOBALS) + CO_GENERATOR) from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT from rpython.rlib.rarithmetic import intmask from rpython.rlib.objectmodel import compute_hash @@ -88,8 +88,6 @@ self._initialize() def _initialize(self): - self._init_flags() - if self.co_cellvars: argcount = self.co_argcount assert argcount >= 0 # annotator hint @@ -134,22 +132,6 @@ '__pypy__' not in sys.builtin_module_names): raise Exception("CPython host codes should not be rendered") - def _init_flags(self): - co_code = self.co_code - next_instr = 0 - while next_instr < len(co_code): - opcode = ord(co_code[next_instr]) - next_instr += 1 - if opcode >= HAVE_ARGUMENT: - next_instr += 2 - while opcode == opcodedesc.EXTENDED_ARG.index: - opcode = ord(co_code[next_instr]) - next_instr += 3 - if opcode == opcodedesc.LOAD_GLOBAL.index: - self.co_flags |= CO_CONTAINSGLOBALS - elif opcode == opcodedesc.LOAD_NAME.index: - self.co_flags |= CO_CONTAINSGLOBALS - co_names = property(lambda self: [self.space.unwrap(w_name) for w_name in self.co_names_w]) # for trace def signature(self): diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -16,10 +16,9 @@ from rpython.tool.stdlib_opcode import host_bytecode_spec # Define some opcodes used -g = globals() for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY POP_BLOCK END_FINALLY'''.split(): - g[op] = stdlib_opcode.opmap[op] + globals()[op] = stdlib_opcode.opmap[op] HAVE_ARGUMENT = stdlib_opcode.HAVE_ARGUMENT class PyFrame(eval.Frame): @@ -303,11 +302,17 @@ @jit.dont_look_inside def descr__reduce__(self, space): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('frame_new') - w = space.wrap + w_tup_state = self._reduce_state(space) + nt = space.newtuple + return nt([new_inst, nt([]), w_tup_state]) + + @jit.dont_look_inside + def _reduce_state(self, space): + from pypy.module._pickle_support import maker # helper fns + w = space.wrap nt = space.newtuple cells = self._getcells() @@ -358,8 +363,7 @@ w(self.instr_prev_plus_one), w_cells, ] - - return nt([new_inst, nt([]), nt(tup_state)]) + return nt(tup_state) @jit.dont_look_inside def descr__setstate__(self, space, w_args): diff --git a/pypy/interpreter/test2/mymodule.py b/pypy/interpreter/test/mymodule.py rename from pypy/interpreter/test2/mymodule.py rename to pypy/interpreter/test/mymodule.py diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py new file mode 100644 --- /dev/null +++ b/pypy/interpreter/test/test_app_main.py @@ -0,0 +1,978 @@ +""" +Tests for the entry point of pypy-c, app_main.py. +""" +from __future__ import with_statement +import py +import sys, os, re, runpy, subprocess +from rpython.tool.udir import udir +from contextlib import contextmanager +from pypy.conftest import pypydir + +banner = sys.version.splitlines()[0] + +app_main = os.path.join(os.path.realpath(os.path.dirname(__file__)), os.pardir, 'app_main.py') +app_main = os.path.abspath(app_main) + +_counter = 0 +def _get_next_path(ext='.py'): + global _counter + p = udir.join('demo_test_app_main_%d%s' % (_counter, ext)) + _counter += 1 + return p + +def getscript(source): + p = _get_next_path() + p.write(str(py.code.Source(source))) + return str(p) + +def getscript_pyc(space, source): + p = _get_next_path() + p.write(str(py.code.Source(source))) + w_dir = space.wrap(str(p.dirpath())) + w_modname = space.wrap(p.purebasename) + space.appexec([w_dir, w_modname], """(dir, modname): + import sys + d = sys.modules.copy() + sys.path.insert(0, dir) + __import__(modname) + sys.path.pop(0) + for key in sys.modules.keys(): + if key not in d: + del sys.modules[key] + """) + p = str(p) + 'c' + assert os.path.isfile(p) # the .pyc file should have been created above + return p + +def getscript_in_dir(source): + pdir = _get_next_path(ext='') + p = pdir.ensure(dir=1).join('__main__.py') + p.write(str(py.code.Source(source))) + # return relative path for testing purposes + return py.path.local().bestrelpath(pdir) + +demo_script = getscript(""" + print 'hello' + print 'Name:', __name__ + print 'File:', __file__ + import sys + print 'Exec:', sys.executable + print 'Argv:', sys.argv + print 'goodbye' + myvalue = 6*7 + """) + +crashing_demo_script = getscript(""" + print 'Hello2' + myvalue2 = 11 + ooups + myvalue2 = 22 + print 'Goodbye2' # should not be reached + """) + + +class TestParseCommandLine: + def check_options(self, options, sys_argv, **expected): + assert sys.argv == sys_argv + for key, value in expected.items(): + assert options[key] == value + for key, value in options.items(): + if key not in expected: + assert not value, ( + "option %r has unexpectedly the value %r" % (key, value)) + + def check(self, argv, env, **expected): From noreply at buildbot.pypy.org Tue May 21 20:17:14 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 21 May 2013 20:17:14 +0200 (CEST) Subject: [pypy-commit] pypy default: an attempt to fix translation without thread Message-ID: <20130521181714.805761C1361@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64395:47ba0f363929 Date: 2013-05-21 20:15 +0200 http://bitbucket.org/pypy/pypy/changeset/47ba0f363929/ Log: an attempt to fix translation without thread diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,12 +124,14 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - os_thread.setup_threads(space) - rffi.aroundstate.before() + if space.config.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - rthread.gc_thread_start() + if space.config.usemodules.thread: + rthread.gc_thread_start() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), From noreply at buildbot.pypy.org Tue May 21 20:26:12 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 21 May 2013 20:26:12 +0200 (CEST) Subject: [pypy-commit] pypy default: typo Message-ID: <20130521182612.90E011C1559@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64396:f752335dabb7 Date: 2013-05-21 20:25 +0200 http://bitbucket.org/pypy/pypy/changeset/f752335dabb7/ Log: typo diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,13 +124,13 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - if space.config.usemodules.thread: + if space.config.objspace.usemodules.thread: os_thread.setup_threads(space) rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - if space.config.usemodules.thread: + if space.config.objspace.usemodules.thread: rthread.gc_thread_start() w_globals = space.newdict() From noreply at buildbot.pypy.org Tue May 21 21:03:47 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 21:03:47 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: A useful docstring. Message-ID: <20130521190347.D97211C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64397:82747c0d598b Date: 2013-05-21 12:01 -0700 http://bitbucket.org/pypy/pypy/changeset/82747c0d598b/ Log: A useful docstring. diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py --- a/rpython/jit/metainterp/virtualizable.py +++ b/rpython/jit/metainterp/virtualizable.py @@ -231,6 +231,10 @@ self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): + """ + Returns whether or not the virtualizable was forced during a + CALL_MAY_FORCE. + """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still From noreply at buildbot.pypy.org Tue May 21 21:03:49 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 21:03:49 +0200 (CEST) Subject: [pypy-commit] pypy default: A useful docstring. Message-ID: <20130521190349.4E41A1C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64398:bb653e057f20 Date: 2013-05-21 12:01 -0700 http://bitbucket.org/pypy/pypy/changeset/bb653e057f20/ Log: A useful docstring. diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py --- a/rpython/jit/metainterp/virtualizable.py +++ b/rpython/jit/metainterp/virtualizable.py @@ -231,6 +231,10 @@ self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): + """ + Returns whether or not the virtualizable was forced during a + CALL_MAY_FORCE. + """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still From noreply at buildbot.pypy.org Tue May 21 21:03:50 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 21:03:50 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20130521190350.95C631C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64399:e59970e51fc5 Date: 2013-05-21 12:02 -0700 http://bitbucket.org/pypy/pypy/changeset/e59970e51fc5/ Log: merged upstream diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,12 +124,14 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - os_thread.setup_threads(space) - rffi.aroundstate.before() + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - rthread.gc_thread_start() + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), From noreply at buildbot.pypy.org Tue May 21 22:26:29 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 22:26:29 +0200 (CEST) Subject: [pypy-commit] pypy on-abort-resops: A branch in which to make the on_abort jit hook include the resops so far. Message-ID: <20130521202629.1AABA1C1361@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: on-abort-resops Changeset: r64400:9073505f32a7 Date: 2013-05-21 13:05 -0700 http://bitbucket.org/pypy/pypy/changeset/9073505f32a7/ Log: A branch in which to make the on_abort jit hook include the resops so far. diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,9 +1,11 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo) + class PyPyJitIface(JitHookInterface): def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -1,11 +1,10 @@ +from rpython.annotator import model as annmodel +from rpython.rlib.objectmodel import specialize +from rpython.rtyper.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance, llstr) +from rpython.rtyper.extregistry import ExtRegistryEntry +from rpython.rtyper.lltypesystem import llmemory, lltype, rclass -from rpython.rtyper.extregistry import ExtRegistryEntry -from rpython.annotator import model as annmodel -from rpython.rtyper.lltypesystem import llmemory, lltype -from rpython.rtyper.lltypesystem import rclass -from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr,\ - cast_base_ptr_to_instance, llstr -from rpython.rlib.objectmodel import specialize def register_helper(s_result): def wrapper(helper): From noreply at buildbot.pypy.org Tue May 21 22:26:30 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 22:26:30 +0200 (CEST) Subject: [pypy-commit] pypy on-abort-resops: When calling the abort handler, include the list of operations thus Message-ID: <20130521202630.79DD81C13E5@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: on-abort-resops Changeset: r64401:fc25a3ecd9a4 Date: 2013-05-21 13:25 -0700 http://bitbucket.org/pypy/pypy/changeset/fc25a3ecd9a4/ Log: When calling the abort handler, include the list of operations thus diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -4,25 +4,26 @@ from pypy.interpreter.error import OperationError from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, - WrappedOp, W_JitLoopInfo) + WrappedOp, W_JitLoopInfo, wrap_oplist) class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1876,7 +1876,9 @@ self.staticdata.warmrunnerdesc.hooks.on_abort(reason, jd_sd.jitdriver, greenkey, - jd_sd.warmstate.get_location_str(greenkey)) + jd_sd.warmstate.get_location_str(greenkey), + self.staticdata.logger_ops, + self.history.operations) self.staticdata.stats.aborted() def blackhole_if_trace_too_long(self): diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -7,18 +7,20 @@ from rpython.rtyper.annlowlevel import hlstr from rpython.jit.metainterp.jitprof import Profiler + class JitHookInterfaceTests(object): # !!!note!!! - don't subclass this from the backend. Subclass the LL # class later instead def test_abort_quasi_immut(self): reasons = [] - + class MyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): assert jitdriver is myjitdriver assert len(greenkey) == 1 reasons.append(reason) assert greenkey_repr == 'blah' + assert len(operations) > 1 iface = MyJitIface() @@ -27,8 +29,10 @@ class Foo: _immutable_fields_ = ['a?'] + def __init__(self, a): self.a = a + def f(a, x): foo = Foo(a) total = 0 @@ -47,7 +51,7 @@ def test_on_compile(self): called = [] - + class MyJitIface(JitHookInterface): def after_compile(self, di): called.append(("compile", di.greenkey[1].getint(), From noreply at buildbot.pypy.org Tue May 21 22:39:45 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 22:39:45 +0200 (CEST) Subject: [pypy-commit] pypy on-abort-resops: update this guy too Message-ID: <20130521203945.6A2F31C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: on-abort-resops Changeset: r64402:d825c920b6e1 Date: 2013-05-21 13:39 -0700 http://bitbucket.org/pypy/pypy/changeset/d825c920b6e1/ Log: update this guy too diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -926,7 +926,7 @@ of JIT running like JIT loops compiled, aborts etc. An instance of this class will be available as policy.jithookiface. """ - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): """ A hook called each time a loop is aborted with jitdriver and greenkey where it started, reason is a string why it got aborted """ From noreply at buildbot.pypy.org Tue May 21 22:51:52 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 22:51:52 +0200 (CEST) Subject: [pypy-commit] pypy on-abort-resops: trnaslation fix Message-ID: <20130521205152.EB7C91C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: on-abort-resops Changeset: r64403:e16fef663d9a Date: 2013-05-21 13:51 -0700 http://bitbucket.org/pypy/pypy/changeset/e16fef663d9a/ Log: trnaslation fix diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1877,7 +1877,7 @@ jd_sd.jitdriver, greenkey, jd_sd.warmstate.get_location_str(greenkey), - self.staticdata.logger_ops, + self.staticdata.logger_ops._make_log_operations(), self.history.operations) self.staticdata.stats.aborted() From noreply at buildbot.pypy.org Tue May 21 22:56:21 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 21 May 2013 22:56:21 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: List MacPorts. I didn't find which page to link to. Message-ID: <20130521205621.2975A1C1361@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r440:e033018afe0c Date: 2013-05-21 22:56 +0200 http://bitbucket.org/pypy/pypy.org/changeset/e033018afe0c/ Log: List MacPorts. I didn't find which page to link to. diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -82,7 +82,7 @@ them
    unless you're ready to hack your system by adding symlinks to the libraries it tries to open. In general, we recommend either building from source or downloading your PyPy from your release vendor. Ubuntu (PPA), -Debian, Homebrew, +Debian, Homebrew, MacPorts, Fedora, Gentoo and Arch are known to package PyPy, with various degrees of being up-to-date. If you feel like trying a more statically linked binary (which we do not recommend using diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -57,7 +57,7 @@ them** unless you're ready to hack your system by adding symlinks to the libraries it tries to open. In general, we recommend either building from source or downloading your PyPy from your release vendor. `Ubuntu`_ (`PPA`_), -`Debian`_, `Homebrew`_, +`Debian`_, `Homebrew`_, MacPorts, `Fedora`_, `Gentoo`_ and `Arch`_ are known to package PyPy, with various degrees of being up-to-date. If you feel like trying a more statically linked binary (which we do not recommend using From noreply at buildbot.pypy.org Tue May 21 23:14:30 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 23:14:30 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove bootstrapping magic and see what happens. Message-ID: <20130521211430.248711C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64404:61e272188959 Date: 2013-05-21 16:22 +0200 http://bitbucket.org/pypy/pypy/changeset/61e272188959/ Log: Remove bootstrapping magic and see what happens. diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -171,13 +171,7 @@ start += step return space.newtuple(subitems) - # getindex_w should get a second argument space.w_IndexError, - # but that doesn't exist the first time this is called. - try: - w_IndexError = space.w_IndexError - except AttributeError: - w_IndexError = None - index = space.getindex_w(w_index, w_IndexError, "tuple index") + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") try: return self.wrappeditems[index] except IndexError: From noreply at buildbot.pypy.org Tue May 21 23:14:31 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 21 May 2013 23:14:31 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: IN-PROGRESS: Remove SMMs on smalltuple, too. Message-ID: <20130521211431.C98891C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64405:fe9e1fed1393 Date: 2013-05-21 23:12 +0200 http://bitbucket.org/pypy/pypy/changeset/fe9e1fed1393/ Log: IN-PROGRESS: Remove SMMs on smalltuple, too. diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -190,10 +190,6 @@ (unicodeobject.W_UnicodeObject, strbufobject.delegate_buf2unicode) ] - if config.objspace.std.withsmalltuple: - from pypy.objspace.std import smalltupleobject - self.typeorder[smalltupleobject.W_SmallTupleObject] += [ - (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] if config.objspace.std.withspecialisedtuple: from pypy.objspace.std import specialisedtupleobject diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py --- a/pypy/objspace/std/smalltupleobject.py +++ b/pypy/objspace/std/smalltupleobject.py @@ -6,36 +6,17 @@ from rpython.rlib.rarithmetic import intmask from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std import slicetype +from pypy.objspace.std.util import negate from pypy.interpreter import gateway from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject + class W_SmallTupleObject(W_AbstractTupleObject): from pypy.objspace.std.tupletype import tuple_typedef as typedef - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] - return tuple(items) def make_specialized_class(n): iter_n = unrolling_iterable(range(n)) @@ -58,30 +39,40 @@ def length(self): return n - def getitem(self, index): + def descr_len(self): + return space.wrap(n) + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + return self._getslice(space, w_index) + index = space.getindex_w(w_index, space.w_IndexError, + "tuple index") + if index < 0: + index += self.length() + return self.getitem(space, index) + + def getitem(self, space, index): for i in iter_n: if index == i: return getattr(self,'w_value%s' % i) - raise IndexError + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) - def setitem(self, index, w_item): - for i in iter_n: - if index == i: - setattr(self, 'w_value%s' % i, w_item) - return - raise IndexError - - def eq(self, space, w_other): + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented if n != w_other.length(): return space.w_False for i in iter_n: item1 = getattr(self,'w_value%s' % i) - item2 = w_other.getitem(i) + item2 = w_other.getitem(space, i) if not space.eq_w(item1, item2): return space.w_False return space.w_True - def hash(self, space): + descr_ne = negate(descr_eq) + + def descr_hash(self, space): mult = 1000003 x = 0x345678 z = n @@ -106,56 +97,3 @@ W_SmallTupleObject8 = make_specialized_class(8) registerimplementation(W_SmallTupleObject) - -def delegate_SmallTuple2Tuple(space, w_small): - return W_TupleObject(w_small.tolist()) - -def len__SmallTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SmallTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SmallTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_smalltuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SmallTuple_ANY(space, w_tuple, w_times): - return mul_smalltuple_times(space, w_tuple, w_times) - -def mul__ANY_SmallTuple(space, w_times, w_tuple): - return mul_smalltuple_times(space, w_tuple, w_times) - -def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def hash__SmallTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -12,51 +12,53 @@ from rpython.rlib import jit from rpython.tool.sourcetools import func_with_new_name from pypy.interpreter import gateway +from pypy.interpreter.gateway import interp2app, interpindirect2app + UNROLL_CUTOFF = 10 + +def tuple_unroll_condition(self, space, other): + return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF)) + + class W_AbstractTupleObject(W_Object): __slots__ = () + def __repr__(w_self): + """representation for debugging purposes""" + reprlist = [repr(w_item) for w_item in w_self.tolist()] + return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) + + def unwrap(w_tuple, space): + items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] + return tuple(items) + def tolist(self): - "Returns the items, as a fixed-size list." + """Returns the items, as a fixed-size list.""" raise NotImplementedError def getitems_copy(self): - "Returns a copy of the items, as a resizable list." + """Returns a copy of the items, as a resizable list.""" raise NotImplementedError + def length(self): + raise NotImplementedError -def tuple_unroll_condition(space, self, w_other): - return jit.loop_unrolling_heuristic(self, len(self.wrappeditems), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_other, len(w_other.wrappeditems), UNROLL_CUTOFF) + def getitem(self, space, item): + raise NotImplementedError + def descr_len(self, space): + result = self.length() + return wrapint(space, result) -class W_TupleObject(W_AbstractTupleObject): - _immutable_fields_ = ['wrappeditems[*]'] - - def __init__(w_self, wrappeditems): - make_sure_not_resized(wrappeditems) - w_self.wrappeditems = wrappeditems # a list of wrapped values - - def __repr__(w_self): - """ representation for debugging purposes """ - reprlist = [repr(w_item) for w_item in w_self.wrappeditems] - return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] - return tuple(items) - - def tolist(self): - return self.wrappeditems - - def getitems_copy(self): - return self.wrappeditems[:] # returns a resizable list + def descr_iter(self, space): + from pypy.objspace.std import iterobject + return iterobject.W_FastTupleIterObject(self, self.tolist()) @staticmethod def descr_new(space, w_tupletype, w_sequence=None): - from pypy.objspace.std.tupleobject import W_TupleObject if w_sequence is None: tuple_w = [] elif (space.is_w(w_tupletype, space.w_tuple) and @@ -69,24 +71,187 @@ return w_obj def descr_repr(self, space): - items = self.wrappeditems + items = self.tolist() # XXX this is quite innefficient, still better than calling # it via applevel if len(items) == 1: return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") - return space.wrap("(" + - (", ".join([space.str_w(space.repr(item)) for item in items])) - + ")") + tmp = ", ".join([space.str_w(space.repr(item)) for item in items]) + return space.wrap("(" + tmp + ")") + + def descr_hash(self, space): + raise NotImplementedError + + def descr_eq(self, space, w_other): + raise NotImplementedError + + def descr_ne(self, space, w_other): + raise NotImplementedError + + def _make_tuple_comparison(name): + import operator + op = getattr(operator, name) + + def compare_tuples(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return _compare_tuples(self, space, w_other) + + @jit.look_inside_iff(tuple_unroll_condition) + def _compare_tuples(self, space, w_other): + items1 = self.tolist() + items2 = w_other.tolist() + ncmp = min(len(items1), len(items2)) + # Search for the first index where items are different + for p in range(ncmp): + if not space.eq_w(items1[p], items2[p]): + return getattr(space, name)(items1[p], items2[p]) + # No more items to compare -- compare sizes + return space.newbool(op(len(items1), len(items2))) + + return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') + + descr_lt = _make_tuple_comparison('lt') + descr_le = _make_tuple_comparison('le') + descr_gt = _make_tuple_comparison('gt') + descr_ge = _make_tuple_comparison('ge') + + @jit.look_inside_iff(lambda self, space, w_obj: + jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF)) + def descr_contains(self, space, w_obj): + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + return space.w_True + return space.w_False + + def descr_add(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + items1 = self.tolist() + items2 = w_other.tolist() + return space.newtuple(items1 + items2) + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + if times == 1 and space.type(self) == space.w_tuple: + return self + items = self.tolist() + return space.newtuple(items * times) + + def descr_getitem(self, space, w_other): + raise NotImplementedError + + def _getslice(self, space, w_index): + items = self.tolist() + length = len(items) + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = items[start] + start += step + return space.newtuple(subitems) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + return space.newtuple(self.tolist()[start:stop]) + + def descr_getnewargs(self, space): + return space.newtuple([space.newtuple(self.tolist())]) + + def descr_count(self, space, w_obj): + """count(obj) -> number of times obj appears in the tuple""" + count = 0 + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + count += 1 + return space.wrap(count) + + @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), + w_stop=gateway.WrappedDefault(sys.maxint)) + def descr_index(self, space, w_obj, w_start, w_stop): + """index(obj, [start, [stop]]) -> first index that obj appears in the + tuple + """ + length = self.length() + start, stop = slicetype.unwrap_start_stop(space, length, w_start, + w_stop) + for i in range(start, min(stop, length)): + w_item = self.tolist()[i] + if space.eq_w(w_item, w_obj): + return space.wrap(i) + raise OperationError(space.w_ValueError, + space.wrap("tuple.index(x): x not in tuple")) + + +W_AbstractTupleObject.typedef = StdTypeDef("tuple", + __doc__ = '''tuple() -> an empty tuple +tuple(sequence) -> tuple initialized from sequence's items + +If the argument is a tuple, the return value is the same object.''', + __new__ = interp2app(W_AbstractTupleObject.descr_new), + __repr__ = interp2app(W_AbstractTupleObject.descr_repr), + __hash__ = interpindirect2app(W_AbstractTupleObject.descr_hash), + + __eq__ = interpindirect2app(W_AbstractTupleObject.descr_eq), + __ne__ = interpindirect2app(W_AbstractTupleObject.descr_ne), + __lt__ = interp2app(W_AbstractTupleObject.descr_lt), + __le__ = interp2app(W_AbstractTupleObject.descr_le), + __gt__ = interp2app(W_AbstractTupleObject.descr_gt), + __ge__ = interp2app(W_AbstractTupleObject.descr_ge), + + __len__ = interp2app(W_AbstractTupleObject.descr_len), + __iter__ = interp2app(W_AbstractTupleObject.descr_iter), + __contains__ = interp2app(W_AbstractTupleObject.descr_contains), + + __add__ = interp2app(W_AbstractTupleObject.descr_add), + __mul__ = interp2app(W_AbstractTupleObject.descr_mul), + __rmul__ = interp2app(W_AbstractTupleObject.descr_mul), + + __getitem__ = interpindirect2app(W_AbstractTupleObject.descr_getitem), + __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice), + + __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs), + count = interp2app(W_AbstractTupleObject.descr_count), + index = interp2app(W_AbstractTupleObject.descr_index) +) + + + +class W_TupleObject(W_AbstractTupleObject): + _immutable_fields_ = ['wrappeditems[*]'] + + def __init__(w_self, wrappeditems): + make_sure_not_resized(wrappeditems) + w_self.wrappeditems = wrappeditems # a list of wrapped values + + def tolist(self): + return self.wrappeditems + + def getitems_copy(self): + return self.wrappeditems[:] # returns a resizable list + + def length(self): + return len(self.wrappeditems) def descr_hash(self, space): return space.wrap(hash_tuple(space, self.wrappeditems)) + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) + @jit.look_inside_iff(tuple_unroll_condition) - def descr_eq(self, space, w_other): - if not isinstance(w_other, W_TupleObject): - return space.w_NotImplemented + def _descr_eq(self, space, w_other): items1 = self.wrappeditems - items2 = w_other.wrappeditems + items2 = w_other.tolist() lgt1 = len(items1) lgt2 = len(items2) if lgt1 != lgt2: @@ -100,77 +265,9 @@ descr_ne = negate(descr_eq) - def _make_tuple_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(tuple_unroll_condition) - def compare_tuples(self, space, w_other): - if not isinstance(w_other, W_TupleObject): - return space.w_NotImplemented - items1 = self.wrappeditems - items2 = w_other.wrappeditems - ncmp = min(len(items1), len(items2)) - # Search for the first index where items are different - for p in range(ncmp): - if not space.eq_w(items1[p], items2[p]): - return getattr(space, name)(items1[p], items2[p]) - # No more items to compare -- compare sizes - return space.newbool(op(len(items1), len(items2))) - return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') - - descr_lt = _make_tuple_comparison('lt') - descr_le = _make_tuple_comparison('le') - descr_gt = _make_tuple_comparison('gt') - descr_ge = _make_tuple_comparison('ge') - - def descr_len(self, space): - result = len(self.wrappeditems) - return wrapint(space, result) - - def descr_iter(self, space): - from pypy.objspace.std import iterobject - return iterobject.W_FastTupleIterObject(self, self.wrappeditems) - - @jit.look_inside_iff(lambda self, space, w_obj: - jit.loop_unrolling_heuristic(self, len(self.wrappeditems), UNROLL_CUTOFF)) - def descr_contains(self, space, w_obj): - for w_item in self.wrappeditems: - if space.eq_w(w_item, w_obj): - return space.w_True - return space.w_False - - def descr_add(self, space, w_other): - if not isinstance(w_other, W_TupleObject): - return space.w_NotImplemented - items1 = self.wrappeditems - items2 = w_other.wrappeditems - return space.newtuple(items1 + items2) - - def descr_mul(self, space, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - return space.w_NotImplemented - raise - if times == 1 and space.type(self) == space.w_tuple: - return self - items = self.wrappeditems - return space.newtuple(items * times) - def descr_getitem(self, space, w_index): if isinstance(w_index, W_SliceObject): - items = self.wrappeditems - length = len(items) - start, stop, step, slicelength = w_index.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = items[start] - start += step - return space.newtuple(subitems) - + return self._getslice(space, w_index) index = space.getindex_w(w_index, space.w_IndexError, "tuple index") try: return self.wrappeditems[index] @@ -178,68 +275,12 @@ raise OperationError(space.w_IndexError, space.wrap("tuple index out of range")) - def descr_getslice(self, space, w_start, w_stop): - length = len(self.wrappeditems) - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return space.newtuple(self.wrappeditems[start:stop]) - - def descr_getnewargs(self, space): - return space.newtuple([space.newtuple(self.wrappeditems)]) - - def descr_count(self, space, w_obj): - """count(obj) -> number of times obj appears in the tuple""" - count = 0 - for w_item in self.wrappeditems: - if space.eq_w(w_item, w_obj): - count += 1 - return space.wrap(count) - - @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), - w_stop=gateway.WrappedDefault(sys.maxint)) - def descr_index(self, space, w_obj, w_start, w_stop): - """index(obj, [start, [stop]]) -> first index that obj appears in the - tuple - """ - length = len(self.wrappeditems) - start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) - for i in range(start, min(stop, length)): - w_item = self.wrappeditems[i] - if space.eq_w(w_item, w_obj): - return space.wrap(i) - raise OperationError(space.w_ValueError, - space.wrap("tuple.index(x): x not in tuple")) - -W_TupleObject.typedef = StdTypeDef("tuple", - __doc__ = '''tuple() -> an empty tuple -tuple(sequence) -> tuple initialized from sequence's items - -If the argument is a tuple, the return value is the same object.''', - __new__ = gateway.interp2app(W_TupleObject.descr_new), - __repr__ = gateway.interp2app(W_TupleObject.descr_repr), - __hash__ = gateway.interp2app(W_TupleObject.descr_hash), - - __eq__ = gateway.interp2app(W_TupleObject.descr_eq), - __ne__ = gateway.interp2app(W_TupleObject.descr_ne), - __lt__ = gateway.interp2app(W_TupleObject.descr_lt), - __le__ = gateway.interp2app(W_TupleObject.descr_le), - __gt__ = gateway.interp2app(W_TupleObject.descr_gt), - __ge__ = gateway.interp2app(W_TupleObject.descr_ge), - - __len__ = gateway.interp2app(W_TupleObject.descr_len), - __iter__ = gateway.interp2app(W_TupleObject.descr_iter), - __contains__ = gateway.interp2app(W_TupleObject.descr_contains), - - __add__ = gateway.interp2app(W_TupleObject.descr_add), - __mul__ = gateway.interp2app(W_TupleObject.descr_mul), - __rmul__ = gateway.interp2app(W_TupleObject.descr_mul), - - __getitem__ = gateway.interp2app(W_TupleObject.descr_getitem), - __getslice__ = gateway.interp2app(W_TupleObject.descr_getslice), - - __getnewargs__ = gateway.interp2app(W_TupleObject.descr_getnewargs), - count = gateway.interp2app(W_TupleObject.descr_count), - index = gateway.interp2app(W_TupleObject.descr_index) -) + def getitem(self, space, index): + try: + return self.wrappeditems[index] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) registerimplementation(W_TupleObject) From noreply at buildbot.pypy.org Tue May 21 23:17:08 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 23:17:08 +0200 (CEST) Subject: [pypy-commit] pypy on-abort-resops: Close to be merged branch Message-ID: <20130521211708.169251C1361@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: on-abort-resops Changeset: r64406:3d7aa9fa1202 Date: 2013-05-21 14:16 -0700 http://bitbucket.org/pypy/pypy/changeset/3d7aa9fa1202/ Log: Close to be merged branch From noreply at buildbot.pypy.org Tue May 21 23:17:09 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 23:17:09 +0200 (CEST) Subject: [pypy-commit] pypy default: Merged on-abort-resops. Message-ID: <20130521211709.9FBDA1C1361@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64407:e0ffe539cd4e Date: 2013-05-21 14:16 -0700 http://bitbucket.org/pypy/pypy/changeset/e0ffe539cd4e/ Log: Merged on-abort-resops. Makes the on_abort callback include the list of operations. diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1876,7 +1876,9 @@ self.staticdata.warmrunnerdesc.hooks.on_abort(reason, jd_sd.jitdriver, greenkey, - jd_sd.warmstate.get_location_str(greenkey)) + jd_sd.warmstate.get_location_str(greenkey), + self.staticdata.logger_ops._make_log_operations(), + self.history.operations) self.staticdata.stats.aborted() def blackhole_if_trace_too_long(self): diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -7,18 +7,20 @@ from rpython.rtyper.annlowlevel import hlstr from rpython.jit.metainterp.jitprof import Profiler + class JitHookInterfaceTests(object): # !!!note!!! - don't subclass this from the backend. Subclass the LL # class later instead def test_abort_quasi_immut(self): reasons = [] - + class MyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): assert jitdriver is myjitdriver assert len(greenkey) == 1 reasons.append(reason) assert greenkey_repr == 'blah' + assert len(operations) > 1 iface = MyJitIface() @@ -27,8 +29,10 @@ class Foo: _immutable_fields_ = ['a?'] + def __init__(self, a): self.a = a + def f(a, x): foo = Foo(a) total = 0 @@ -47,7 +51,7 @@ def test_on_compile(self): called = [] - + class MyJitIface(JitHookInterface): def after_compile(self, di): called.append(("compile", di.greenkey[1].getint(), diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -926,7 +926,7 @@ of JIT running like JIT loops compiled, aborts etc. An instance of this class will be available as policy.jithookiface. """ - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): """ A hook called each time a loop is aborted with jitdriver and greenkey where it started, reason is a string why it got aborted """ diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -1,11 +1,10 @@ +from rpython.annotator import model as annmodel +from rpython.rlib.objectmodel import specialize +from rpython.rtyper.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance, llstr) +from rpython.rtyper.extregistry import ExtRegistryEntry +from rpython.rtyper.lltypesystem import llmemory, lltype, rclass -from rpython.rtyper.extregistry import ExtRegistryEntry -from rpython.annotator import model as annmodel -from rpython.rtyper.lltypesystem import llmemory, lltype -from rpython.rtyper.lltypesystem import rclass -from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr,\ - cast_base_ptr_to_instance, llstr -from rpython.rlib.objectmodel import specialize def register_helper(s_result): def wrapper(helper): From noreply at buildbot.pypy.org Tue May 21 23:18:52 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 21 May 2013 23:18:52 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged default in Message-ID: <20130521211852.9C8D41C1361@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64408:2c69cbcad3c1 Date: 2013-05-21 14:17 -0700 http://bitbucket.org/pypy/pypy/changeset/2c69cbcad3c1/ Log: merged default in diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,12 +124,14 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - os_thread.setup_threads(space) - rffi.aroundstate.before() + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - rthread.gc_thread_start() + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1876,7 +1876,9 @@ self.staticdata.warmrunnerdesc.hooks.on_abort(reason, jd_sd.jitdriver, greenkey, - jd_sd.warmstate.get_location_str(greenkey)) + jd_sd.warmstate.get_location_str(greenkey), + self.staticdata.logger_ops._make_log_operations(), + self.history.operations) self.staticdata.stats.aborted() def blackhole_if_trace_too_long(self): diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -7,18 +7,20 @@ from rpython.rtyper.annlowlevel import hlstr from rpython.jit.metainterp.jitprof import Profiler + class JitHookInterfaceTests(object): # !!!note!!! - don't subclass this from the backend. Subclass the LL # class later instead def test_abort_quasi_immut(self): reasons = [] - + class MyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): assert jitdriver is myjitdriver assert len(greenkey) == 1 reasons.append(reason) assert greenkey_repr == 'blah' + assert len(operations) > 1 iface = MyJitIface() @@ -27,8 +29,10 @@ class Foo: _immutable_fields_ = ['a?'] + def __init__(self, a): self.a = a + def f(a, x): foo = Foo(a) total = 0 @@ -47,7 +51,7 @@ def test_on_compile(self): called = [] - + class MyJitIface(JitHookInterface): def after_compile(self, di): called.append(("compile", di.greenkey[1].getint(), diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -926,7 +926,7 @@ of JIT running like JIT loops compiled, aborts etc. An instance of this class will be available as policy.jithookiface. """ - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): """ A hook called each time a loop is aborted with jitdriver and greenkey where it started, reason is a string why it got aborted """ diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -1,11 +1,10 @@ +from rpython.annotator import model as annmodel +from rpython.rlib.objectmodel import specialize +from rpython.rtyper.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance, llstr) +from rpython.rtyper.extregistry import ExtRegistryEntry +from rpython.rtyper.lltypesystem import llmemory, lltype, rclass -from rpython.rtyper.extregistry import ExtRegistryEntry -from rpython.annotator import model as annmodel -from rpython.rtyper.lltypesystem import llmemory, lltype -from rpython.rtyper.lltypesystem import rclass -from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr,\ - cast_base_ptr_to_instance, llstr -from rpython.rlib.objectmodel import specialize def register_helper(s_result): def wrapper(helper): From noreply at buildbot.pypy.org Wed May 22 00:49:07 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 00:49:07 +0200 (CEST) Subject: [pypy-commit] pypy default: Don't generate guard_class for an exception when its type is known Message-ID: <20130521224907.56DBA1C1559@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64409:d64dc3f388ad Date: 2013-05-21 15:48 -0700 http://bitbucket.org/pypy/pypy/changeset/d64dc3f388ad/ Log: Don't generate guard_class for an exception when its type is known diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1053,9 +1053,10 @@ @arguments("box", "orgpc") def opimpl_raise(self, exc_value_box, orgpc): # xxx hack - clsbox = self.cls_of_box(exc_value_box) - self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], - resumepc=orgpc) + if not self.metainterp.heapcache.is_class_known(exc_value_box): + clsbox = self.cls_of_box(exc_value_box) + self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], + resumepc=orgpc) self.metainterp.class_of_last_exc_is_const = True self.metainterp.last_exc_value_box = exc_value_box self.metainterp.popframe() diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -5,8 +5,6 @@ from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rstring import StringBuilder -import py - class TestLLtype(LLJitMixin): def test_dont_record_repeated_guard_class(self): @@ -628,3 +626,22 @@ res = self.interp_operations(fn, [0]) assert res == 1 self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0) + + def test_raise_known_class_no_guard_class(self): + def raise_exc(cls): + raise cls + + def fn(n): + if n: + cls = ValueError + else: + cls = TypeError + try: + raise_exc(cls) + except ValueError: + return -1 + return n + + res = self.interp_operations(fn, [1]) + assert res == -1 + self.check_operations_history(guard_class=0) From noreply at buildbot.pypy.org Wed May 22 00:50:10 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 00:50:10 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged default in Message-ID: <20130521225010.CFE661C1361@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64410:d588636b04d9 Date: 2013-05-21 15:49 -0700 http://bitbucket.org/pypy/pypy/changeset/d588636b04d9/ Log: merged default in diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1053,9 +1053,10 @@ @arguments("box", "orgpc") def opimpl_raise(self, exc_value_box, orgpc): # xxx hack - clsbox = self.cls_of_box(exc_value_box) - self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], - resumepc=orgpc) + if not self.metainterp.heapcache.is_class_known(exc_value_box): + clsbox = self.cls_of_box(exc_value_box) + self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], + resumepc=orgpc) self.metainterp.class_of_last_exc_is_const = True self.metainterp.last_exc_value_box = exc_value_box self.metainterp.popframe() diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -5,8 +5,6 @@ from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rstring import StringBuilder -import py - class TestLLtype(LLJitMixin): def test_dont_record_repeated_guard_class(self): @@ -628,3 +626,22 @@ res = self.interp_operations(fn, [0]) assert res == 1 self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0) + + def test_raise_known_class_no_guard_class(self): + def raise_exc(cls): + raise cls + + def fn(n): + if n: + cls = ValueError + else: + cls = TypeError + try: + raise_exc(cls) + except ValueError: + return -1 + return n + + res = self.interp_operations(fn, [1]) + assert res == -1 + self.check_operations_history(guard_class=0) From noreply at buildbot.pypy.org Wed May 22 02:25:40 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 02:25:40 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: Mark this as immutable. Message-ID: <20130522002540.050A31C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64411:d95d58323a97 Date: 2013-05-21 17:23 -0700 http://bitbucket.org/pypy/pypy/changeset/d95d58323a97/ Log: Mark this as immutable. diff --git a/rpython/tool/error.py b/rpython/tool/error.py --- a/rpython/tool/error.py +++ b/rpython/tool/error.py @@ -2,11 +2,15 @@ """ error handling features, just a way of displaying errors """ -from rpython.tool.ansi_print import ansi_log -from rpython.flowspace.model import Variable import sys import py + +from rpython.flowspace.model import Variable +from rpython.rlib import jit +from rpython.tool.ansi_print import ansi_log + + log = py.log.Producer("error") py.log.setconsumer("error", ansi_log) @@ -14,7 +18,8 @@ SHOW_ANNOTATIONS = True SHOW_DEFAULT_LINES_OF_CODE = 0 -def source_lines1(graph, block, operindex=None, offset=None, long=False, \ + +def source_lines1(graph, block, operindex=None, offset=None, long=False, show_lines_of_code=SHOW_DEFAULT_LINES_OF_CODE): if block is not None: if block is graph.returnblock: @@ -32,23 +37,24 @@ else: if block is None or not block.operations: return [] + def toline(operindex): return offset2lineno(graph.func.func_code, block.operations[operindex].offset) if operindex is None: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) if not long: return ['?'] here = None else: operline = toline(operindex) if long: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) here = operline else: linerange = (operline, operline) here = None lines = ["Happened at file %s line %d" % (graph.filename, here or linerange[0]), ""] - for n in range(max(0, linerange[0]-show_lines_of_code), \ + for n in range(max(0, linerange[0]-show_lines_of_code), min(linerange[1]+1+show_lines_of_code, len(graph_lines)+graph.startline)): if n == here: prefix = '==> ' @@ -136,6 +142,7 @@ from rpython.translator.tool.pdbplus import PdbPlusShow from rpython.translator.driver import log t = drv.translator + class options: huge = 100 @@ -161,6 +168,7 @@ pdb_plus_show.start(tb) + at jit.elidable def offset2lineno(c, stopat): tab = c.co_lnotab line = c.co_firstlineno @@ -170,4 +178,4 @@ if addr > stopat: break line = line + ord(tab[i+1]) - return line \ No newline at end of file + return line From noreply at buildbot.pypy.org Wed May 22 02:26:56 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 02:26:56 +0200 (CEST) Subject: [pypy-commit] pypy default: Mark this as immutable. Message-ID: <20130522002656.7E4EC1C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64412:88fcf46365c8 Date: 2013-05-21 17:23 -0700 http://bitbucket.org/pypy/pypy/changeset/88fcf46365c8/ Log: Mark this as immutable. diff --git a/rpython/tool/error.py b/rpython/tool/error.py --- a/rpython/tool/error.py +++ b/rpython/tool/error.py @@ -2,11 +2,15 @@ """ error handling features, just a way of displaying errors """ -from rpython.tool.ansi_print import ansi_log -from rpython.flowspace.model import Variable import sys import py + +from rpython.flowspace.model import Variable +from rpython.rlib import jit +from rpython.tool.ansi_print import ansi_log + + log = py.log.Producer("error") py.log.setconsumer("error", ansi_log) @@ -14,7 +18,8 @@ SHOW_ANNOTATIONS = True SHOW_DEFAULT_LINES_OF_CODE = 0 -def source_lines1(graph, block, operindex=None, offset=None, long=False, \ + +def source_lines1(graph, block, operindex=None, offset=None, long=False, show_lines_of_code=SHOW_DEFAULT_LINES_OF_CODE): if block is not None: if block is graph.returnblock: @@ -32,23 +37,24 @@ else: if block is None or not block.operations: return [] + def toline(operindex): return offset2lineno(graph.func.func_code, block.operations[operindex].offset) if operindex is None: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) if not long: return ['?'] here = None else: operline = toline(operindex) if long: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) here = operline else: linerange = (operline, operline) here = None lines = ["Happened at file %s line %d" % (graph.filename, here or linerange[0]), ""] - for n in range(max(0, linerange[0]-show_lines_of_code), \ + for n in range(max(0, linerange[0]-show_lines_of_code), min(linerange[1]+1+show_lines_of_code, len(graph_lines)+graph.startline)): if n == here: prefix = '==> ' @@ -136,6 +142,7 @@ from rpython.translator.tool.pdbplus import PdbPlusShow from rpython.translator.driver import log t = drv.translator + class options: huge = 100 @@ -161,6 +168,7 @@ pdb_plus_show.start(tb) + at jit.elidable def offset2lineno(c, stopat): tab = c.co_lnotab line = c.co_firstlineno @@ -170,4 +178,4 @@ if addr > stopat: break line = line + ord(tab[i+1]) - return line \ No newline at end of file + return line From noreply at buildbot.pypy.org Wed May 22 03:12:09 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 03:12:09 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove tuple from multi-method table. Message-ID: <20130522011209.A66DE1C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64413:0fc0f446a6f7 Date: 2013-05-22 00:45 +0200 http://bitbucket.org/pypy/pypy/changeset/0fc0f446a6f7/ Log: Remove tuple from multi-method table. diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -15,8 +15,6 @@ _registered_implementations.add(implcls) option_to_typename = { - "withspecialisedtuple" : ["specialisedtupleobject.W_SpecialisedTupleObject"], - "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], "withstrbuf" : ["strbufobject.W_StringBufferObject"], } @@ -38,7 +36,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -79,6 +76,7 @@ # not-multimethod based types + self.pythontypes.append(tupleobject.W_TupleObject.typedef) self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) @@ -90,7 +88,6 @@ boolobject.W_BoolObject: [], intobject.W_IntObject: [], floatobject.W_FloatObject: [], - tupleobject.W_TupleObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -109,7 +106,6 @@ self.imported_but_not_registered = { stringobject.W_StringObject: True, - tupleobject.W_TupleObject: True, } for option, value in config.objspace.std: if option.startswith("with") and option in option_to_typename: @@ -191,10 +187,11 @@ strbufobject.delegate_buf2unicode) ] - if config.objspace.std.withspecialisedtuple: - from pypy.objspace.std import specialisedtupleobject - self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ - (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] + # XXX fix specialisedtuple + #if config.objspace.std.withspecialisedtuple: + # from pypy.objspace.std import specialisedtupleobject + # self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ + # (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] # put W_Root everywhere self.typeorder[W_Root] = [] diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py --- a/pypy/objspace/std/smalltupleobject.py +++ b/pypy/objspace/std/smalltupleobject.py @@ -1,26 +1,15 @@ from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.sliceobject import W_SliceObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject +from pypy.objspace.std.util import negate from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.objspace.std.util import negate -from pypy.interpreter import gateway -from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject - - -class W_SmallTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef def make_specialized_class(n): iter_n = unrolling_iterable(range(n)) - class cls(W_SmallTupleObject): + class cls(W_AbstractTupleObject): def __init__(self, values): assert len(values) == n @@ -39,9 +28,6 @@ def length(self): return n - def descr_len(self): - return space.wrap(n) - def descr_getitem(self, space, w_index): if isinstance(w_index, W_SliceObject): return self._getslice(space, w_index) @@ -95,5 +81,3 @@ W_SmallTupleObject6 = make_specialized_class(6) W_SmallTupleObject7 = make_specialized_class(7) W_SmallTupleObject8 = make_specialized_class(8) - -registerimplementation(W_SmallTupleObject) diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ b/pypy/objspace/std/test/test_smalltupleobject.py @@ -1,5 +1,5 @@ from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 from pypy.interpreter.error import OperationError from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject from pypy.tool.pytest.objspace import gettestobjspace @@ -55,12 +55,16 @@ c = (1,3,2) assert hash(a) != hash(c) + def test_foo(self): + assert tuple([0]) + (1,) == (0, 1) + assert not tuple([0]) + (1,) == (0,) + class TestW_SmallTupleObject(): spaceconfig = {"objspace.std.withsmalltuple": True} def test_issmalltupleobject(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - assert isinstance(w_tuple, W_SmallTupleObject) + assert isinstance(w_tuple, W_SmallTupleObject2) def test_hash_agains_normal_tuple(self): normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) @@ -69,7 +73,7 @@ smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - assert isinstance(w_smalltuple, W_SmallTupleObject) + assert isinstance(w_smalltuple, W_SmallTupleObject2) assert isinstance(w_tuple, W_TupleObject) assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,18 +1,17 @@ import sys +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate +from rpython.rlib import jit +from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.objspace.std.util import negate -from pypy.objspace.std.stdtypedef import StdTypeDef -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib import jit from rpython.tool.sourcetools import func_with_new_name -from pypy.interpreter import gateway -from pypy.interpreter.gateway import interp2app, interpindirect2app UNROLL_CUTOFF = 10 @@ -23,7 +22,7 @@ jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF)) -class W_AbstractTupleObject(W_Object): +class W_AbstractTupleObject(W_Root): __slots__ = () def __repr__(w_self): @@ -282,8 +281,6 @@ raise OperationError(space.w_IndexError, space.wrap("tuple index out of range")) -registerimplementation(W_TupleObject) - @jit.look_inside_iff(lambda space, wrappeditems: jit.loop_unrolling_heuristic(wrappeditems, len(wrappeditems), UNROLL_CUTOFF)) diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py --- a/pypy/objspace/std/tupletype.py +++ b/pypy/objspace/std/tupletype.py @@ -3,12 +3,13 @@ def wraptuple(space, list_w): from pypy.objspace.std.tupleobject import W_TupleObject - if space.config.objspace.std.withspecialisedtuple: - from specialisedtupleobject import makespecialisedtuple, NotSpecialised - try: - return makespecialisedtuple(space, list_w) - except NotSpecialised: - pass + # XXX fix specialisedtuple + #if space.config.objspace.std.withspecialisedtuple: + # from specialisedtupleobject import makespecialisedtuple, NotSpecialised + # try: + # return makespecialisedtuple(space, list_w) + # except NotSpecialised: + # pass if space.config.objspace.std.withsmalltuple: from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 From noreply at buildbot.pypy.org Wed May 22 03:12:11 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 03:12:11 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove commented out code in specialisedtupleobject.py. Message-ID: <20130522011211.201401C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64414:7288d7239d8c Date: 2013-05-22 01:28 +0200 http://bitbucket.org/pypy/pypy/changeset/7288d7239d8c/ Log: Remove commented out code in specialisedtupleobject.py. diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -22,9 +22,6 @@ reprlist = [repr(item) for item in self._to_unwrapped_list()] return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - def _to_unwrapped_list(self): "NOT_RPYTHON" raise NotImplementedError @@ -53,10 +50,10 @@ def make_specialised_class(typetuple): assert type(typetuple) == tuple - + nValues = len(typetuple) iter_n = unrolling_iterable(range(nValues)) - + class cls(W_SpecialisedTupleObject): def __init__(self, space, *values_w): self.space = space @@ -80,7 +77,7 @@ return nValues def tolist(self): - list_w = [None] * nValues + list_w = [None] * nValues for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -145,20 +142,6 @@ def ne(self, space, w_other): return space.newbool(not self._eq(w_other)) -## def _compare(self, compare_op, w_other): -## if not isinstance(w_other, cls): -## raise FailedToImplement -## ncmp = min(self.length(), w_other.length()) -## for i in iter_n: -## if typetuple[i] == Any:#like space.eq on wrapped or two params? -## raise FailedToImplement -## if ncmp > i: -## l_val = getattr(self, 'value%s' % i) -## r_val = getattr(w_other, 'value%s' % i) -## if l_val != r_val: -## return compare_op(l_val, r_val) -## return compare_op(self.length(), w_other.length()) - def getitem(self, index): for i in iter_n: if index == i: @@ -177,55 +160,22 @@ _specialisations = [] Cls_ii = make_specialised_class((int, int)) -#Cls_is = make_specialised_class((int, str)) -#Cls_io = make_specialised_class((int, object)) -#Cls_si = make_specialised_class((str, int)) -#Cls_ss = make_specialised_class((str, str)) -#Cls_so = make_specialised_class((str, object)) -#Cls_oi = make_specialised_class((object, int)) -#Cls_os = make_specialised_class((object, str)) Cls_oo = make_specialised_class((object, object)) Cls_ff = make_specialised_class((float, float)) -#Cls_ooo = make_specialised_class((object, object, object)) def makespecialisedtuple(space, list_w): if len(list_w) == 2: w_arg1, w_arg2 = list_w w_type1 = space.type(w_arg1) - #w_type2 = space.type(w_arg2) - # if w_type1 is space.w_int: w_type2 = space.type(w_arg2) if w_type2 is space.w_int: return Cls_ii(space, w_arg1, w_arg2) - #elif w_type2 is space.w_str: - # return Cls_is(space, w_arg1, w_arg2) - #else: - # return Cls_io(space, w_arg1, w_arg2) - # - #elif w_type1 is space.w_str: - # if w_type2 is space.w_int: - # return Cls_si(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_ss(space, w_arg1, w_arg2) - # else: - # return Cls_so(space, w_arg1, w_arg2) - # elif w_type1 is space.w_float: w_type2 = space.type(w_arg2) if w_type2 is space.w_float: return Cls_ff(space, w_arg1, w_arg2) - # - #else: - # if w_type2 is space.w_int: - # return Cls_oi(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_os(space, w_arg1, w_arg2) - # else: return Cls_oo(space, w_arg1, w_arg2) - # - #elif len(list_w) == 3: - # return Cls_ooo(space, list_w[0], list_w[1], list_w[2]) else: raise NotSpecialised @@ -284,20 +234,6 @@ def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): return w_tuple1.ne(space, w_tuple2) -##from operator import lt, le, ge, gt - -##def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(lt, w_tuple2)) - -##def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(le, w_tuple2)) - -##def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(ge, w_tuple2)) - -##def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(gt, w_tuple2)) - def hash__SpecialisedTuple(space, w_tuple): return w_tuple.hash(space) From noreply at buildbot.pypy.org Wed May 22 03:12:12 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 03:12:12 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: IN-PROGRESS: Make specialisedtupleobject work. Message-ID: <20130522011212.58FF01C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64415:8da13dda52f2 Date: 2013-05-22 03:03 +0200 http://bitbucket.org/pypy/pypy/changeset/8da13dda52f2/ Log: IN-PROGRESS: Make specialisedtupleobject work. diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -187,12 +187,6 @@ strbufobject.delegate_buf2unicode) ] - # XXX fix specialisedtuple - #if config.objspace.std.withspecialisedtuple: - # from pypy.objspace.std import specialisedtupleobject - # self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ - # (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] - # put W_Root everywhere self.typeorder[W_Root] = [] for type in self.typeorder: diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py --- a/pypy/objspace/std/smalltupleobject.py +++ b/pypy/objspace/std/smalltupleobject.py @@ -1,5 +1,4 @@ from pypy.interpreter.error import OperationError -from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.util import negate from rpython.rlib.rarithmetic import intmask @@ -28,16 +27,9 @@ def length(self): return n - def descr_getitem(self, space, w_index): - if isinstance(w_index, W_SliceObject): - return self._getslice(space, w_index) - index = space.getindex_w(w_index, space.w_IndexError, - "tuple index") + def getitem(self, space, index): if index < 0: - index += self.length() - return self.getitem(space, index) - - def getitem(self, space, index): + index += n for i in iter_n: if index == i: return getattr(self,'w_value%s' % i) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -1,52 +1,15 @@ from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.tupleobject import W_AbstractTupleObject -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.util import negate +from rpython.rlib.objectmodel import compute_hash from rpython.rlib.rarithmetic import intmask -from rpython.rlib.objectmodel import compute_hash from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name + class NotSpecialised(Exception): pass -class W_SpecialisedTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - __slots__ = [] - - def __repr__(self): - """ representation for debugging purposes """ - reprlist = [repr(item) for item in self._to_unwrapped_list()] - return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) - - def _to_unwrapped_list(self): - "NOT_RPYTHON" - raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(self, space): - return tuple(self._to_unwrapped_list()) - - def delegating(self): - pass # for tests only - def make_specialised_class(typetuple): assert type(typetuple) == tuple @@ -54,7 +17,7 @@ nValues = len(typetuple) iter_n = unrolling_iterable(range(nValues)) - class cls(W_SpecialisedTupleObject): + class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space assert len(values_w) == nValues @@ -88,17 +51,7 @@ # same source code, but builds and returns a resizable list getitems_copy = func_with_new_name(tolist, 'getitems_copy') - def _to_unwrapped_list(self): - "NOT_RPYTHON" - list_w = [None] * nValues - for i in iter_n: - value = getattr(self, 'value%s' % i) - if typetuple[i] == object: - value = self.space.unwrap(value) - list_w[i] = value - return list_w - - def hash(self, space): + def descr_hash(self, space): # XXX duplicate logic from tupleobject.py mult = 1000003 x = 0x345678 @@ -120,36 +73,35 @@ x += 97531 return space.wrap(intmask(x)) - def _eq(self, w_other): + def descr_eq(self, space, w_other): if not isinstance(w_other, cls): # if we are not comparing same types, give up - raise FailedToImplement + return space.w_NotImplemented for i in iter_n: myval = getattr(self, 'value%s' % i) otherval = getattr(w_other, 'value%s' % i) if typetuple[i] == object: if not self.space.eq_w(myval, otherval): - return False + return space.w_False else: if myval != otherval: - return False + return space.w_False else: - return True + return space.w_True - def eq(self, space, w_other): - return space.newbool(self._eq(w_other)) + descr_ne = negate(descr_eq) - def ne(self, space, w_other): - return space.newbool(not self._eq(w_other)) - - def getitem(self, index): + def getitem(self, space, index): + if index < 0: + index += nValues for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) if typetuple[i] != object: - value = self.space.wrap(value) + value = space.wrap(value) return value - raise IndexError + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) cls.__name__ = ('W_SpecialisedTupleObject_' + ''.join([t.__name__[0] for t in typetuple])) @@ -178,64 +130,3 @@ return Cls_oo(space, w_arg1, w_arg2) else: raise NotSpecialised - -# ____________________________________________________________ - -registerimplementation(W_SpecialisedTupleObject) - -def delegate_SpecialisedTuple2Tuple(space, w_specialised): - w_specialised.delegating() - return W_TupleObject(w_specialised.tolist()) - -def len__SpecialisedTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SpecialisedTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SpecialisedTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_specialisedtuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SpecialisedTuple_ANY(space, w_tuple, w_times): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def mul__ANY_SpecialisedTuple(space, w_times, w_tuple): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.ne(space, w_tuple2) - -def hash__SpecialisedTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -1,6 +1,5 @@ import py, sys from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject from pypy.objspace.std.specialisedtupleobject import _specialisations from pypy.interpreter.error import OperationError from pypy.tool.pytest.objspace import gettestobjspace @@ -21,7 +20,7 @@ def test_isnotspecialisedtupleobject(self): w_tuple = self.space.newtuple([self.space.wrap({})]) - assert not isinstance(w_tuple, W_SpecialisedTupleObject) + assert not 'W_SpecialisedTupleObject' in type(w_tuple).__name__ def test_specialisedtupleclassname(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) @@ -38,7 +37,7 @@ S_w_tuple = S_space.newtuple(S_values_w) if must_be_specialized: - assert isinstance(S_w_tuple, W_SpecialisedTupleObject) + assert 'W_SpecialisedTupleObject' in type(S_w_tuple).__name__ assert isinstance(N_w_tuple, W_TupleObject) assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) @@ -57,23 +56,6 @@ class AppTestW_SpecialisedTupleObject: spaceconfig = {"objspace.std.withspecialisedtuple": True} - def setup_class(cls): - def forbid_delegation(space, w_tuple): - def delegation_forbidden(): - # haaaack - co = sys._getframe(2).f_code - if co.co_name.startswith('_mm_repr_tuple'): - return - raise OperationError(space.w_ReferenceError, w_tuple) - w_tuple.delegating = delegation_forbidden - return w_tuple - if cls.runappdirect: - cls.w_forbid_delegation = lambda self, x: x - cls.test_delegation = lambda self: skip("runappdirect") - else: - cls.w_forbid_delegation = cls.space.wrap( - gateway.interp2app(forbid_delegation)) - def w_isspecialised(self, obj, expected=''): import __pypy__ r = __pypy__.internal_repr(obj) @@ -101,12 +83,8 @@ obj = (1, 2, 3) assert self.isspecialised(obj, '_ooo') - def test_delegation(self): - t = self.forbid_delegation((42, 43)) - raises(ReferenceError, t.__getslice__, 0, 1) - def test_len(self): - t = self.forbid_delegation((42,43)) + t = (42, 43) assert len(t) == 2 def test_notspecialisedtuple(self): @@ -133,7 +111,7 @@ def test_eq_no_delegation(self): t = (1,) - a = self.forbid_delegation(t + (2,)) + a = t + (2,) b = (1, 2) assert a == b @@ -151,7 +129,7 @@ assert ((1,2) == (x,y)) == (1 == x and 2 == y) def test_neq(self): - a = self.forbid_delegation((1,2)) + a = (1,2) b = (1,) b = b+(2,) assert not a != b @@ -160,7 +138,7 @@ assert a != c def test_ordering(self): - a = (1,2) #self.forbid_delegation((1,2)) --- code commented out + a = (1,2) assert a < (2,2) assert a < (1,3) assert not a < (1,2) @@ -205,7 +183,7 @@ assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L)) def test_getitem(self): - t = self.forbid_delegation((5,3)) + t = (5, 3) assert (t)[0] == 5 assert (t)[1] == 3 assert (t)[-1] == 3 @@ -216,14 +194,14 @@ def test_three_tuples(self): if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - b = self.forbid_delegation((1, 2, 3)) + b = (1, 2, 3) c = (1,) d = c + (2, 3) assert self.isspecialised(d) assert b == d def test_mongrel(self): - a = self.forbid_delegation((2.2, '333')) + a = (2.2, '333') assert self.isspecialised(a) assert len(a) == 2 assert a[0] == 2.2 and a[1] == '333' @@ -233,7 +211,7 @@ # if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - a = self.forbid_delegation((1, 2.2, '333')) + a = (1, 2.2, '333') assert self.isspecialised(a) assert len(a) == 3 assert a[0] == 1 and a[1] == 2.2 and a[2] == '333' diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -142,8 +142,11 @@ items = self.tolist() return space.newtuple(items * times) - def descr_getitem(self, space, w_other): - raise NotImplementedError + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + return self._getslice(space, w_index) + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") + return self.getitem(space, index) def _getslice(self, space, w_index): items = self.tolist() @@ -213,7 +216,7 @@ __mul__ = interp2app(W_AbstractTupleObject.descr_mul), __rmul__ = interp2app(W_AbstractTupleObject.descr_mul), - __getitem__ = interpindirect2app(W_AbstractTupleObject.descr_getitem), + __getitem__ = interp2app(W_AbstractTupleObject.descr_getitem), __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice), __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs), @@ -264,16 +267,6 @@ descr_ne = negate(descr_eq) - def descr_getitem(self, space, w_index): - if isinstance(w_index, W_SliceObject): - return self._getslice(space, w_index) - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - try: - return self.wrappeditems[index] - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - def getitem(self, space, index): try: return self.wrappeditems[index] diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py --- a/pypy/objspace/std/tupletype.py +++ b/pypy/objspace/std/tupletype.py @@ -3,13 +3,12 @@ def wraptuple(space, list_w): from pypy.objspace.std.tupleobject import W_TupleObject - # XXX fix specialisedtuple - #if space.config.objspace.std.withspecialisedtuple: - # from specialisedtupleobject import makespecialisedtuple, NotSpecialised - # try: - # return makespecialisedtuple(space, list_w) - # except NotSpecialised: - # pass + if space.config.objspace.std.withspecialisedtuple: + from specialisedtupleobject import makespecialisedtuple, NotSpecialised + try: + return makespecialisedtuple(space, list_w) + except NotSpecialised: + pass if space.config.objspace.std.withsmalltuple: from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 From noreply at buildbot.pypy.org Wed May 22 03:12:13 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 03:12:13 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Kill tupletype.py. Message-ID: <20130522011213.B404F1C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64416:8c199c93b314 Date: 2013-05-22 03:08 +0200 http://bitbucket.org/pypy/pypy/changeset/8c199c93b314/ Log: Kill tupletype.py. diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -281,7 +281,7 @@ return newlong(self, val) def newtuple(self, list_w): - from pypy.objspace.std.tupletype import wraptuple + from pypy.objspace.std.tupleobject import wraptuple assert isinstance(list_w, list) make_sure_not_resized(list_w) return wraptuple(self, list_w) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -290,5 +290,35 @@ x += 97531 return intmask(x) -from pypy.objspace.std import tupletype -tupletype.tuple_typedef = W_TupleObject.typedef + +def wraptuple(space, list_w): + if space.config.objspace.std.withspecialisedtuple: + from specialisedtupleobject import makespecialisedtuple, NotSpecialised + try: + return makespecialisedtuple(space, list_w) + except NotSpecialised: + pass + + if space.config.objspace.std.withsmalltuple: + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 + if len(list_w) == 2: + return W_SmallTupleObject2(list_w) + if len(list_w) == 3: + return W_SmallTupleObject3(list_w) + if len(list_w) == 4: + return W_SmallTupleObject4(list_w) + if len(list_w) == 5: + return W_SmallTupleObject5(list_w) + if len(list_w) == 6: + return W_SmallTupleObject6(list_w) + if len(list_w) == 7: + return W_SmallTupleObject7(list_w) + if len(list_w) == 8: + return W_SmallTupleObject8(list_w) + return W_TupleObject(list_w) diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py deleted file mode 100644 --- a/pypy/objspace/std/tupletype.py +++ /dev/null @@ -1,36 +0,0 @@ -from pypy.objspace.std.register_all import register_all - -def wraptuple(space, list_w): - from pypy.objspace.std.tupleobject import W_TupleObject - - if space.config.objspace.std.withspecialisedtuple: - from specialisedtupleobject import makespecialisedtuple, NotSpecialised - try: - return makespecialisedtuple(space, list_w) - except NotSpecialised: - pass - - if space.config.objspace.std.withsmalltuple: - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 - if len(list_w) == 2: - return W_SmallTupleObject2(list_w) - if len(list_w) == 3: - return W_SmallTupleObject3(list_w) - if len(list_w) == 4: - return W_SmallTupleObject4(list_w) - if len(list_w) == 5: - return W_SmallTupleObject5(list_w) - if len(list_w) == 6: - return W_SmallTupleObject6(list_w) - if len(list_w) == 7: - return W_SmallTupleObject7(list_w) - if len(list_w) == 8: - return W_SmallTupleObject8(list_w) - return W_TupleObject(list_w) - From noreply at buildbot.pypy.org Wed May 22 03:12:15 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 03:12:15 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Kill itertype.py. Message-ID: <20130522011215.08C191C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64417:82a424bfdd8b Date: 2013-05-22 00:38 +0200 http://bitbucket.org/pypy/pypy/changeset/82a424bfdd8b/ Log: Kill itertype.py. diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,15 +1,16 @@ """Generic iterator implementations""" +from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.stdtypedef import StdTypeDef class W_AbstractIterObject(W_Object): __slots__ = () + class W_AbstractSeqIterObject(W_AbstractIterObject): - from pypy.objspace.std.itertype import iter_typedef as typedef - def __init__(w_self, w_seq, index=0): if index < 0: index = 0 @@ -26,13 +27,54 @@ w_len = space.wrap(0) return w_len + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + + # cpython does not support pickling iterators but stackless python do + #msg = 'Pickling for iterators dissabled as cpython does not support it' + #raise OperationError(space.w_TypeError, space.wrap(msg)) + + from pypy.objspace.std.iterobject import W_AbstractSeqIterObject + assert isinstance(self, W_AbstractSeqIterObject) + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('seqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) + + def descr_length_hint(self, space): + from pypy.objspace.std.iterobject import W_AbstractSeqIterObject + assert isinstance(self, W_AbstractSeqIterObject) + return self.getlength(space) + +W_AbstractSeqIterObject.typedef = StdTypeDef("sequenceiterator", + __doc__ = '''iter(collection) -> iterator +iter(callable, sentinel) -> iterator + +Get an iterator from an object. In the first form, the argument must +supply its own iterator, or be a sequence. +In the second form, the callable is called until it returns the sentinel.''', + + __reduce__ = gateway.interp2app(W_AbstractSeqIterObject.descr_reduce), + __length_hint__ = gateway.interp2app(W_AbstractSeqIterObject.descr_length_hint), + ) +W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False +iter_typedef = W_AbstractSeqIterObject.typedef + + class W_SeqIterObject(W_AbstractSeqIterObject): """Sequence iterator implementation for general sequences.""" + class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed """Sequence iterator specialized for lists. """ + class W_FastTupleIterObject(W_AbstractSeqIterObject): """Sequence iterator specialized for tuples, accessing directly their RPython-level list of wrapped objects. @@ -41,14 +83,51 @@ W_AbstractSeqIterObject.__init__(w_self, w_seq) w_self.tupleitems = wrappeditems + class W_ReverseSeqIterObject(W_Object): - from pypy.objspace.std.itertype import reverse_iter_typedef as typedef - def __init__(w_self, space, w_seq, index=-1): w_self.w_seq = w_seq w_self.w_len = space.len(w_seq) w_self.index = space.int_w(w_self.w_len) + index + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.objspace.std.iterobject import W_ReverseSeqIterObject + assert isinstance(self, W_ReverseSeqIterObject) + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('reverseseqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) + + def descr_length_hint(self, space): + from pypy.objspace.std.iterobject import W_ReverseSeqIterObject + assert isinstance(self, W_ReverseSeqIterObject) + if self.w_seq is None: + return space.wrap(0) + index = self.index + 1 + w_length = space.len(self.w_seq) + # if length of sequence is less than index :exhaust iterator + if space.is_true(space.gt(space.wrap(self.index), w_length)): + w_len = space.wrap(0) + self.w_seq = None + else: + w_len = space.wrap(index) + if space.is_true(space.lt(w_len, space.wrap(0))): + w_len = space.wrap(0) + return w_len + +W_ReverseSeqIterObject.typedef = StdTypeDef("reversesequenceiterator", + __reduce__ = gateway.interp2app(W_ReverseSeqIterObject.descr_reduce), + __length_hint__ = gateway.interp2app(W_ReverseSeqIterObject.descr_length_hint), +) +W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False +reverse_iter_typedef = W_ReverseSeqIterObject.typedef + registerimplementation(W_SeqIterObject) registerimplementation(W_FastListIterObject) diff --git a/pypy/objspace/std/itertype.py b/pypy/objspace/std/itertype.py deleted file mode 100644 --- a/pypy/objspace/std/itertype.py +++ /dev/null @@ -1,85 +0,0 @@ -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.interpreter.error import OperationError - -# ____________________________________________________________ - -def descr_seqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - - # cpython does not support pickling iterators but stackless python do - #msg = 'Pickling for iterators dissabled as cpython does not support it' - #raise OperationError(space.w_TypeError, space.wrap(msg)) - - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('seqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_seqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - return w_self.getlength(space) - -# ____________________________________________________________ - -def descr_reverseseqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('reverseseqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_reverseseqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - if w_self.w_seq is None: - return space.wrap(0) - index = w_self.index + 1 - w_length = space.len(w_self.w_seq) - # if length of sequence is less than index :exhaust iterator - if space.is_true(space.gt(space.wrap(w_self.index), w_length)): - w_len = space.wrap(0) - w_self.w_seq = None - else: - w_len = space.wrap(index) - if space.is_true(space.lt(w_len, space.wrap(0))): - w_len = space.wrap(0) - return w_len - -# ____________________________________________________________ -iter_typedef = StdTypeDef("sequenceiterator", - __doc__ = '''iter(collection) -> iterator -iter(callable, sentinel) -> iterator - -Get an iterator from an object. In the first form, the argument must -supply its own iterator, or be a sequence. -In the second form, the callable is called until it returns the sentinel.''', - - __reduce__ = gateway.interp2app(descr_seqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_seqiter__length_hint__), - ) -iter_typedef.acceptable_as_base_class = False - -reverse_iter_typedef = StdTypeDef("reversesequenceiterator", - - __reduce__ = gateway.interp2app(descr_reverseseqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_reverseseqiter__length_hint__), - ) -reverse_iter_typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -47,7 +47,7 @@ from pypy.objspace.std.longtype import long_typedef from pypy.objspace.std.unicodetype import unicode_typedef from pypy.objspace.std.nonetype import none_typedef - from pypy.objspace.std.itertype import iter_typedef + from pypy.objspace.std.iterobject import iter_typedef self.pythontypes = [value for key, value in result.__dict__.items() if not key.startswith('_')] # don't look From noreply at buildbot.pypy.org Wed May 22 03:12:16 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 03:12:16 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Kill iter SMMs. Message-ID: <20130522011216.564E31C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64418:447f13b83628 Date: 2013-05-22 01:01 +0200 http://bitbucket.org/pypy/pypy/changeset/447f13b83628/ Log: Kill iter SMMs. diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -9,6 +9,12 @@ class W_AbstractIterObject(W_Object): __slots__ = () + def descr_iter(self, space): + return self + + def descr_next(self, space): + raise NotImplementedError + class W_AbstractSeqIterObject(W_AbstractIterObject): def __init__(w_self, w_seq, index=0): @@ -59,6 +65,8 @@ supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.''', + __iter__ = gateway.interp2app(W_AbstractSeqIterObject.descr_iter), + next = gateway.interpindirect2app(W_AbstractSeqIterObject.descr_next), __reduce__ = gateway.interp2app(W_AbstractSeqIterObject.descr_reduce), __length_hint__ = gateway.interp2app(W_AbstractSeqIterObject.descr_length_hint), ) @@ -69,10 +77,37 @@ class W_SeqIterObject(W_AbstractSeqIterObject): """Sequence iterator implementation for general sequences.""" + def descr_next(self, space): + if self.w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + self.index += 1 + return w_item + class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed - """Sequence iterator specialized for lists. - """ + """Sequence iterator specialized for lists.""" + + def descr_next(self, space): + from pypy.objspace.std.listobject import W_ListObject + w_seq = self.w_seq + if w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + assert isinstance(w_seq, W_ListObject) + index = self.index + try: + w_item = w_seq.getitem(index) + except IndexError: + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item class W_FastTupleIterObject(W_AbstractSeqIterObject): @@ -83,6 +118,19 @@ W_AbstractSeqIterObject.__init__(w_self, w_seq) w_self.tupleitems = wrappeditems + def descr_next(self, space): + if self.tupleitems is None: + raise OperationError(space.w_StopIteration, space.w_None) + index = self.index + try: + w_item = self.tupleitems[index] + except IndexError: + self.tupleitems = None + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + class W_ReverseSeqIterObject(W_Object): def __init__(w_self, space, w_seq, index=-1): @@ -121,7 +169,25 @@ w_len = space.wrap(0) return w_len + def descr_iter(self, space): + return self + + def descr_next(self, space): + if self.w_seq is None or self.index < 0: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + self.index -= 1 + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + return w_item + W_ReverseSeqIterObject.typedef = StdTypeDef("reversesequenceiterator", + __iter__ = gateway.interp2app(W_ReverseSeqIterObject.descr_iter), + next = gateway.interp2app(W_ReverseSeqIterObject.descr_next), __reduce__ = gateway.interp2app(W_ReverseSeqIterObject.descr_reduce), __length_hint__ = gateway.interp2app(W_ReverseSeqIterObject.descr_length_hint), ) @@ -133,74 +199,3 @@ registerimplementation(W_FastListIterObject) registerimplementation(W_FastTupleIterObject) registerimplementation(W_ReverseSeqIterObject) - -def iter__SeqIter(space, w_seqiter): - return w_seqiter - -def next__SeqIter(space, w_seqiter): - if w_seqiter.w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index += 1 - return w_item - - -def iter__FastTupleIter(space, w_seqiter): - return w_seqiter - -def next__FastTupleIter(space, w_seqiter): - if w_seqiter.tupleitems is None: - raise OperationError(space.w_StopIteration, space.w_None) - index = w_seqiter.index - try: - w_item = w_seqiter.tupleitems[index] - except IndexError: - w_seqiter.tupleitems = None - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__FastListIter(space, w_seqiter): - return w_seqiter - -def next__FastListIter(space, w_seqiter): - from pypy.objspace.std.listobject import W_ListObject - w_seq = w_seqiter.w_seq - if w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - assert isinstance(w_seq, W_ListObject) - index = w_seqiter.index - try: - w_item = w_seq.getitem(index) - except IndexError: - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__ReverseSeqIter(space, w_seqiter): - return w_seqiter - -def next__ReverseSeqIter(space, w_seqiter): - if w_seqiter.w_seq is None or w_seqiter.index < 0: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - w_seqiter.index -= 1 - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - return w_item - -register_all(vars()) From noreply at buildbot.pypy.org Wed May 22 03:12:17 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 03:12:17 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Remove iterators from multi-method table. Message-ID: <20130522011217.90A8F1C1361@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64419:49537825a626 Date: 2013-05-22 01:07 +0200 http://bitbucket.org/pypy/pypy/changeset/49537825a626/ Log: Remove iterators from multi-method table. diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,22 +1,11 @@ """Generic iterator implementations""" from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all from pypy.objspace.std.stdtypedef import StdTypeDef -class W_AbstractIterObject(W_Object): - __slots__ = () - - def descr_iter(self, space): - return self - - def descr_next(self, space): - raise NotImplementedError - - -class W_AbstractSeqIterObject(W_AbstractIterObject): +class W_AbstractSeqIterObject(W_Root): def __init__(w_self, w_seq, index=0): if index < 0: index = 0 @@ -33,6 +22,12 @@ w_len = space.wrap(0) return w_len + def descr_iter(self, space): + return self + + def descr_next(self, space): + raise NotImplementedError + def descr_reduce(self, space): """ XXX to do: remove this __reduce__ method and do @@ -71,7 +66,6 @@ __length_hint__ = gateway.interp2app(W_AbstractSeqIterObject.descr_length_hint), ) W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False -iter_typedef = W_AbstractSeqIterObject.typedef class W_SeqIterObject(W_AbstractSeqIterObject): @@ -132,7 +126,7 @@ return w_item -class W_ReverseSeqIterObject(W_Object): +class W_ReverseSeqIterObject(W_Root): def __init__(w_self, space, w_seq, index=-1): w_self.w_seq = w_seq w_self.w_len = space.len(w_seq) @@ -192,10 +186,3 @@ __length_hint__ = gateway.interp2app(W_ReverseSeqIterObject.descr_length_hint), ) W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False -reverse_iter_typedef = W_ReverseSeqIterObject.typedef - - -registerimplementation(W_SeqIterObject) -registerimplementation(W_FastListIterObject) -registerimplementation(W_FastTupleIterObject) -registerimplementation(W_ReverseSeqIterObject) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -47,7 +47,6 @@ from pypy.objspace.std.longtype import long_typedef from pypy.objspace.std.unicodetype import unicode_typedef from pypy.objspace.std.nonetype import none_typedef - from pypy.objspace.std.iterobject import iter_typedef self.pythontypes = [value for key, value in result.__dict__.items() if not key.startswith('_')] # don't look @@ -83,6 +82,7 @@ self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) + self.pythontypes.append(iterobject.W_AbstractSeqIterObject.typedef) # the set of implementation types self.typeorder = { @@ -98,10 +98,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - iterobject.W_SeqIterObject: [], - iterobject.W_FastListIterObject: [], - iterobject.W_FastTupleIterObject: [], - iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], From noreply at buildbot.pypy.org Wed May 22 10:17:01 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 10:17:01 +0200 (CEST) Subject: [pypy-commit] pypy arm-stacklet: add arm to available platforms for selection Message-ID: <20130522081701.86C3F1C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-stacklet Changeset: r64420:8cc441451529 Date: 2013-05-22 03:03 -0500 http://bitbucket.org/pypy/pypy/changeset/8cc441451529/ Log: add arm to available platforms for selection diff --git a/rpython/translator/c/src/stacklet/slp_platformselect.h b/rpython/translator/c/src/stacklet/slp_platformselect.h --- a/rpython/translator/c/src/stacklet/slp_platformselect.h +++ b/rpython/translator/c/src/stacklet/slp_platformselect.h @@ -8,6 +8,8 @@ #include "switch_x86_64_gcc.h" /* gcc on amd64 */ #elif defined(__GNUC__) && defined(__i386__) #include "switch_x86_gcc.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__arm__) +#include "switch_arm_gcc.h" /* gcc on arm */ #else #error "Unsupported platform!" #endif From noreply at buildbot.pypy.org Wed May 22 10:17:03 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 10:17:03 +0200 (CEST) Subject: [pypy-commit] pypy arm-stacklet: initial implementation of slp_switch for ARM Message-ID: <20130522081703.088431C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-stacklet Changeset: r64421:35453be9d318 Date: 2013-05-22 03:10 -0500 http://bitbucket.org/pypy/pypy/changeset/35453be9d318/ Log: initial implementation of slp_switch for ARM diff --git a/rpython/translator/c/src/stacklet/switch_arm_gcc.h b/rpython/translator/c/src/stacklet/switch_arm_gcc.h new file mode 100644 --- /dev/null +++ b/rpython/translator/c/src/stacklet/switch_arm_gcc.h @@ -0,0 +1,40 @@ + +static void __attribute__((optimize("O3"))) *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra) +{ + void *result; + __asm__ volatile ( + "mov r3, %[save_state]\n" + /* save values in calee saved registers for later */ + "mov r4, %[restore_state]\n" + "mov r5, %[extra]\n" + "mov r0, sp\n" /* arg 1: current (old) stack pointer */ + "mov r1, r5\n" /* arg 2: extra */ + "blx r3\n" /* call save_state() */ + + /* skip the rest if the return value is null */ + "cmp r0, #0\n" + "beq zero\n" + + "mov sp, r0\n" /* change the stack pointer */ + + /* From now on, the stack pointer is modified, but the content of the + stack is not restored yet. It contains only garbage here. */ + "mov r1, r5\n" /* arg 2: extra */ + /* arg 1: current (new) stack pointer is already in r0*/ + "blx r4\n" /* call restore_state() */ + + /* The stack's content is now restored. */ + "zero:\n" + "mov %[result], r0\n" + + : [result]"=r"(result) /* output variables */ + /* input variables */ + : [restore_state]"r"(restore_state), + [save_state]"r"(save_state), + [extra]"r"(extra) + : "lr", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r13" + ); + return result; +} From noreply at buildbot.pypy.org Wed May 22 10:17:04 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 10:17:04 +0200 (CEST) Subject: [pypy-commit] pypy arm-stacklet: enable _continuation on ARM Message-ID: <20130522081704.5A7B41C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-stacklet Changeset: r64422:fd2338465291 Date: 2013-05-22 03:14 -0500 http://bitbucket.org/pypy/pypy/changeset/fd2338465291/ Log: enable _continuation on ARM diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -364,8 +364,6 @@ # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] - if config.translation.platform == 'arm' and '_continuation' in modules: - modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -65,7 +65,7 @@ self.tasks[0].withdepth(self.random.genrand32() % 50) assert len(self.tasks[0].lst) == 0 - @here_is_a_test + #@here_is_a_test def test_destroy(self): # this used to give MemoryError in shadowstack tests for i in range(100000): From noreply at buildbot.pypy.org Wed May 22 10:18:57 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 10:18:57 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove test_setitem(). Message-ID: <20130522081857.321D71C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64423:0e0ffca3fde2 Date: 2013-05-22 10:14 +0200 http://bitbucket.org/pypy/pypy/changeset/0e0ffca3fde2/ Log: Remove test_setitem(). diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ b/pypy/objspace/std/test/test_smalltupleobject.py @@ -78,11 +78,3 @@ assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) - - def test_setitem(self): - w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - w_smalltuple.setitem(0, self.space.wrap(5)) - list_w = w_smalltuple.tolist() - assert len(list_w) == 2 - assert self.space.eq_w(list_w[0], self.space.wrap(5)) - assert self.space.eq_w(list_w[1], self.space.wrap(2)) From noreply at buildbot.pypy.org Wed May 22 10:18:58 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 10:18:58 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Add a non-specialized code path to W_SpecialisedTupleObject's descr_eq(). Message-ID: <20130522081858.945121C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64424:f9d3d3fb8ad9 Date: 2013-05-22 10:16 +0200 http://bitbucket.org/pypy/pypy/changeset/f9d3d3fb8ad9/ Log: Add a non-specialized code path to W_SpecialisedTupleObject's descr_eq(). diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -74,9 +74,23 @@ return space.wrap(intmask(x)) def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplementedError if not isinstance(w_other, cls): - # if we are not comparing same types, give up - return space.w_NotImplemented + if nValues != w_other.length(): + return space.w_False + for i in iter_n: + myval = getattr(self, 'value%s' % i) + otherval = w_other.getitem(space, i) + if typetuple[i] == object: + myval_wrapped = myval + else: + myval_wrapped = space.wrap(myval) + if not space.eq_w(myval_wrapped, otherval): + return space.w_False + else: + return space.w_True + for i in iter_n: myval = getattr(self, 'value%s' % i) otherval = getattr(w_other, 'value%s' % i) From noreply at buildbot.pypy.org Wed May 22 11:14:31 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 11:14:31 +0200 (CEST) Subject: [pypy-commit] pypy default: make shadowstack the default gcrootfinder for all builds except linux/x86 Message-ID: <20130522091431.AFFFB1C0F0F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64425:bf86c92ce059 Date: 2013-05-22 09:11 +0000 http://bitbucket.org/pypy/pypy/changeset/bf86c92ce059/ Log: make shadowstack the default gcrootfinder for all builds except linux/x86 diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -13,9 +13,9 @@ DEFL_GC = "minimark" if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" + DEFL_ROOTFINDER = "asmgcc" else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + DEFL_ROOTFINDER = "shadowstack" IS_64_BITS = sys.maxint > 2147483647 @@ -89,7 +89,7 @@ ChoiceOption("gcrootfinder", "Strategy for finding GC Roots (framework GCs only)", ["n/a", "shadowstack", "asmgcc"], - "shadowstack", + DEFL_ROOTFINDER, cmdline="--gcrootfinder", requires={ "shadowstack": [("translation.gctransformer", "framework")], @@ -112,7 +112,7 @@ BoolOption("jit", "generate a JIT", default=False, suggests=[("translation.gc", DEFL_GC), - ("translation.gcrootfinder", DEFL_ROOTFINDER_WITHJIT), + ("translation.gcrootfinder", DEFL_ROOTFINDER), ("translation.list_comprehension_operations", True)]), ChoiceOption("jit_backend", "choose the backend for the JIT", ["auto", "x86", "x86-without-sse2", 'arm'], From noreply at buildbot.pypy.org Wed May 22 11:14:33 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 11:14:33 +0200 (CEST) Subject: [pypy-commit] pypy default: make cross-translation arm builds require shadowstack and suggest the right jit Message-ID: <20130522091433.30D1D1C0F0F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64426:e707c30857dc Date: 2013-05-22 09:13 +0000 http://bitbucket.org/pypy/pypy/changeset/e707c30857dc/ Log: make cross-translation arm builds require shadowstack and suggest the right jit backend. This should reduce the number of command-line flags for a 'default' cross-translation diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -276,7 +276,9 @@ ]), ChoiceOption("platform", "target platform", ['host'] + PLATFORMS, default='host', - cmdline='--platform'), + cmdline='--platform', + requires={"arm": [("translation.gcrootfinder", "shadowstack")]}, + suggests={"arm": [("translation.jit_backend", "arm")]}), ]) From noreply at buildbot.pypy.org Wed May 22 11:30:43 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:43 +0200 (CEST) Subject: [pypy-commit] lang-js default: fixed [].sort() and obj.put behaviour. Message-ID: <20130522093043.89A741C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r383:477e94f31216 Date: 2013-05-13 00:49 -0300 http://bitbucket.org/pypy/lang-js/changeset/477e94f31216/ Log: fixed [].sort() and obj.put behaviour. diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -40,6 +40,8 @@ # 15.4.4.11 put_native_function(w_ArrayPrototype, u'sort', sort) + put_native_function(w_ArrayPrototype, u'forEach', for_each) + # 15.4.4.7 @w_return @@ -162,10 +164,17 @@ lower = lower + 1 + at w_return +def for_each(this): + obj = this + length = this.get(u'length').ToUInt32() + return this + + # 15.4.4.11 @w_return def sort(this, args): - obj = this + obj = this.ToObject() length = this.get(u'length').ToUInt32() comparefn = get_arg(args, 0) diff --git a/js/jsobj.py b/js/jsobj.py --- a/js/jsobj.py +++ b/js/jsobj.py @@ -324,7 +324,7 @@ own_desc = self.get_own_property(p) if is_data_descriptor(own_desc) is True: - value_desc = PropertyDescriptor(value=v) + value_desc = PropertyDescriptor(value=v, writable=True) self.define_own_property(p, value_desc, throw) return diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,12 @@ from test.test_interp import assertv, assertp +def test_sort(capsys): + assertp("var x = [5,2]; print(x.sort());", '2,5', capsys) + assertp("var x = [1,2,3]; print(x.sort());", '1,2,3', capsys) + assertp("var x = [4,3,2,1]; print(x.sort());", '1,2,3,4', capsys) + + def test_array_push(capsys): assertv("var x = []; x.push(42); x.length;", 1) assertv("var x = []; x.push(42); x[0];", 42) diff --git a/test/test_w_array.py b/test/test_w_array.py --- a/test/test_w_array.py +++ b/test/test_w_array.py @@ -3,6 +3,14 @@ from js.object_space import _w +def test_array_put_change_index(): + a = W__Array() + a.put(u'0', 42) + assert a.get(u'0') == 42 + a.put(u'0', 43) + assert a.get(u'0') == 43 + + def test_array_get(): a = W__Array() a._set_prop(u'23', DataProperty(42, True, True, True)) From noreply at buildbot.pypy.org Wed May 22 11:30:44 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:44 +0200 (CEST) Subject: [pypy-commit] lang-js default: removed forEach incomplete code. Message-ID: <20130522093044.B4CA31C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r384:5b134866e4d5 Date: 2013-05-13 13:35 -0300 http://bitbucket.org/pypy/lang-js/changeset/5b134866e4d5/ Log: removed forEach incomplete code. diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -40,8 +40,6 @@ # 15.4.4.11 put_native_function(w_ArrayPrototype, u'sort', sort) - put_native_function(w_ArrayPrototype, u'forEach', for_each) - # 15.4.4.7 @w_return @@ -164,17 +162,10 @@ lower = lower + 1 - at w_return -def for_each(this): - obj = this - length = this.get(u'length').ToUInt32() - return this - - # 15.4.4.11 @w_return def sort(this, args): - obj = this.ToObject() + obj = this length = this.get(u'length').ToUInt32() comparefn = get_arg(args, 0) From noreply at buildbot.pypy.org Wed May 22 11:30:45 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:45 +0200 (CEST) Subject: [pypy-commit] lang-js default: Merge. Message-ID: <20130522093045.EEBA21C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r385:2b95a7505bfb Date: 2013-05-13 13:36 -0300 http://bitbucket.org/pypy/lang-js/changeset/2b95a7505bfb/ Log: Merge. changed js/baseop.py changed js/object_space.py changed js/opcodes.py diff --git a/js/baseop.py b/js/baseop.py --- a/js/baseop.py +++ b/js/baseop.py @@ -3,10 +3,12 @@ """ from js.jsobj import W_String, W_IntNumber, W_FloatNumber -from js.object_space import _w, isint +from js.object_space import _w, isint, isstr, isfloat from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rfloat import isnan, isinf +from rpython.rlib.objectmodel import specialize + from js.builtins.number import w_NAN, w_POSITIVE_INFINITY, w_NEGATIVE_INFINITY import math @@ -141,50 +143,56 @@ return W_FloatNumber(val) -def compare(ctx, x, y): + at specialize.argtype(0, 1) +def _compare_gt(x, y): + return x > y + + + at specialize.argtype(0, 1) +def _compare_ge(x, y): + return x >= y + + +def _base_compare(x, y, _compare): if isint(x) and isint(y): - return x.ToInteger() > y.ToInteger() - if isinstance(x, W_FloatNumber) and isinstance(y, W_FloatNumber): - if isnan(x.ToNumber()) or isnan(y.ToNumber()): - return -1 - return x.ToNumber() > y.ToNumber() - s1 = x.ToPrimitive('Number') - s2 = y.ToPrimitive('Number') - if not (isinstance(s1, W_String) and isinstance(s2, W_String)): - s4 = s1.ToNumber() - s5 = s2.ToNumber() - if isnan(s4) or isnan(s5): - return False - return s4 > s5 + return _compare(x.ToInteger(), y.ToInteger()) + + if isfloat(x) and isfloat(y): + n1 = x.ToNumber() + n2 = x.ToNumber() + return _compare(n1, n2) + + p1 = x.ToPrimitive('Number') + p2 = y.ToPrimitive('Number') + + if not (isstr(p1) and isstr(p2)): + n1 = p1.ToNumber() + n2 = p2.ToNumber() + return _compare(n1, n2) else: - s4 = s1.to_string() - s5 = s2.to_string() - return s4 > s5 + s1 = p1.to_string() + s2 = p2.to_string() + return _compare(s1, s2) -def compare_e(ctx, x, y): - if isint(x) and isint(y): - return x.ToInteger() >= y.ToInteger() - if isinstance(x, W_FloatNumber) and isinstance(y, W_FloatNumber): - if isnan(x.ToNumber()) or isnan(y.ToNumber()): - return -1 - return x.ToNumber() >= y.ToNumber() - s1 = x.ToPrimitive('Number') - s2 = y.ToPrimitive('Number') - if not (isinstance(s1, W_String) and isinstance(s2, W_String)): - s4 = s1.ToNumber() - s5 = s2.ToNumber() - if isnan(s4) or isnan(s5): - return False - return s4 >= s5 - else: - s4 = s1.to_string() - s5 = s2.to_string() - return s4 >= s5 +def compare_gt(x, y): + return _base_compare(x, y, _compare_gt) + + +def compare_ge(x, y): + return _base_compare(x, y, _compare_ge) + + +def compare_lt(x, y): + return _base_compare(y, x, _compare_gt) + + +def compare_le(x, y): + return _base_compare(y, x, _compare_ge) # 11.9.3 -def AbstractEC(ctx, x, y): +def AbstractEC(x, y): """ Implements the Abstract Equality Comparison x == y trying to be fully to the spec @@ -220,19 +228,19 @@ (type1 == "null" and type2 == "undefined"): return True if type1 == "number" and type2 == "string": - return AbstractEC(ctx, x, W_FloatNumber(y.ToNumber())) + return AbstractEC(x, W_FloatNumber(y.ToNumber())) if type1 == "string" and type2 == "number": - return AbstractEC(ctx, W_FloatNumber(x.ToNumber()), y) + return AbstractEC(W_FloatNumber(x.ToNumber()), y) if type1 == "boolean": - return AbstractEC(ctx, W_FloatNumber(x.ToNumber()), y) + return AbstractEC(W_FloatNumber(x.ToNumber()), y) if type2 == "boolean": - return AbstractEC(ctx, x, W_FloatNumber(y.ToNumber())) + return AbstractEC(x, W_FloatNumber(y.ToNumber())) if (type1 == "string" or type1 == "number") and \ type2 == "object": - return AbstractEC(ctx, x, y.ToPrimitive()) + return AbstractEC(x, y.ToPrimitive()) if (type2 == "string" or type2 == "number") and \ type1 == "object": - return AbstractEC(ctx, x.ToPrimitive(), y) + return AbstractEC(x.ToPrimitive(), y) return False objtype = x.GetValue().type() diff --git a/js/object_space.py b/js/object_space.py --- a/js/object_space.py +++ b/js/object_space.py @@ -7,6 +7,16 @@ return isinstance(w, W_IntNumber) +def isstr(w): + from js.jsobj import W_String + return isinstance(w, W_String) + + +def isfloat(w): + from js.jsobj import W_FloatNumber + return isinstance(w, W_FloatNumber) + + @enforceargs(int) def newint(i): from js.jsobj import W_IntNumber @@ -79,7 +89,7 @@ @enforceargs(bool) def newbool(val): - if val is True: + if val: return w_True return w_False diff --git a/js/opcodes.py b/js/opcodes.py --- a/js/opcodes.py +++ b/js/opcodes.py @@ -3,8 +3,7 @@ from js.object_space import _w, isint from js.exception import JsTypeError -from js.baseop import plus, sub, compare, AbstractEC, StrictEC,\ - compare_e, increment, decrement, mult, division, uminus, mod +from js.baseop import plus, sub, AbstractEC, StrictEC, increment, decrement, mult, division, uminus, mod from js.jsobj import put_property @@ -35,12 +34,10 @@ from js.object_space import newbool s4 = ctx.stack_pop() s2 = ctx.stack_pop() - res = self.decision(ctx, s2, s4) - # XXX mimik behaviour of old newbool - res_true = res is True - ctx.stack_append(newbool(res_true)) + res = self.decision(s2, s4) + ctx.stack_append(newbool(res)) - def decision(self, ctx, op1, op2): + def decision(self, op1, op2): raise NotImplementedError @@ -369,16 +366,17 @@ rnum = rval.ToUInt32() lnum = lval.ToUInt32() - from rpython.rlib.rarithmetic import ovfcheck_float_to_int + #from rpython.rlib.rarithmetic import ovfcheck_float_to_int shift_count = rnum & 0x1F res = lnum >> shift_count + w_res = _w(res) - try: - ovfcheck_float_to_int(res) - w_res = _w(res) - except OverflowError: - w_res = _w(float(res)) + #try: + #ovfcheck_float_to_int(res) + #w_res = _w(res) + #except OverflowError: + #w_res = _w(float(res)) ctx.stack_append(w_res) @@ -476,42 +474,50 @@ class GT(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare(ctx, op1, op2) + def decision(self, op1, op2): + from js.baseop import compare_gt + res = compare_gt(op1, op2) + return res class GE(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare_e(ctx, op1, op2) + def decision(self, op1, op2): + from js.baseop import compare_ge + res = compare_ge(op1, op2) + return res class LT(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare(ctx, op2, op1) + def decision(self, op1, op2): + from js.baseop import compare_lt + res = compare_lt(op1, op2) + return res class LE(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return compare_e(ctx, op2, op1) + def decision(self, op1, op2): + from js.baseop import compare_le + res = compare_le(op1, op2) + return res class EQ(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return AbstractEC(ctx, op1, op2) + def decision(self, op1, op2): + return AbstractEC(op1, op2) class NE(BaseBinaryComparison): - def decision(self, ctx, op1, op2): - return not AbstractEC(ctx, op1, op2) + def decision(self, op1, op2): + return not AbstractEC(op1, op2) class IS(BaseBinaryComparison): - def decision(self, ctx, op1, op2): + def decision(self, op1, op2): return StrictEC(op1, op2) class ISNOT(BaseBinaryComparison): - def decision(self, ctx, op1, op2): + def decision(self, op1, op2): return not StrictEC(op1, op2) From noreply at buildbot.pypy.org Wed May 22 11:30:47 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:47 +0200 (CEST) Subject: [pypy-commit] lang-js default: implemented [].indexOf and [].forEach Message-ID: <20130522093047.369251C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r386:c11ac659bd1e Date: 2013-05-15 01:29 -0300 http://bitbucket.org/pypy/lang-js/changeset/c11ac659bd1e/ Log: implemented [].indexOf and [].forEach diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -40,6 +40,10 @@ # 15.4.4.11 put_native_function(w_ArrayPrototype, u'sort', sort) + put_native_function(w_ArrayPrototype, u'forEach', for_each) + + put_native_function(w_ArrayPrototype, u'indexOf', index_of) + # 15.4.4.7 @w_return @@ -162,6 +166,34 @@ lower = lower + 1 + at w_return +def index_of(this, args): + obj = this + length = this.get(u'length').ToUInt32() + elem = get_arg(args, 0) + from_index = get_arg(args, 1).ToUInt32() + + from js.jsobj import W_IntNumber + for i in xrange(from_index, length): + y = obj.get(unicode(i)) + if elem == y: + return W_IntNumber(i) + return W_IntNumber(-1) + + +def for_each(this, args): + obj = this + length = this.get(u'length').ToUInt32() + + callback = get_arg(args, 0) + from js.jsobj import W_BasicFunction + assert isinstance(callback, W_BasicFunction) + + for i in xrange(length): + x = obj.get(unicode(str(i))) + callback.Call(args=[x], this=newundefined()) + + # 15.4.4.11 @w_return def sort(this, args): diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,18 @@ from test.test_interp import assertv, assertp +def test_array_index_of(capsys): + assertp("var a = [1,2,3]; print(a.indexOf(1));", "0", capsys) + assertp("var a = [1,2,3]; print(a.indexOf(3));", "2", capsys) + assertp("var a = [1,2,3]; print(a.indexOf(5));", "-1", capsys) + assertp("var a = [1,2,3,1]; print(a.indexOf(1,2));", "3", capsys) + assertp("var a = [1,2,3,1]; print(a.indexOf(1,5));", "-1", capsys) + + +def test_array_foreach(capsys): + assertp("var a = [1,2,3]; var b = []; a.forEach(function(v){b.push(v*2)}); print(b);", "2,4,6", capsys) + + def test_sort(capsys): assertp("var x = [5,2]; print(x.sort());", '2,5', capsys) assertp("var x = [1,2,3]; print(x.sort());", '1,2,3', capsys) From noreply at buildbot.pypy.org Wed May 22 11:30:48 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:48 +0200 (CEST) Subject: [pypy-commit] lang-js default: Merge. Message-ID: <20130522093048.70EBE1C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r387:f8d62a109320 Date: 2013-05-15 18:23 -0300 http://bitbucket.org/pypy/lang-js/changeset/f8d62a109320/ Log: Merge. diff --git a/js/jsobj.py b/js/jsobj.py --- a/js/jsobj.py +++ b/js/jsobj.py @@ -1484,6 +1484,9 @@ return Descr(inherited.writable, None, inherited, prop) def _define_own_idx_property(self, idx, desc, throw=False, current_desc=None, prop=None): + if current_desc is None: + current_desc = self._get_idx_property(idx) + from js.object_space import _w old_len_desc = self.get_own_property(u'length') assert old_len_desc is not None @@ -1595,6 +1598,7 @@ if desc.has_set_getter() and desc.getter != current.getter: return _ireject(throw, idx) # 12 + prop = self._get_iprop(idx) prop.update_with_descriptor(desc) # 13 @@ -1612,12 +1616,13 @@ # 15.4.5.1 def define_own_property(self, p, desc, throw=False): from js.object_space import _w - old_len_desc = self.get_own_property(u'length') - assert old_len_desc is not None - old_len = old_len_desc.value.ToUInt32() # 3 if p == u'length': + old_len_desc = self.get_own_property(u'length') + assert old_len_desc is not None + old_len = old_len_desc.value.ToUInt32() + if desc.has_set_value() is False: return W_BasicObject.define_own_property(self, u'length', desc, throw) new_len_desc = desc.copy() From noreply at buildbot.pypy.org Wed May 22 11:30:49 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:49 +0200 (CEST) Subject: [pypy-commit] lang-js default: implemented [].lastIndexOf Message-ID: <20130522093049.963E11C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r388:d0c0e12a41e2 Date: 2013-05-17 00:41 -0300 http://bitbucket.org/pypy/lang-js/changeset/d0c0e12a41e2/ Log: implemented [].lastIndexOf diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -44,6 +44,8 @@ put_native_function(w_ArrayPrototype, u'indexOf', index_of) + put_native_function(w_ArrayPrototype, u'lastIndexOf', last_index_of) + # 15.4.4.7 @w_return @@ -167,6 +169,28 @@ @w_return +def last_index_of(this, args): + obj = this + elem = get_arg(args, 0) + length = this.get(u'length').ToUInt32() + from_index = length + + if len(args) > 1: + findex = get_arg(args, 1).ToInt32() + if findex < 0: + from_index = length + findex + else: + from_index = findex + + from js.jsobj import W_IntNumber + for i in xrange(from_index, -1, -1): + y = obj.get(unicode(i)) + if elem == y: + return W_IntNumber(i) + return W_IntNumber(-1) + + + at w_return def index_of(this, args): obj = this length = this.get(u'length').ToUInt32() diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,15 @@ from test.test_interp import assertv, assertp +def test_arrya_last_index_of(capsys): + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2));", "3", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(7));", "-1", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, 3));", "3", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, 2));", "0", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, -2));", "0", capsys) + assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, -1));", "3", capsys) + + def test_array_index_of(capsys): assertp("var a = [1,2,3]; print(a.indexOf(1));", "0", capsys) assertp("var a = [1,2,3]; print(a.indexOf(3));", "2", capsys) From noreply at buildbot.pypy.org Wed May 22 11:30:50 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:50 +0200 (CEST) Subject: [pypy-commit] lang-js default: fixed typo. Message-ID: <20130522093050.AEEFA1C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r389:ea1db4caae17 Date: 2013-05-18 15:19 -0300 http://bitbucket.org/pypy/lang-js/changeset/ea1db4caae17/ Log: fixed typo. diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,7 +1,7 @@ from test.test_interp import assertv, assertp -def test_arrya_last_index_of(capsys): +def test_array_last_index_of(capsys): assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2));", "3", capsys) assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(7));", "-1", capsys) assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2, 3));", "3", capsys) From noreply at buildbot.pypy.org Wed May 22 11:30:51 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:51 +0200 (CEST) Subject: [pypy-commit] lang-js default: implemented [].shift Message-ID: <20130522093051.C3A971C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r390:601cbe26b7b1 Date: 2013-05-20 00:11 -0300 http://bitbucket.org/pypy/lang-js/changeset/601cbe26b7b1/ Log: implemented [].shift diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -46,6 +46,8 @@ put_native_function(w_ArrayPrototype, u'lastIndexOf', last_index_of) + put_native_function(w_ArrayPrototype, u'shift', shift) + # 15.4.4.7 @w_return @@ -136,6 +138,25 @@ return element + at w_return +def shift(this, args): + o = this.ToObject() + l = o.get(u'length').ToUInt32() + + if l == 0: + o.put(u'length', _w(0)) + return newundefined() + else: + new_length = l - 1 + element = o.get(u"0") + for i in xrange(0, new_length): + indx = unicode(str(i)) + next_indx = unicode(str(i + 1)) + o.put(indx, o.get(next_indx)) + o.put(u'length', _w(new_length)) + return element + + # 15.4.4.8 @w_return def reverse(this, args): diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,12 @@ from test.test_interp import assertv, assertp +def test_array_shift(capsys): + assertp("var a = [2, 5, 9, 2]; print(a.shift());", "2", capsys) + assertp("var a = [2, 5, 9, 2]; a.shift(); print(a);", "5,9,2", capsys) + assertp("var a = [2, 5, 9, 2]; a.shift(); print(a.length);", "3", capsys) + + def test_array_last_index_of(capsys): assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(2));", "3", capsys) assertp("var a = [2, 5, 9, 2]; print(a.lastIndexOf(7));", "-1", capsys) From noreply at buildbot.pypy.org Wed May 22 11:30:53 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:53 +0200 (CEST) Subject: [pypy-commit] lang-js default: merge Message-ID: <20130522093053.298211C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r391:a9963a288dd2 Date: 2013-05-20 00:15 -0300 http://bitbucket.org/pypy/lang-js/changeset/a9963a288dd2/ Log: merge From noreply at buildbot.pypy.org Wed May 22 11:30:54 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:54 +0200 (CEST) Subject: [pypy-commit] lang-js default: fixed merge. Message-ID: <20130522093054.808FA1C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r392:fea399d190db Date: 2013-05-20 00:18 -0300 http://bitbucket.org/pypy/lang-js/changeset/fea399d190db/ Log: fixed merge. diff --git a/js/jsobj.py b/js/jsobj.py --- a/js/jsobj.py +++ b/js/jsobj.py @@ -324,7 +324,7 @@ own_desc = self.get_own_property(p) if is_data_descriptor(own_desc) is True: - value_desc = PropertyDescriptor(value=v, writable=True) + value_desc = PropertyDescriptor(value=v) self.define_own_property(p, value_desc, throw) return From noreply at buildbot.pypy.org Wed May 22 11:30:55 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:55 +0200 (CEST) Subject: [pypy-commit] lang-js default: implemented [].slice Message-ID: <20130522093055.8E8A01C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r393:4a574c8049ff Date: 2013-05-20 01:44 -0300 http://bitbucket.org/pypy/lang-js/changeset/4a574c8049ff/ Log: implemented [].slice diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -48,6 +48,24 @@ put_native_function(w_ArrayPrototype, u'shift', shift) + put_native_function(w_ArrayPrototype, u'slice', slice) + + + at w_return +def slice(this, args): + o = this.ToObject() + from_index = get_arg(args, 0).ToUInt32() + to_index = get_arg(args, 1).ToUInt32() + + n = [] + + i = 0 + for k in xrange(from_index, to_index): + n.append(o.get(unicode(str(k)))) + i += 1 + + return _w(n) + # 15.4.4.7 @w_return diff --git a/test/test_array.py b/test/test_array.py --- a/test/test_array.py +++ b/test/test_array.py @@ -1,6 +1,10 @@ from test.test_interp import assertv, assertp +def test_array_slice(capsys): + assertp("var a = [2, 5, 9, 2]; print(a.slice(1,3));", "5,9", capsys) + + def test_array_shift(capsys): assertp("var a = [2, 5, 9, 2]; print(a.shift());", "2", capsys) assertp("var a = [2, 5, 9, 2]; a.shift(); print(a);", "5,9,2", capsys) From noreply at buildbot.pypy.org Wed May 22 11:30:56 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Wed, 22 May 2013 11:30:56 +0200 (CEST) Subject: [pypy-commit] lang-js default: removed unused counter. Message-ID: <20130522093056.BF60C1C12A2@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r394:cdfd44c86dcb Date: 2013-05-20 10:54 -0300 http://bitbucket.org/pypy/lang-js/changeset/cdfd44c86dcb/ Log: removed unused counter. diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -59,10 +59,8 @@ n = [] - i = 0 for k in xrange(from_index, to_index): n.append(o.get(unicode(str(k)))) - i += 1 return _w(n) From noreply at buildbot.pypy.org Wed May 22 11:50:04 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 11:50:04 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Rewrite test_hash_agains_normal_tuple() to use one object space. Message-ID: <20130522095004.62F581C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64427:4b09b2a9ef69 Date: 2013-05-22 10:38 +0200 http://bitbucket.org/pypy/pypy/changeset/4b09b2a9ef69/ Log: Rewrite test_hash_agains_normal_tuple() to use one object space. diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ b/pypy/objspace/std/test/test_smalltupleobject.py @@ -67,14 +67,11 @@ assert isinstance(w_tuple, W_SmallTupleObject2) def test_hash_agains_normal_tuple(self): - normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) - w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) + w_tuple = W_TupleObject([self.space.wrap(1), self.space.wrap(2)]) + w_smalltuple = self.space.newtuple([self.space.wrap(1), + self.space.wrap(2)]) + assert isinstance(w_smalltuple, W_SmallTupleObject2) - smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) - w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - assert isinstance(w_smalltuple, W_SmallTupleObject2) - assert isinstance(w_tuple, W_TupleObject) - assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) + assert self.space.is_true(self.space.eq(w_tuple, w_smalltuple)) + assert self.space.is_true(self.space.eq(self.space.hash(w_tuple), + self.space.hash(w_smalltuple))) From noreply at buildbot.pypy.org Wed May 22 11:50:05 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 11:50:05 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Inline hash_tuple(). Message-ID: <20130522095005.CE9031C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64428:1fabc722bc4f Date: 2013-05-22 10:55 +0200 http://bitbucket.org/pypy/pypy/changeset/1fabc722bc4f/ Log: Inline hash_tuple(). diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -191,7 +191,6 @@ raise OperationError(space.w_ValueError, space.wrap("tuple.index(x): x not in tuple")) - W_AbstractTupleObject.typedef = StdTypeDef("tuple", __doc__ = '''tuple() -> an empty tuple tuple(sequence) -> tuple initialized from sequence's items @@ -225,7 +224,6 @@ ) - class W_TupleObject(W_AbstractTupleObject): _immutable_fields_ = ['wrappeditems[*]'] @@ -242,8 +240,20 @@ def length(self): return len(self.wrappeditems) + @jit.look_inside_iff(lambda self, space: jit.loop_unrolling_heuristic( + self.wrappeditems, len(self.wrappeditems), UNROLL_CUTOFF)) def descr_hash(self, space): - return space.wrap(hash_tuple(space, self.wrappeditems)) + # this is the CPython 2.4 algorithm (changed from 2.3) + mult = 1000003 + x = 0x345678 + z = len(self.wrappeditems) + for w_item in self.wrappeditems: + y = space.hash_w(w_item) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return intmask(x) def descr_eq(self, space, w_other): if not isinstance(w_other, W_AbstractTupleObject): @@ -275,22 +285,6 @@ space.wrap("tuple index out of range")) - at jit.look_inside_iff(lambda space, wrappeditems: - jit.loop_unrolling_heuristic(wrappeditems, len(wrappeditems), UNROLL_CUTOFF)) -def hash_tuple(space, wrappeditems): - # this is the CPython 2.4 algorithm (changed from 2.3) - mult = 1000003 - x = 0x345678 - z = len(wrappeditems) - for w_item in wrappeditems: - y = space.hash_w(w_item) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return intmask(x) - - def wraptuple(space, list_w): if space.config.objspace.std.withspecialisedtuple: from specialisedtupleobject import makespecialisedtuple, NotSpecialised From noreply at buildbot.pypy.org Wed May 22 11:50:07 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 11:50:07 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Wrap return value of descr_hash(). Message-ID: <20130522095007.399CA1C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64429:96d8d298a906 Date: 2013-05-22 11:20 +0200 http://bitbucket.org/pypy/pypy/changeset/96d8d298a906/ Log: Wrap return value of descr_hash(). diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -253,7 +253,7 @@ z -= 1 mult += 82520 + z + z x += 97531 - return intmask(x) + return space.wrap(intmask(x)) def descr_eq(self, space, w_other): if not isinstance(w_other, W_AbstractTupleObject): From noreply at buildbot.pypy.org Wed May 22 11:50:08 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 11:50:08 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Style fixes. Message-ID: <20130522095008.7742A1C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64430:8da79536cbc4 Date: 2013-05-22 11:22 +0200 http://bitbucket.org/pypy/pypy/changeset/8da79536cbc4/ Log: Style fixes. diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py --- a/pypy/objspace/std/smalltupleobject.py +++ b/pypy/objspace/std/smalltupleobject.py @@ -8,8 +8,8 @@ def make_specialized_class(n): iter_n = unrolling_iterable(range(n)) + class cls(W_AbstractTupleObject): - def __init__(self, values): assert len(values) == n for i in iter_n: @@ -32,7 +32,7 @@ index += n for i in iter_n: if index == i: - return getattr(self,'w_value%s' % i) + return getattr(self, 'w_value%s' % i) raise OperationError(space.w_IndexError, space.wrap("tuple index out of range")) @@ -42,7 +42,7 @@ if n != w_other.length(): return space.w_False for i in iter_n: - item1 = getattr(self,'w_value%s' % i) + item1 = getattr(self, 'w_value%s' % i) item2 = w_other.getitem(space, i) if not space.eq_w(item1, item2): return space.w_False diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -80,7 +80,7 @@ if nValues != w_other.length(): return space.w_False for i in iter_n: - myval = getattr(self, 'value%s' % i) + myval = getattr(self, 'value%s' % i) otherval = w_other.getitem(space, i) if typetuple[i] == object: myval_wrapped = myval @@ -92,7 +92,7 @@ return space.w_True for i in iter_n: - myval = getattr(self, 'value%s' % i) + myval = getattr(self, 'value%s' % i) otherval = getattr(w_other, 'value%s' % i) if typetuple[i] == object: if not self.space.eq_w(myval, otherval): diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ b/pypy/objspace/std/test/test_smalltupleobject.py @@ -1,8 +1,7 @@ +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 +from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 -from pypy.interpreter.error import OperationError -from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject -from pypy.tool.pytest.objspace import gettestobjspace + class AppTestW_SmallTupleObject(AppTestW_TupleObject): spaceconfig = {"objspace.std.withsmalltuple": True} @@ -16,8 +15,8 @@ """) def test_smalltuple(self): - self.issmall((1,2)) - self.issmall((1,2,3)) + self.issmall((1, 2)) + self.issmall((1, 2, 3)) def test_slicing_to_small(self): self.issmall((1, 2, 3)[0:2]) # SmallTuple2 @@ -27,38 +26,39 @@ self.issmall((1, 2, 3, 4)[0:3:1]) def test_adding_to_small(self): - self.issmall((1,)+(2,)) # SmallTuple2 - self.issmall((1,1)+(2,)) # SmallTuple3 - self.issmall((1,)+(2,3)) + self.issmall((1,) + (2,)) # SmallTuple2 + self.issmall((1, 1) + (2,)) # SmallTuple3 + self.issmall((1,) + (2, 3)) def test_multiply_to_small(self): - self.issmall((1,)*2) - self.issmall((1,)*3) + self.issmall((1,) * 2) + self.issmall((1,) * 3) def test_slicing_from_small(self): - assert (1,2)[0:1:1] == (1,) - assert (1,2,3)[0:2:1] == (1,2) + assert (1, 2)[0:1:1] == (1,) + assert (1, 2, 3)[0:2:1] == (1, 2) def test_eq(self): - a = (1,2,3) - b = (1,2,3) + a = (1, 2, 3) + b = (1, 2, 3) assert a == b - c = (1,3,2) + c = (1, 3, 2) assert a != c def test_hash(self): - a = (1,2,3) - b = (1,2,3) + a = (1, 2, 3) + b = (1, 2, 3) assert hash(a) == hash(b) - c = (1,3,2) + c = (1, 3, 2) assert hash(a) != hash(c) def test_foo(self): assert tuple([0]) + (1,) == (0, 1) assert not tuple([0]) + (1,) == (0,) + class TestW_SmallTupleObject(): spaceconfig = {"objspace.std.withsmalltuple": True} diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -1,10 +1,7 @@ -import py, sys +from pypy.objspace.std.specialisedtupleobject import _specialisations +from pypy.objspace.std.test import test_tupleobject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.specialisedtupleobject import _specialisations -from pypy.interpreter.error import OperationError from pypy.tool.pytest.objspace import gettestobjspace -from pypy.objspace.std.test import test_tupleobject -from pypy.interpreter import gateway for cls in _specialisations: @@ -17,11 +14,11 @@ def test_isspecialisedtupleobjectintint(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert isinstance(w_tuple, W_SpecialisedTupleObject_ii) - + def test_isnotspecialisedtupleobject(self): w_tuple = self.space.newtuple([self.space.wrap({})]) assert not 'W_SpecialisedTupleObject' in type(w_tuple).__name__ - + def test_specialisedtupleclassname(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii' @@ -29,7 +26,7 @@ def test_hash_against_normal_tuple(self): N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": False}) S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) - + def hash_test(values, must_be_specialized=True): N_values_w = [N_space.wrap(value) for value in values] S_values_w = [S_space.wrap(value) for value in values] @@ -42,15 +39,15 @@ assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) - hash_test([1,2]) - hash_test([1.5,2.8]) - hash_test([1.0,2.0]) - hash_test(['arbitrary','strings']) - hash_test([1,(1,2,3,4)]) - hash_test([1,(1,2)]) - hash_test([1,('a',2)]) - hash_test([1,()]) - hash_test([1,2,3], must_be_specialized=False) + hash_test([1, 2]) + hash_test([1.5, 2.8]) + hash_test([1.0, 2.0]) + hash_test(['arbitrary', 'strings']) + hash_test([1, (1, 2, 3, 4)]) + hash_test([1, (1, 2)]) + hash_test([1, ('a', 2)]) + hash_test([1, ()]) + hash_test([1, 2, 3], must_be_specialized=False) class AppTestW_SpecialisedTupleObject: @@ -88,7 +85,7 @@ assert len(t) == 2 def test_notspecialisedtuple(self): - assert not self.isspecialised((42,43,44,45)) + assert not self.isspecialised((42, 43, 44, 45)) assert not self.isspecialised((1.5,)) def test_slicing_to_specialised(self): @@ -118,66 +115,66 @@ c = (2, 1) assert not a == c - def test_eq_can_delegate(self): - a = (1,2) - b = (1,3,2) + def test_eq_can_delegate(self): + a = (1, 2) + b = (1, 3, 2) assert not a == b values = [2, 2L, 2.0, 1, 1L, 1.0] for x in values: for y in values: - assert ((1,2) == (x,y)) == (1 == x and 2 == y) + assert ((1, 2) == (x, y)) == (1 == x and 2 == y) def test_neq(self): - a = (1,2) + a = (1, 2) b = (1,) - b = b+(2,) + b = b + (2,) assert not a != b - - c = (1,3) + + c = (1, 3) assert a != c - + def test_ordering(self): - a = (1,2) - assert a < (2,2) - assert a < (1,3) - assert not a < (1,2) + a = (1, 2) + assert a < (2, 2) + assert a < (1, 3) + assert not a < (1, 2) - assert a <= (2,2) - assert a <= (1,2) - assert not a <= (1,1) - - assert a >= (0,2) - assert a >= (1,2) - assert not a >= (1,3) - - assert a > (0,2) - assert a > (1,1) - assert not a > (1,3) + assert a <= (2, 2) + assert a <= (1, 2) + assert not a <= (1, 1) - assert (2,2) > a - assert (1,3) > a - assert not (1,2) > a - - assert (2,2) >= a - assert (1,2) >= a - assert not (1,1) >= a - - assert (0,2) <= a - assert (1,2) <= a - assert not (1,3) <= a - - assert (0,2) < a - assert (1,1) < a - assert not (1,3) < a + assert a >= (0, 2) + assert a >= (1, 2) + assert not a >= (1, 3) + + assert a > (0, 2) + assert a > (1, 1) + assert not a > (1, 3) + + assert (2, 2) > a + assert (1, 3) > a + assert not (1, 2) > a + + assert (2, 2) >= a + assert (1, 2) >= a + assert not (1, 1) >= a + + assert (0, 2) <= a + assert (1, 2) <= a + assert not (1, 3) <= a + + assert (0, 2) < a + assert (1, 1) < a + assert not (1, 3) < a def test_hash(self): - a = (1,2) + a = (1, 2) b = (1,) - b += (2,) # else a and b refer to same constant + b += (2,) # else a and b refer to same constant assert hash(a) == hash(b) - c = (2,4) + c = (2, 4) assert hash(a) != hash(c) assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L)) diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -1,17 +1,16 @@ -#from __future__ import nested_scopes +from pypy.interpreter.error import OperationError from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.interpreter.error import OperationError + class TestW_TupleObject: - def test_is_true(self): w = self.space.wrap w_tuple = W_TupleObject([]) - assert self.space.is_true(w_tuple) == False + assert self.space.is_true(w_tuple) is False w_tuple = W_TupleObject([w(5)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True w_tuple = W_TupleObject([w(5), w(3)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True def test_len(self): w = self.space.wrap @@ -19,7 +18,7 @@ assert self.space.eq_w(self.space.len(w_tuple), w(0)) w_tuple = W_TupleObject([w(5)]) assert self.space.eq_w(self.space.len(w_tuple), w(1)) - w_tuple = W_TupleObject([w(5), w(3), w(99)]*111) + w_tuple = W_TupleObject([w(5), w(3), w(99)] * 111) assert self.space.eq_w(self.space.len(w_tuple), w(333)) def test_getitem(self): @@ -65,7 +64,7 @@ w_tuple2 = W_TupleObject([w(-7)] * 111) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple1), W_TupleObject([w(5), w(3), w(99), - w(5), w(3), w(99)])) + w(5), w(3), w(99)])) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple2), W_TupleObject([w(5), w(3), w(99)] + [w(-7)] * 111)) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple0), w_tuple1) @@ -77,7 +76,7 @@ arg = w(2) n = 3 w_tup = W_TupleObject([arg]) - w_tup3 = W_TupleObject([arg]*n) + w_tup3 = W_TupleObject([arg] * n) w_res = self.space.mul(w_tup, w(n)) assert self.space.eq_w(w_tup3, w_res) # commute @@ -91,26 +90,26 @@ w = self.space.wrap def test1(testtuple, start, stop, step, expected): - w_slice = self.space.newslice(w(start), w(stop), w(step)) + w_slice = self.space.newslice(w(start), w(stop), w(step)) w_tuple = W_TupleObject([w(i) for i in testtuple]) w_result = self.space.getitem(w_tuple, w_slice) assert self.space.unwrap(w_result) == expected - - for testtuple in [(), (5,3,99), tuple(range(5,555,10))]: + + for testtuple in [(), (5, 3, 99), tuple(range(5, 555, 10))]: for start in [-2, -1, 0, 1, 10]: for end in [-1, 0, 2, 999]: test1(testtuple, start, end, 1, testtuple[start:end]) - test1((5,7,1,4), 3, 1, -2, (4,)) - test1((5,7,1,4), 3, 0, -2, (4, 7)) - test1((5,7,1,4), 3, -1, -2, ()) - test1((5,7,1,4), -2, 11, 2, (1,)) - test1((5,7,1,4), -3, 11, 2, (7, 4)) - test1((5,7,1,4), -5, 11, 2, (5, 1)) + test1((5, 7, 1, 4), 3, 1, -2, (4,)) + test1((5, 7, 1, 4), 3, 0, -2, (4, 7)) + test1((5, 7, 1, 4), 3, -1, -2, ()) + test1((5, 7, 1, 4), -2, 11, 2, (1,)) + test1((5, 7, 1, 4), -3, 11, 2, (7, 4)) + test1((5, 7, 1, 4), -5, 11, 2, (5, 1)) def test_eq(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -126,9 +125,10 @@ self.space.w_True) assert self.space.eq_w(self.space.eq(w_tuple2, w_tuple3), self.space.w_False) + def test_ne(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -144,9 +144,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ne(w_tuple2, w_tuple3), self.space.w_True) + def test_lt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -165,10 +166,10 @@ self.space.w_True) assert self.space.eq_w(self.space.lt(w_tuple4, w_tuple3), self.space.w_True) - + def test_ge(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -187,10 +188,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ge(w_tuple4, w_tuple3), self.space.w_False) - + def test_gt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -209,10 +210,10 @@ self.space.w_False) assert self.space.eq_w(self.space.gt(w_tuple4, w_tuple3), self.space.w_False) - + def test_le(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -234,28 +235,27 @@ class AppTestW_TupleObject: - def test_is_true(self): assert not () assert (5,) - assert (5,3) + assert (5, 3) def test_len(self): assert len(()) == 0 assert len((5,)) == 1 - assert len((5,3,99,1,2,3,4,5,6)) == 9 + assert len((5, 3, 99, 1, 2, 3, 4, 5, 6)) == 9 def test_getitem(self): - assert (5,3)[0] == 5 - assert (5,3)[1] == 3 - assert (5,3)[-1] == 3 - assert (5,3)[-2] == 5 - raises(IndexError, "(5,3)[2]") + assert (5, 3)[0] == 5 + assert (5, 3)[1] == 3 + assert (5, 3)[-1] == 3 + assert (5, 3)[-2] == 5 + raises(IndexError, "(5, 3)[2]") raises(IndexError, "(5,)[1]") raises(IndexError, "()[0]") def test_iter(self): - t = (5,3,99) + t = (5, 3, 99) i = iter(t) assert i.next() == 5 assert i.next() == 3 @@ -263,7 +263,7 @@ raises(StopIteration, i.next) def test_contains(self): - t = (5,3,99) + t = (5, 3, 99) assert 5 in t assert 99 in t assert not 11 in t @@ -271,35 +271,35 @@ def test_add(self): t0 = () - t1 = (5,3,99) + t1 = (5, 3, 99) assert t0 + t0 == t0 assert t1 + t0 == t1 - assert t1 + t1 == (5,3,99,5,3,99) + assert t1 + t1 == (5, 3, 99, 5, 3, 99) def test_mul(self): assert () * 10 == () - assert (5,) * 3 == (5,5,5) - assert (5,2) * 2 == (5,2,5,2) + assert (5,) * 3 == (5, 5, 5) + assert (5, 2) * 2 == (5, 2, 5, 2) def test_mul_identity(self): - t = (1,2,3) + t = (1, 2, 3) assert (t * 1) is t def test_mul_subtype(self): class T(tuple): pass - t = T([1,2,3]) + t = T([1, 2, 3]) assert (t * 1) is not t assert (t * 1) == t def test_getslice_2(self): - assert (5,2,3)[1:2] == (2,) + assert (5, 2, 3)[1:2] == (2,) def test_eq(self): t0 = () - t1 = (5,3,99) - t2 = (5,3,99) - t3 = (5,3,99,-1) - t4 = (5,3,9,1) + t1 = (5, 3, 99) + t2 = (5, 3, 99) + t3 = (5, 3, 99, -1) + t4 = (5, 3, 9, 1) assert not t0 == t1 assert t0 != t1 assert t1 == t2 @@ -321,15 +321,15 @@ # check that hash behaves as in 2.4 for at least 31 bits assert hash(()) & 0x7fffffff == 0x35d373 assert hash((12,)) & 0x7fffffff == 0x1cca0557 - assert hash((12,34)) & 0x7fffffff == 0x153e2a41 + assert hash((12, 34)) & 0x7fffffff == 0x153e2a41 def test_getnewargs(self): - assert () .__getnewargs__() == ((),) + assert () .__getnewargs__() == ((),) def test_repr(self): assert repr((1,)) == '(1,)' assert repr(()) == '()' - assert repr((1,2,3)) == '(1, 2, 3)' + assert repr((1, 2, 3)) == '(1, 2, 3)' def test_getslice(self): assert ('a', 'b', 'c').__getslice__(-17, 2) == ('a', 'b') From noreply at buildbot.pypy.org Wed May 22 11:50:09 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 11:50:09 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Rewrite test_hash_against_normal_tuple() to use one object space. Message-ID: <20130522095009.C34201C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64431:fc48231969c9 Date: 2013-05-22 11:29 +0200 http://bitbucket.org/pypy/pypy/changeset/fc48231969c9/ Log: Rewrite test_hash_against_normal_tuple() to use one object space. diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -24,20 +24,18 @@ assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii' def test_hash_against_normal_tuple(self): - N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": False}) - S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) - def hash_test(values, must_be_specialized=True): - N_values_w = [N_space.wrap(value) for value in values] - S_values_w = [S_space.wrap(value) for value in values] - N_w_tuple = N_space.newtuple(N_values_w) - S_w_tuple = S_space.newtuple(S_values_w) + N_values_w = [self.space.wrap(value) for value in values] + S_values_w = [self.space.wrap(value) for value in values] + N_w_tuple = W_TupleObject(N_values_w) + S_w_tuple = self.space.newtuple(S_values_w) if must_be_specialized: assert 'W_SpecialisedTupleObject' in type(S_w_tuple).__name__ - assert isinstance(N_w_tuple, W_TupleObject) - assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) - assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) + assert self.space.is_true(self.space.eq(N_w_tuple, S_w_tuple)) + assert self.space.is_true( + self.space.eq(self.space.hash(N_w_tuple), + self.space.hash(S_w_tuple))) hash_test([1, 2]) hash_test([1.5, 2.8]) From noreply at buildbot.pypy.org Wed May 22 11:50:11 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 11:50:11 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Fix string methods that take tuples as arguments (eg. 'ab'.startswith(('a', 'b'))). Message-ID: <20130522095011.02F381C01AB@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64432:81de1c3de10f Date: 2013-05-22 11:47 +0200 http://bitbucket.org/pypy/pypy/changeset/81de1c3de10f/ Log: Fix string methods that take tuples as arguments (eg. 'ab'.startswith(('a', 'b'))). diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -14,7 +14,7 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -310,31 +310,30 @@ w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): + if isinstance(w_prefix, W_AbstractTupleObject): + w_str = str__Bytearray(space, w_bytearray) + w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.unpackiterable(w_prefix)]) + return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + w_start, w_stop) + w_prefix = space.wrap(space.bufferstr_new_w(w_prefix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) -def str_startswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_prefix)]) - return stringobject.str_startswith__String_Tuple_ANY_ANY(space, w_str, w_prefix, - w_start, w_stop) - def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): + if isinstance(w_suffix, W_AbstractTupleObject): + w_str = str__Bytearray(space, w_bytearray) + w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.unpackiterable(w_suffix)]) + return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) -def str_endswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_suffix)]) - return stringobject.str_endswith__String_Tuple_ANY_ANY(space, w_str, w_suffix, - w_start, w_stop) - def str_join__Bytearray_ANY(space, w_self, w_list): list_w = space.listview(w_list) if not list_w: diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -12,7 +12,7 @@ from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringtype import ( joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from rpython.rlib import jit from rpython.rlib.objectmodel import ( compute_hash, compute_unique_id, specialize) @@ -684,7 +684,9 @@ w_end, True) return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) -def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): +def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): + if not isinstance(w_suffixes, W_AbstractTupleObject): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): @@ -702,7 +704,9 @@ w_end, True) return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) -def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): +def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): + if not isinstance(w_prefixes, W_AbstractTupleObject): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -12,7 +12,7 @@ W_StringObject, make_rsplit_with_delim) from pypy.objspace.std.stringtype import stringendswith, stringstartswith from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.objectmodel import ( @@ -501,8 +501,10 @@ # with additional parameters as rpython) return space.newbool(stringstartswith(self, w_substr._value, start, end)) -def unicode_startswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_prefixes, +def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_prefixes, w_start, w_end): + if not isinstance(w_prefixes, W_AbstractTupleObject): + raise FailedToImplement unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): @@ -511,8 +513,10 @@ return space.w_True return space.w_False -def unicode_endswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_suffixes, +def unicode_endswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_suffixes, w_start, w_end): + if not isinstance(w_suffixes, W_AbstractTupleObject): + raise FailedToImplement unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): From noreply at buildbot.pypy.org Wed May 22 11:56:39 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 11:56:39 +0200 (CEST) Subject: [pypy-commit] pypy default: kill tabs Message-ID: <20130522095639.915EA1C0F0F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64433:c75a14958ada Date: 2013-05-22 11:55 +0200 http://bitbucket.org/pypy/pypy/changeset/c75a14958ada/ Log: kill tabs diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -277,8 +277,8 @@ ChoiceOption("platform", "target platform", ['host'] + PLATFORMS, default='host', cmdline='--platform', - requires={"arm": [("translation.gcrootfinder", "shadowstack")]}, - suggests={"arm": [("translation.jit_backend", "arm")]}), + requires={"arm": [("translation.gcrootfinder", "shadowstack")]}, + suggests={"arm": [("translation.jit_backend", "arm")]}), ]) From noreply at buildbot.pypy.org Wed May 22 12:07:52 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 12:07:52 +0200 (CEST) Subject: [pypy-commit] pypy arm-stacklet: merge default Message-ID: <20130522100752.2DE0E1C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-stacklet Changeset: r64434:32e7e7d6593f Date: 2013-05-22 04:56 -0500 http://bitbucket.org/pypy/pypy/changeset/32e7e7d6593f/ Log: merge default diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,12 +124,14 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - os_thread.setup_threads(space) - rffi.aroundstate.before() + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - rthread.gc_thread_start() + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -9,8 +9,8 @@ # ____________________________________________________________ - at unwrap_spec(w_depth = WrappedDefault(0)) -def _getframe(space, w_depth): + at unwrap_spec(depth=int) +def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default @@ -18,7 +18,6 @@ This function should be used for internal and specialized purposes only.""" - depth = space.int_w(w_depth) if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -13,9 +13,9 @@ DEFL_GC = "minimark" if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" + DEFL_ROOTFINDER = "asmgcc" else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + DEFL_ROOTFINDER = "shadowstack" IS_64_BITS = sys.maxint > 2147483647 @@ -89,7 +89,7 @@ ChoiceOption("gcrootfinder", "Strategy for finding GC Roots (framework GCs only)", ["n/a", "shadowstack", "asmgcc"], - "shadowstack", + DEFL_ROOTFINDER, cmdline="--gcrootfinder", requires={ "shadowstack": [("translation.gctransformer", "framework")], @@ -112,7 +112,7 @@ BoolOption("jit", "generate a JIT", default=False, suggests=[("translation.gc", DEFL_GC), - ("translation.gcrootfinder", DEFL_ROOTFINDER_WITHJIT), + ("translation.gcrootfinder", DEFL_ROOTFINDER), ("translation.list_comprehension_operations", True)]), ChoiceOption("jit_backend", "choose the backend for the JIT", ["auto", "x86", "x86-without-sse2", 'arm'], @@ -276,7 +276,9 @@ ]), ChoiceOption("platform", "target platform", ['host'] + PLATFORMS, default='host', - cmdline='--platform'), + cmdline='--platform', + requires={"arm": [("translation.gcrootfinder", "shadowstack")]}, + suggests={"arm": [("translation.jit_backend", "arm")]}), ]) diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1053,9 +1053,10 @@ @arguments("box", "orgpc") def opimpl_raise(self, exc_value_box, orgpc): # xxx hack - clsbox = self.cls_of_box(exc_value_box) - self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], - resumepc=orgpc) + if not self.metainterp.heapcache.is_class_known(exc_value_box): + clsbox = self.cls_of_box(exc_value_box) + self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], + resumepc=orgpc) self.metainterp.class_of_last_exc_is_const = True self.metainterp.last_exc_value_box = exc_value_box self.metainterp.popframe() @@ -1876,7 +1877,9 @@ self.staticdata.warmrunnerdesc.hooks.on_abort(reason, jd_sd.jitdriver, greenkey, - jd_sd.warmstate.get_location_str(greenkey)) + jd_sd.warmstate.get_location_str(greenkey), + self.staticdata.logger_ops._make_log_operations(), + self.history.operations) self.staticdata.stats.aborted() def blackhole_if_trace_too_long(self): diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -7,18 +7,20 @@ from rpython.rtyper.annlowlevel import hlstr from rpython.jit.metainterp.jitprof import Profiler + class JitHookInterfaceTests(object): # !!!note!!! - don't subclass this from the backend. Subclass the LL # class later instead def test_abort_quasi_immut(self): reasons = [] - + class MyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): assert jitdriver is myjitdriver assert len(greenkey) == 1 reasons.append(reason) assert greenkey_repr == 'blah' + assert len(operations) > 1 iface = MyJitIface() @@ -27,8 +29,10 @@ class Foo: _immutable_fields_ = ['a?'] + def __init__(self, a): self.a = a + def f(a, x): foo = Foo(a) total = 0 @@ -47,7 +51,7 @@ def test_on_compile(self): called = [] - + class MyJitIface(JitHookInterface): def after_compile(self, di): called.append(("compile", di.greenkey[1].getint(), diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -5,8 +5,6 @@ from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rstring import StringBuilder -import py - class TestLLtype(LLJitMixin): def test_dont_record_repeated_guard_class(self): @@ -628,3 +626,22 @@ res = self.interp_operations(fn, [0]) assert res == 1 self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0) + + def test_raise_known_class_no_guard_class(self): + def raise_exc(cls): + raise cls + + def fn(n): + if n: + cls = ValueError + else: + cls = TypeError + try: + raise_exc(cls) + except ValueError: + return -1 + return n + + res = self.interp_operations(fn, [1]) + assert res == -1 + self.check_operations_history(guard_class=0) diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py --- a/rpython/jit/metainterp/virtualizable.py +++ b/rpython/jit/metainterp/virtualizable.py @@ -231,6 +231,10 @@ self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): + """ + Returns whether or not the virtualizable was forced during a + CALL_MAY_FORCE. + """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -926,7 +926,7 @@ of JIT running like JIT loops compiled, aborts etc. An instance of this class will be available as policy.jithookiface. """ - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): """ A hook called each time a loop is aborted with jitdriver and greenkey where it started, reason is a string why it got aborted """ diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -1,11 +1,10 @@ +from rpython.annotator import model as annmodel +from rpython.rlib.objectmodel import specialize +from rpython.rtyper.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance, llstr) +from rpython.rtyper.extregistry import ExtRegistryEntry +from rpython.rtyper.lltypesystem import llmemory, lltype, rclass -from rpython.rtyper.extregistry import ExtRegistryEntry -from rpython.annotator import model as annmodel -from rpython.rtyper.lltypesystem import llmemory, lltype -from rpython.rtyper.lltypesystem import rclass -from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr,\ - cast_base_ptr_to_instance, llstr -from rpython.rlib.objectmodel import specialize def register_helper(s_result): def wrapper(helper): diff --git a/rpython/tool/error.py b/rpython/tool/error.py --- a/rpython/tool/error.py +++ b/rpython/tool/error.py @@ -2,11 +2,15 @@ """ error handling features, just a way of displaying errors """ -from rpython.tool.ansi_print import ansi_log -from rpython.flowspace.model import Variable import sys import py + +from rpython.flowspace.model import Variable +from rpython.rlib import jit +from rpython.tool.ansi_print import ansi_log + + log = py.log.Producer("error") py.log.setconsumer("error", ansi_log) @@ -14,7 +18,8 @@ SHOW_ANNOTATIONS = True SHOW_DEFAULT_LINES_OF_CODE = 0 -def source_lines1(graph, block, operindex=None, offset=None, long=False, \ + +def source_lines1(graph, block, operindex=None, offset=None, long=False, show_lines_of_code=SHOW_DEFAULT_LINES_OF_CODE): if block is not None: if block is graph.returnblock: @@ -32,23 +37,24 @@ else: if block is None or not block.operations: return [] + def toline(operindex): return offset2lineno(graph.func.func_code, block.operations[operindex].offset) if operindex is None: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) if not long: return ['?'] here = None else: operline = toline(operindex) if long: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) here = operline else: linerange = (operline, operline) here = None lines = ["Happened at file %s line %d" % (graph.filename, here or linerange[0]), ""] - for n in range(max(0, linerange[0]-show_lines_of_code), \ + for n in range(max(0, linerange[0]-show_lines_of_code), min(linerange[1]+1+show_lines_of_code, len(graph_lines)+graph.startline)): if n == here: prefix = '==> ' @@ -136,6 +142,7 @@ from rpython.translator.tool.pdbplus import PdbPlusShow from rpython.translator.driver import log t = drv.translator + class options: huge = 100 @@ -161,6 +168,7 @@ pdb_plus_show.start(tb) + at jit.elidable def offset2lineno(c, stopat): tab = c.co_lnotab line = c.co_firstlineno @@ -170,4 +178,4 @@ if addr > stopat: break line = line + ord(tab[i+1]) - return line \ No newline at end of file + return line From noreply at buildbot.pypy.org Wed May 22 12:07:53 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 12:07:53 +0200 (CEST) Subject: [pypy-commit] pypy arm-stacklet: enable this test again Message-ID: <20130522100753.94DDC1C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-stacklet Changeset: r64435:1055671d633b Date: 2013-05-22 05:01 -0500 http://bitbucket.org/pypy/pypy/changeset/1055671d633b/ Log: enable this test again diff --git a/rpython/rlib/test/test_rstacklet.py b/rpython/rlib/test/test_rstacklet.py --- a/rpython/rlib/test/test_rstacklet.py +++ b/rpython/rlib/test/test_rstacklet.py @@ -65,7 +65,7 @@ self.tasks[0].withdepth(self.random.genrand32() % 50) assert len(self.tasks[0].lst) == 0 - #@here_is_a_test + @here_is_a_test def test_destroy(self): # this used to give MemoryError in shadowstack tests for i in range(100000): From noreply at buildbot.pypy.org Wed May 22 12:07:55 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 12:07:55 +0200 (CEST) Subject: [pypy-commit] pypy arm-stacklet: close to be merged branch Message-ID: <20130522100755.0189C1C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: arm-stacklet Changeset: r64436:a4532b161f42 Date: 2013-05-22 05:02 -0500 http://bitbucket.org/pypy/pypy/changeset/a4532b161f42/ Log: close to be merged branch From noreply at buildbot.pypy.org Wed May 22 12:07:56 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 12:07:56 +0200 (CEST) Subject: [pypy-commit] pypy default: merge arm-stacklet Message-ID: <20130522100756.81CA41C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64437:fc98eb924881 Date: 2013-05-22 05:04 -0500 http://bitbucket.org/pypy/pypy/changeset/fc98eb924881/ Log: merge arm-stacklet diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -364,8 +364,6 @@ # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] - if config.translation.platform == 'arm' and '_continuation' in modules: - modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/rpython/translator/c/src/stacklet/slp_platformselect.h b/rpython/translator/c/src/stacklet/slp_platformselect.h --- a/rpython/translator/c/src/stacklet/slp_platformselect.h +++ b/rpython/translator/c/src/stacklet/slp_platformselect.h @@ -8,6 +8,8 @@ #include "switch_x86_64_gcc.h" /* gcc on amd64 */ #elif defined(__GNUC__) && defined(__i386__) #include "switch_x86_gcc.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__arm__) +#include "switch_arm_gcc.h" /* gcc on arm */ #else #error "Unsupported platform!" #endif diff --git a/rpython/translator/c/src/stacklet/switch_arm_gcc.h b/rpython/translator/c/src/stacklet/switch_arm_gcc.h new file mode 100644 --- /dev/null +++ b/rpython/translator/c/src/stacklet/switch_arm_gcc.h @@ -0,0 +1,40 @@ + +static void __attribute__((optimize("O3"))) *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra) +{ + void *result; + __asm__ volatile ( + "mov r3, %[save_state]\n" + /* save values in calee saved registers for later */ + "mov r4, %[restore_state]\n" + "mov r5, %[extra]\n" + "mov r0, sp\n" /* arg 1: current (old) stack pointer */ + "mov r1, r5\n" /* arg 2: extra */ + "blx r3\n" /* call save_state() */ + + /* skip the rest if the return value is null */ + "cmp r0, #0\n" + "beq zero\n" + + "mov sp, r0\n" /* change the stack pointer */ + + /* From now on, the stack pointer is modified, but the content of the + stack is not restored yet. It contains only garbage here. */ + "mov r1, r5\n" /* arg 2: extra */ + /* arg 1: current (new) stack pointer is already in r0*/ + "blx r4\n" /* call restore_state() */ + + /* The stack's content is now restored. */ + "zero:\n" + "mov %[result], r0\n" + + : [result]"=r"(result) /* output variables */ + /* input variables */ + : [restore_state]"r"(restore_state), + [save_state]"r"(save_state), + [extra]"r"(extra) + : "lr", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r13" + ); + return result; +} From noreply at buildbot.pypy.org Wed May 22 12:07:58 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 12:07:58 +0200 (CEST) Subject: [pypy-commit] pypy default: update whatsnew Message-ID: <20130522100758.01FCC1C01AB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64438:536ce5675cf1 Date: 2013-05-22 05:05 -0500 http://bitbucket.org/pypy/pypy/changeset/536ce5675cf1/ Log: update whatsnew 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 @@ -25,3 +25,6 @@ .. branch: remove-list-smm-2 Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support From noreply at buildbot.pypy.org Wed May 22 12:09:29 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 22 May 2013 12:09:29 +0200 (CEST) Subject: [pypy-commit] pypy default: Improve to report missing-in-the-current-branch merges only. Message-ID: <20130522100929.E014A1C0328@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64439:ebf947247f97 Date: 2013-05-22 12:08 +0200 http://bitbucket.org/pypy/pypy/changeset/ebf947247f97/ Log: Improve to report missing-in-the-current-branch merges only. It prevents test_whatnew.py from suddenly failing on some older unmodified branch just by changes on default. diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged From noreply at buildbot.pypy.org Wed May 22 12:19:17 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 12:19:17 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Use space.isinstance_w(x, space.w_tuple) instead of isinstance(x, W_AbstractTupleObject). Message-ID: <20130522101917.876971C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64440:463087e7703f Date: 2013-05-22 12:17 +0200 http://bitbucket.org/pypy/pypy/changeset/463087e7703f/ Log: Use space.isinstance_w(x, space.w_tuple) instead of isinstance(x, W_AbstractTupleObject). diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -14,7 +14,6 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -310,10 +309,10 @@ w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - if isinstance(w_prefix, W_AbstractTupleObject): + if space.isinstance_w(w_prefix, space.w_tuple): w_str = str__Bytearray(space, w_bytearray) w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_prefix)]) + space.fixedview(w_prefix)]) return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) @@ -323,10 +322,10 @@ w_start, w_stop) def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): - if isinstance(w_suffix, W_AbstractTupleObject): + if space.isinstance_w(w_suffix, space.w_tuple): w_str = str__Bytearray(space, w_bytearray) w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_suffix)]) + space.fixedview(w_suffix)]) return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -12,7 +12,6 @@ from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringtype import ( joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) -from pypy.objspace.std.tupleobject import W_AbstractTupleObject from rpython.rlib import jit from rpython.rlib.objectmodel import ( compute_hash, compute_unique_id, specialize) @@ -685,7 +684,7 @@ return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): - if not isinstance(w_suffixes, W_AbstractTupleObject): + if not space.isinstance_w(w_suffixes, space.w_tuple): raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) @@ -705,7 +704,7 @@ return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): - if not isinstance(w_prefixes, W_AbstractTupleObject): + if not space.isinstance_w(w_prefixes, space.w_tuple): raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -12,7 +12,6 @@ W_StringObject, make_rsplit_with_delim) from pypy.objspace.std.stringtype import stringendswith, stringstartswith from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.tupleobject import W_AbstractTupleObject from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.objectmodel import ( @@ -503,7 +502,7 @@ def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_prefixes, w_start, w_end): - if not isinstance(w_prefixes, W_AbstractTupleObject): + if not space.isinstance_w(w_prefixes, space.w_tuple): raise FailedToImplement unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) @@ -515,7 +514,7 @@ def unicode_endswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_suffixes, w_start, w_end): - if not isinstance(w_suffixes, W_AbstractTupleObject): + if not space.isinstance_w(w_suffixes, space.w_tuple): raise FailedToImplement unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) From noreply at buildbot.pypy.org Wed May 22 13:28:33 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 13:28:33 +0200 (CEST) Subject: [pypy-commit] pypy default: add missing architecture check (thanks tumbleweed) Message-ID: <20130522112833.6883E1C331B@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64441:9eb1a83630fe Date: 2013-05-22 13:27 +0200 http://bitbucket.org/pypy/pypy/changeset/9eb1a83630fe/ Log: add missing architecture check (thanks tumbleweed) diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -3,6 +3,8 @@ from rpython.config.config import ChoiceOption, StrOption, Config from rpython.config.config import ConfigError from rpython.config.support import detect_number_of_processors +from rpython.jit.backend.detect_cpu import autodetect +from rpython.jit.backend.detect_cpu import MODEL_X86, MODEL_X86_NO_SSE2, MODEL_X86_64 DEFL_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() # and just small enough to prevend inlining of some rlist functions. @@ -12,7 +14,10 @@ DEFL_LOW_INLINE_THRESHOLD = DEFL_INLINE_THRESHOLD / 2.0 DEFL_GC = "minimark" -if sys.platform.startswith("linux"): + +_is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) + +if sys.platform.startswith("linux") and _is_x86: DEFL_ROOTFINDER = "asmgcc" else: DEFL_ROOTFINDER = "shadowstack" From noreply at buildbot.pypy.org Wed May 22 13:44:04 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 22 May 2013 13:44:04 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changed the smalltalk value of the pc for returned, shadowed contexts to w_nil Message-ID: <20130522114404.B763C1C0F0F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r401:44ff7eb950d2 Date: 2013-05-22 09:46 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/44ff7eb950d2/ Log: changed the smalltalk value of the pc for returned, shadowed contexts to w_nil diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -560,9 +560,12 @@ def wrap_pc(self): pc = self.pc() - pc += 1 - pc += self.s_method().bytecodeoffset - return self.space.wrap_int(pc) + if pc == -1: + return self.space.w_nil + else: + pc += 1 + pc += self.s_method().bytecodeoffset + return self.space.wrap_int(pc) def pc(self): return self._pc diff --git a/spyvm/test/test_shadow.py b/spyvm/test/test_shadow.py --- a/spyvm/test/test_shadow.py +++ b/spyvm/test/test_shadow.py @@ -275,3 +275,10 @@ assert s_class.lookup(key) is w_method.as_compiledmethod_get_shadow(space) assert s_class.version is not version assert s_class.version is w_parent.as_class_get_shadow(space).version + +def test_returned_contexts_pc(): + w_context = methodcontext() + s_context = w_context.as_methodcontext_get_shadow(space) + assert w_context.fetch(space, constants.CTXPART_PC_INDEX) is not space.w_nil + s_context.mark_returned() + assert w_context.fetch(space, constants.CTXPART_PC_INDEX) is space.w_nil From noreply at buildbot.pypy.org Wed May 22 13:44:06 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 22 May 2013 13:44:06 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed the bug that contexts which are marked returned by Smalltalk-code are not really dead... Message-ID: <20130522114406.365A71C0F0F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r402:76af22274477 Date: 2013-05-22 13:43 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/76af22274477/ Log: fixed the bug that contexts which are marked returned by Smalltalk- code are not really dead... diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -552,11 +552,12 @@ def store_unwrap_pc(self, w_pc): if w_pc.is_same_object(self.space.w_nil): - return - pc = self.space.unwrap_int(w_pc) - pc -= self.s_method().bytecodeoffset - pc -= 1 - self.store_pc(pc) + self.store_pc(-1) + else: + pc = self.space.unwrap_int(w_pc) + pc -= self.s_method().bytecodeoffset + pc -= 1 + self.store_pc(pc) def wrap_pc(self): pc = self.pc() From noreply at buildbot.pypy.org Wed May 22 14:03:26 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 14:03:26 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Correctly wrap tuples. Message-ID: <20130522120326.35D4F1C0F0F@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64442:3bdb25b6cbd4 Date: 2013-05-22 12:21 +0200 http://bitbucket.org/pypy/pypy/changeset/3bdb25b6cbd4/ Log: Correctly wrap tuples. diff --git a/pypy/objspace/std/test/test_lengthhint.py b/pypy/objspace/std/test/test_lengthhint.py --- a/pypy/objspace/std/test/test_lengthhint.py +++ b/pypy/objspace/std/test/test_lengthhint.py @@ -74,7 +74,7 @@ self._test_length_hint(self.space.wrap(u'Y' * self.SIZE)) def test_tuple(self): - self._test_length_hint(self.space.newtuple(self.ITEMS)) + self._test_length_hint(self.space.wrap(tuple(self.ITEMS))) def test_reversed(self): # test the generic reversed iterator (w_foo lacks __reversed__) From noreply at buildbot.pypy.org Wed May 22 14:03:27 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 14:03:27 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Skip this test for now. Message-ID: <20130522120327.DF9881C0F0F@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64443:6434342f6b11 Date: 2013-05-22 12:55 +0200 http://bitbucket.org/pypy/pypy/changeset/6434342f6b11/ Log: Skip this test for now. diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py --- a/pypy/objspace/std/test/test_stdobjspace.py +++ b/pypy/objspace/std/test/test_stdobjspace.py @@ -37,6 +37,7 @@ assert space.sliceindices(w_obj, w(3)) == (1,2,3) def test_fastpath_isinstance(self): + py.test.skip("skipped until SMMs are removed") from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.iterobject import W_AbstractSeqIterObject From noreply at buildbot.pypy.org Wed May 22 14:19:46 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 14:19:46 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Fix tuple marshalling. Message-ID: <20130522121946.D7EC31C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64444:915695333aec Date: 2013-05-22 14:07 +0200 http://bitbucket.org/pypy/pypy/changeset/915695333aec/ Log: Fix tuple marshalling. diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -23,7 +23,7 @@ from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.floatobject import W_FloatObject -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject @@ -288,14 +288,17 @@ raise_exception(space, 'bad marshal data') register(TYPE_STRINGREF, unmarshal_stringref) -def marshal_w__Tuple(space, w_tuple, m): - items = w_tuple.wrappeditems +def marshal_tuple(space, w_tuple, m): + if not isinstance(w_tuple, W_AbstractTupleObject): + raise_exception(space, "unmarshallable object") + items = w_tuple.tolist() m.put_tuple_w(TYPE_TUPLE, items) +handled_by_any.append(('tuple', marshal_tuple)) -def unmarshal_Tuple(space, u, tc): +def unmarshal_tuple(space, u, tc): items_w = u.get_tuple_w() return space.newtuple(items_w) -register(TYPE_TUPLE, unmarshal_Tuple) +register(TYPE_TUPLE, unmarshal_tuple) def marshal_list(space, w_list, m): if not isinstance(w_list, W_ListObject): From noreply at buildbot.pypy.org Wed May 22 14:19:49 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 14:19:49 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove unnecessary import that broke tests. Message-ID: <20130522121949.108D01C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64445:82898009fe76 Date: 2013-05-22 14:13 +0200 http://bitbucket.org/pypy/pypy/changeset/82898009fe76/ Log: Remove unnecessary import that broke tests. diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") From noreply at buildbot.pypy.org Wed May 22 14:21:02 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 14:21:02 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: hg merge default Message-ID: <20130522122102.626031C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64446:dda491285391 Date: 2013-05-22 14:19 +0200 http://bitbucket.org/pypy/pypy/changeset/dda491285391/ Log: hg merge default diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -364,8 +364,6 @@ # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] - if config.translation.platform == 'arm' and '_continuation' in modules: - modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -22,3 +22,9 @@ .. branch: remove-dict-smm Remove multi-methods on dict + +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,12 +124,14 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - os_thread.setup_threads(space) - rffi.aroundstate.before() + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - rthread.gc_thread_start() + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), 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 @@ -344,7 +344,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1, external=False) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -9,8 +9,8 @@ # ____________________________________________________________ - at unwrap_spec(w_depth = WrappedDefault(0)) -def _getframe(space, w_depth): + at unwrap_spec(depth=int) +def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default @@ -18,7 +18,6 @@ This function should be used for internal and specialized purposes only.""" - depth = space.int_w(w_depth) if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -3,6 +3,8 @@ from rpython.config.config import ChoiceOption, StrOption, Config from rpython.config.config import ConfigError from rpython.config.support import detect_number_of_processors +from rpython.jit.backend.detect_cpu import autodetect +from rpython.jit.backend.detect_cpu import MODEL_X86, MODEL_X86_NO_SSE2, MODEL_X86_64 DEFL_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() # and just small enough to prevend inlining of some rlist functions. @@ -12,10 +14,13 @@ DEFL_LOW_INLINE_THRESHOLD = DEFL_INLINE_THRESHOLD / 2.0 DEFL_GC = "minimark" -if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" + +_is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) + +if sys.platform.startswith("linux") and _is_x86: + DEFL_ROOTFINDER = "asmgcc" else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + DEFL_ROOTFINDER = "shadowstack" IS_64_BITS = sys.maxint > 2147483647 @@ -89,7 +94,7 @@ ChoiceOption("gcrootfinder", "Strategy for finding GC Roots (framework GCs only)", ["n/a", "shadowstack", "asmgcc"], - "shadowstack", + DEFL_ROOTFINDER, cmdline="--gcrootfinder", requires={ "shadowstack": [("translation.gctransformer", "framework")], @@ -112,7 +117,7 @@ BoolOption("jit", "generate a JIT", default=False, suggests=[("translation.gc", DEFL_GC), - ("translation.gcrootfinder", DEFL_ROOTFINDER_WITHJIT), + ("translation.gcrootfinder", DEFL_ROOTFINDER), ("translation.list_comprehension_operations", True)]), ChoiceOption("jit_backend", "choose the backend for the JIT", ["auto", "x86", "x86-without-sse2", 'arm'], @@ -276,7 +281,9 @@ ]), ChoiceOption("platform", "target platform", ['host'] + PLATFORMS, default='host', - cmdline='--platform'), + cmdline='--platform', + requires={"arm": [("translation.gcrootfinder", "shadowstack")]}, + suggests={"arm": [("translation.jit_backend", "arm")]}), ]) diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1053,9 +1053,10 @@ @arguments("box", "orgpc") def opimpl_raise(self, exc_value_box, orgpc): # xxx hack - clsbox = self.cls_of_box(exc_value_box) - self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], - resumepc=orgpc) + if not self.metainterp.heapcache.is_class_known(exc_value_box): + clsbox = self.cls_of_box(exc_value_box) + self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], + resumepc=orgpc) self.metainterp.class_of_last_exc_is_const = True self.metainterp.last_exc_value_box = exc_value_box self.metainterp.popframe() @@ -1876,7 +1877,9 @@ self.staticdata.warmrunnerdesc.hooks.on_abort(reason, jd_sd.jitdriver, greenkey, - jd_sd.warmstate.get_location_str(greenkey)) + jd_sd.warmstate.get_location_str(greenkey), + self.staticdata.logger_ops._make_log_operations(), + self.history.operations) self.staticdata.stats.aborted() def blackhole_if_trace_too_long(self): diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -7,18 +7,20 @@ from rpython.rtyper.annlowlevel import hlstr from rpython.jit.metainterp.jitprof import Profiler + class JitHookInterfaceTests(object): # !!!note!!! - don't subclass this from the backend. Subclass the LL # class later instead def test_abort_quasi_immut(self): reasons = [] - + class MyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): assert jitdriver is myjitdriver assert len(greenkey) == 1 reasons.append(reason) assert greenkey_repr == 'blah' + assert len(operations) > 1 iface = MyJitIface() @@ -27,8 +29,10 @@ class Foo: _immutable_fields_ = ['a?'] + def __init__(self, a): self.a = a + def f(a, x): foo = Foo(a) total = 0 @@ -47,7 +51,7 @@ def test_on_compile(self): called = [] - + class MyJitIface(JitHookInterface): def after_compile(self, di): called.append(("compile", di.greenkey[1].getint(), diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -5,8 +5,6 @@ from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rstring import StringBuilder -import py - class TestLLtype(LLJitMixin): def test_dont_record_repeated_guard_class(self): @@ -628,3 +626,22 @@ res = self.interp_operations(fn, [0]) assert res == 1 self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0) + + def test_raise_known_class_no_guard_class(self): + def raise_exc(cls): + raise cls + + def fn(n): + if n: + cls = ValueError + else: + cls = TypeError + try: + raise_exc(cls) + except ValueError: + return -1 + return n + + res = self.interp_operations(fn, [1]) + assert res == -1 + self.check_operations_history(guard_class=0) diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py --- a/rpython/jit/metainterp/virtualizable.py +++ b/rpython/jit/metainterp/virtualizable.py @@ -231,6 +231,10 @@ self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): + """ + Returns whether or not the virtualizable was forced during a + CALL_MAY_FORCE. + """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still diff --git a/rpython/memory/gc/env.py b/rpython/memory/gc/env.py --- a/rpython/memory/gc/env.py +++ b/rpython/memory/gc/env.py @@ -132,7 +132,7 @@ # ---------- Linux2 ---------- def get_L2cache_linux2(): - arch = platform.machine() + arch = os.uname()[4] # machine if arch.endswith('86') or arch == 'x86_64': return get_L2cache_linux2_cpuinfo() if arch in ('alpha', 'ppc', 'ppc64'): diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -926,7 +926,7 @@ of JIT running like JIT loops compiled, aborts etc. An instance of this class will be available as policy.jithookiface. """ - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): """ A hook called each time a loop is aborted with jitdriver and greenkey where it started, reason is a string why it got aborted """ diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -1,11 +1,10 @@ +from rpython.annotator import model as annmodel +from rpython.rlib.objectmodel import specialize +from rpython.rtyper.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance, llstr) +from rpython.rtyper.extregistry import ExtRegistryEntry +from rpython.rtyper.lltypesystem import llmemory, lltype, rclass -from rpython.rtyper.extregistry import ExtRegistryEntry -from rpython.annotator import model as annmodel -from rpython.rtyper.lltypesystem import llmemory, lltype -from rpython.rtyper.lltypesystem import rclass -from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr,\ - cast_base_ptr_to_instance, llstr -from rpython.rlib.objectmodel import specialize def register_helper(s_result): def wrapper(helper): diff --git a/rpython/tool/error.py b/rpython/tool/error.py --- a/rpython/tool/error.py +++ b/rpython/tool/error.py @@ -2,11 +2,15 @@ """ error handling features, just a way of displaying errors """ -from rpython.tool.ansi_print import ansi_log -from rpython.flowspace.model import Variable import sys import py + +from rpython.flowspace.model import Variable +from rpython.rlib import jit +from rpython.tool.ansi_print import ansi_log + + log = py.log.Producer("error") py.log.setconsumer("error", ansi_log) @@ -14,7 +18,8 @@ SHOW_ANNOTATIONS = True SHOW_DEFAULT_LINES_OF_CODE = 0 -def source_lines1(graph, block, operindex=None, offset=None, long=False, \ + +def source_lines1(graph, block, operindex=None, offset=None, long=False, show_lines_of_code=SHOW_DEFAULT_LINES_OF_CODE): if block is not None: if block is graph.returnblock: @@ -32,23 +37,24 @@ else: if block is None or not block.operations: return [] + def toline(operindex): return offset2lineno(graph.func.func_code, block.operations[operindex].offset) if operindex is None: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) if not long: return ['?'] here = None else: operline = toline(operindex) if long: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) here = operline else: linerange = (operline, operline) here = None lines = ["Happened at file %s line %d" % (graph.filename, here or linerange[0]), ""] - for n in range(max(0, linerange[0]-show_lines_of_code), \ + for n in range(max(0, linerange[0]-show_lines_of_code), min(linerange[1]+1+show_lines_of_code, len(graph_lines)+graph.startline)): if n == here: prefix = '==> ' @@ -136,6 +142,7 @@ from rpython.translator.tool.pdbplus import PdbPlusShow from rpython.translator.driver import log t = drv.translator + class options: huge = 100 @@ -161,6 +168,7 @@ pdb_plus_show.start(tb) + at jit.elidable def offset2lineno(c, stopat): tab = c.co_lnotab line = c.co_firstlineno @@ -170,4 +178,4 @@ if addr > stopat: break line = line + ord(tab[i+1]) - return line \ No newline at end of file + return line diff --git a/rpython/translator/c/src/stacklet/slp_platformselect.h b/rpython/translator/c/src/stacklet/slp_platformselect.h --- a/rpython/translator/c/src/stacklet/slp_platformselect.h +++ b/rpython/translator/c/src/stacklet/slp_platformselect.h @@ -8,6 +8,8 @@ #include "switch_x86_64_gcc.h" /* gcc on amd64 */ #elif defined(__GNUC__) && defined(__i386__) #include "switch_x86_gcc.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__arm__) +#include "switch_arm_gcc.h" /* gcc on arm */ #else #error "Unsupported platform!" #endif diff --git a/rpython/translator/c/src/stacklet/switch_arm_gcc.h b/rpython/translator/c/src/stacklet/switch_arm_gcc.h new file mode 100644 --- /dev/null +++ b/rpython/translator/c/src/stacklet/switch_arm_gcc.h @@ -0,0 +1,40 @@ + +static void __attribute__((optimize("O3"))) *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra) +{ + void *result; + __asm__ volatile ( + "mov r3, %[save_state]\n" + /* save values in calee saved registers for later */ + "mov r4, %[restore_state]\n" + "mov r5, %[extra]\n" + "mov r0, sp\n" /* arg 1: current (old) stack pointer */ + "mov r1, r5\n" /* arg 2: extra */ + "blx r3\n" /* call save_state() */ + + /* skip the rest if the return value is null */ + "cmp r0, #0\n" + "beq zero\n" + + "mov sp, r0\n" /* change the stack pointer */ + + /* From now on, the stack pointer is modified, but the content of the + stack is not restored yet. It contains only garbage here. */ + "mov r1, r5\n" /* arg 2: extra */ + /* arg 1: current (new) stack pointer is already in r0*/ + "blx r4\n" /* call restore_state() */ + + /* The stack's content is now restored. */ + "zero:\n" + "mov %[result], r0\n" + + : [result]"=r"(result) /* output variables */ + /* input variables */ + : [restore_state]"r"(restore_state), + [save_state]"r"(save_state), + [extra]"r"(extra) + : "lr", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r13" + ); + return result; +} From noreply at buildbot.pypy.org Wed May 22 14:39:57 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 14:39:57 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove smalltuples. They are disabled by default and can easily be readded. Message-ID: <20130522123957.C582B1C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64447:9ff8b4beff41 Date: 2013-05-22 14:37 +0200 http://bitbucket.org/pypy/pypy/changeset/9ff8b4beff41/ Log: Remove smalltuples. They are disabled by default and can easily be readded. diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -215,10 +215,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/smalltupleobject.py +++ /dev/null @@ -1,75 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.objspace.std.tupleobject import W_AbstractTupleObject -from pypy.objspace.std.util import negate -from rpython.rlib.rarithmetic import intmask -from rpython.rlib.unroll import unrolling_iterable -from rpython.tool.sourcetools import func_with_new_name - - -def make_specialized_class(n): - iter_n = unrolling_iterable(range(n)) - - class cls(W_AbstractTupleObject): - def __init__(self, values): - assert len(values) == n - for i in iter_n: - setattr(self, 'w_value%s' % i, values[i]) - - def tolist(self): - l = [None] * n - for i in iter_n: - l[i] = getattr(self, 'w_value%s' % i) - return l - - # same source code, but builds and returns a resizable list - getitems_copy = func_with_new_name(tolist, 'getitems_copy') - - def length(self): - return n - - def getitem(self, space, index): - if index < 0: - index += n - for i in iter_n: - if index == i: - return getattr(self, 'w_value%s' % i) - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - - def descr_eq(self, space, w_other): - if not isinstance(w_other, W_AbstractTupleObject): - return space.w_NotImplemented - if n != w_other.length(): - return space.w_False - for i in iter_n: - item1 = getattr(self, 'w_value%s' % i) - item2 = w_other.getitem(space, i) - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - - descr_ne = negate(descr_eq) - - def descr_hash(self, space): - mult = 1000003 - x = 0x345678 - z = n - for i in iter_n: - w_item = getattr(self, 'w_value%s' % i) - y = space.int_w(space.hash(w_item)) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return space.wrap(intmask(x)) - - cls.__name__ = "W_SmallTupleObject%s" % n - return cls - -W_SmallTupleObject2 = make_specialized_class(2) -W_SmallTupleObject3 = make_specialized_class(3) -W_SmallTupleObject4 = make_specialized_class(4) -W_SmallTupleObject5 = make_specialized_class(5) -W_SmallTupleObject6 = make_specialized_class(6) -W_SmallTupleObject7 = make_specialized_class(7) -W_SmallTupleObject8 = make_specialized_class(8) diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ /dev/null @@ -1,77 +0,0 @@ -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 -from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject -from pypy.objspace.std.tupleobject import W_TupleObject - - -class AppTestW_SmallTupleObject(AppTestW_TupleObject): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def setup_class(cls): - cls.w_issmall = cls.space.appexec([], """(): - import __pypy__ - def issmall(obj): - assert "SmallTuple" in __pypy__.internal_repr(obj) - return issmall - """) - - def test_smalltuple(self): - self.issmall((1, 2)) - self.issmall((1, 2, 3)) - - def test_slicing_to_small(self): - self.issmall((1, 2, 3)[0:2]) # SmallTuple2 - self.issmall((1, 2, 3)[0:2:1]) - - self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3 - self.issmall((1, 2, 3, 4)[0:3:1]) - - def test_adding_to_small(self): - self.issmall((1,) + (2,)) # SmallTuple2 - self.issmall((1, 1) + (2,)) # SmallTuple3 - self.issmall((1,) + (2, 3)) - - def test_multiply_to_small(self): - self.issmall((1,) * 2) - self.issmall((1,) * 3) - - def test_slicing_from_small(self): - assert (1, 2)[0:1:1] == (1,) - assert (1, 2, 3)[0:2:1] == (1, 2) - - def test_eq(self): - a = (1, 2, 3) - b = (1, 2, 3) - assert a == b - - c = (1, 3, 2) - assert a != c - - def test_hash(self): - a = (1, 2, 3) - b = (1, 2, 3) - assert hash(a) == hash(b) - - c = (1, 3, 2) - assert hash(a) != hash(c) - - def test_foo(self): - assert tuple([0]) + (1,) == (0, 1) - assert not tuple([0]) + (1,) == (0,) - - -class TestW_SmallTupleObject(): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def test_issmalltupleobject(self): - w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - assert isinstance(w_tuple, W_SmallTupleObject2) - - def test_hash_agains_normal_tuple(self): - w_tuple = W_TupleObject([self.space.wrap(1), self.space.wrap(2)]) - w_smalltuple = self.space.newtuple([self.space.wrap(1), - self.space.wrap(2)]) - assert isinstance(w_smalltuple, W_SmallTupleObject2) - - assert self.space.is_true(self.space.eq(w_tuple, w_smalltuple)) - assert self.space.is_true(self.space.eq(self.space.hash(w_tuple), - self.space.hash(w_smalltuple))) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -292,27 +292,4 @@ return makespecialisedtuple(space, list_w) except NotSpecialised: pass - - if space.config.objspace.std.withsmalltuple: - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 - if len(list_w) == 2: - return W_SmallTupleObject2(list_w) - if len(list_w) == 3: - return W_SmallTupleObject3(list_w) - if len(list_w) == 4: - return W_SmallTupleObject4(list_w) - if len(list_w) == 5: - return W_SmallTupleObject5(list_w) - if len(list_w) == 6: - return W_SmallTupleObject6(list_w) - if len(list_w) == 7: - return W_SmallTupleObject7(list_w) - if len(list_w) == 8: - return W_SmallTupleObject8(list_w) return W_TupleObject(list_w) From noreply at buildbot.pypy.org Wed May 22 15:00:47 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 22 May 2013 15:00:47 +0200 (CEST) Subject: [pypy-commit] pypy default: fix interplevel subclasses for dict and list Message-ID: <20130522130047.EE9801C0328@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64448:692ff89f4bd5 Date: 2013-05-22 14:59 +0200 http://bitbucket.org/pypy/pypy/changeset/692ff89f4bd5/ Log: fix interplevel subclasses for dict and list diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -663,6 +663,13 @@ class2type[base] = w_type self._interplevel_classes[w_type] = base + # register other things + from pypy.objspace.std.dictmultiobject import W_DictMultiObject + from pypy.objspace.std.listobject import W_ListObject + + self._interplevel_classes[self.w_dict] = W_DictMultiObject + self._interplevel_classes[self.w_list] = W_ListObject + @specialize.memo() def _get_interplevel_cls(self, w_type): if not hasattr(self, "_interplevel_classes"): From noreply at buildbot.pypy.org Wed May 22 15:01:53 2013 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 22 May 2013 15:01:53 +0200 (CEST) Subject: [pypy-commit] pypy default: add sets Message-ID: <20130522130153.0D3DF1C0328@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64449:09477d50934b Date: 2013-05-22 15:01 +0200 http://bitbucket.org/pypy/pypy/changeset/09477d50934b/ Log: add sets diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -666,9 +666,11 @@ # register other things from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.listobject import W_ListObject + from pypy.objspace.std.setobject import W_SetObject self._interplevel_classes[self.w_dict] = W_DictMultiObject self._interplevel_classes[self.w_list] = W_ListObject + self._interplevel_classes[self.w_set] = W_SetObject @specialize.memo() def _get_interplevel_cls(self, w_type): From noreply at buildbot.pypy.org Wed May 22 15:10:20 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 15:10:20 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Simplify. Message-ID: <20130522131020.16E8B1C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64450:16b0ec9cc99f Date: 2013-05-22 14:59 +0200 http://bitbucket.org/pypy/pypy/changeset/16b0ec9cc99f/ Log: Simplify. diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -82,11 +82,9 @@ for i in iter_n: myval = getattr(self, 'value%s' % i) otherval = w_other.getitem(space, i) - if typetuple[i] == object: - myval_wrapped = myval - else: - myval_wrapped = space.wrap(myval) - if not space.eq_w(myval_wrapped, otherval): + if typetuple[i] != object: + myval = space.wrap(myval) + if not space.eq_w(myval, otherval): return space.w_False else: return space.w_True From noreply at buildbot.pypy.org Wed May 22 15:46:58 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 15:46:58 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: start extracting an interface from x86/callbuilder.py Message-ID: <20130522134658.CB0BF1C331B@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64451:1e10efb3ccd5 Date: 2013-05-22 08:12 -0500 http://bitbucket.org/pypy/pypy/changeset/1e10efb3ccd5/ Log: start extracting an interface from x86/callbuilder.py diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/llsupport/callbuilder.py @@ -0,0 +1,75 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI + +class AbstractCallBuilder(object): + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # set by save_result_value() + tmpresloc = None + + def __init__(self, assembler, fnloc, arglocs, resloc, restype, ressize): + # Avoid tons of issues with a non-immediate fnloc by sticking it + # as an extra argument if needed + self.fnloc = fnloc + self.arglocs = arglocs + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + self.ressigned = False + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_stack_pointer() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + + def prepare_arguments(self): + raise NotImplementedError + + def push_gcmap(self): + raise NotImplementedError + + def pop_gcmap(self): + raise NotImplementedError + + def emit_raw_call(self): + raise NotImplementedError + + def restore_stack_pointer(self): + raise NotImplementedError + + def load_result(self): + raise NotImplementedError diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -8,6 +8,7 @@ r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) from rpython.jit.backend.x86.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder # darwin requires the stack to be 16 bytes aligned on calls. @@ -19,7 +20,8 @@ -class AbstractCallBuilder(object): + +class CallBuilderX86(AbstractCallBuilder): # max number of words we have room in esp; if we need more for # arguments, we need to decrease esp temporarily @@ -30,65 +32,19 @@ argtypes = "" ressign = False - # this is the calling convention (can be FFI_STDCALL on Windows) - callconv = FFI_DEFAULT_ABI - - # is it for the main CALL of a call_release_gil? - is_call_release_gil = False - - # set by save_result_value() - tmpresloc = None - - def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT, ressize=WORD): - # Avoid tons of issues with a non-immediate fnloc by sticking it - # as an extra argument if needed + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) - if self.fnloc_is_immediate: - self.fnloc = fnloc - self.arglocs = arglocs - else: + if not self.fnloc_is_immediate: + self.fnloc = None self.arglocs = arglocs + [fnloc] - self.asm = assembler - self.mc = assembler.mc - self.resloc = resloc - self.restype = restype - self.ressize = ressize self.current_esp = 0 # 0 or (usually) negative, counted in bytes - def emit_no_collect(self): - """Emit a call that cannot collect.""" - self.prepare_arguments() - self.emit_raw_call() - self.restore_esp() - self.load_result() - - def emit(self): - """Emit a regular call; not for CALL_RELEASE_GIL.""" - self.prepare_arguments() - self.push_gcmap() - self.emit_raw_call() - self.restore_esp() - self.pop_gcmap() - self.load_result() - - def emit_call_release_gil(self): - """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr - and reacqgil_addr.""" - self.select_call_release_gil_mode() - self.prepare_arguments() - self.push_gcmap_for_call_release_gil() - self.call_releasegil_addr_and_move_real_arguments() - self.emit_raw_call() - self.restore_esp() - self.move_real_result_and_call_reacqgil_addr() - self.pop_gcmap() - self.load_result() - def select_call_release_gil_mode(self): """Overridden in CallBuilder64""" - self.is_call_release_gil = True + AbstractCallBuilder.select_call_release_gil_mode(self) if self.asm._is_asmgcc(): from rpython.memory.gctransform import asmgcroot self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS @@ -105,7 +61,7 @@ self.current_esp -= align * WORD self.mc.SUB_ri(esp.value, align * WORD) - def restore_esp(self, target_esp=0): + def restore_stack_pointer(self, target_esp=0): if self.current_esp != target_esp: self.mc.ADD_ri(esp.value, target_esp - self.current_esp) self.current_esp = target_esp @@ -204,7 +160,7 @@ self.mc.ADD(ebp, imm(1)) # ebp any more # self.restore_register_arguments() - self.restore_esp(initial_esp) + self.restore_stack_pointer(initial_esp) def save_register_arguments(self): """Overridden in CallBuilder64""" @@ -248,7 +204,7 @@ raise NotImplementedError -class CallBuilder32(AbstractCallBuilder): +class CallBuilder32(CallBuilderX86): def prepare_arguments(self): arglocs = self.arglocs @@ -318,7 +274,7 @@ else: self.mc.MOV(resloc, self.tmpresloc) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP+4]. We use "+4" @@ -343,7 +299,7 @@ self.mc.MOV_sr(4, eax.value) -class CallBuilder64(AbstractCallBuilder): +class CallBuilder64(CallBuilderX86): ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] @@ -389,7 +345,7 @@ i += 1 def select_call_release_gil_mode(self): - AbstractCallBuilder.select_call_release_gil_mode(self) + CallBuilderX86.select_call_release_gil_mode(self) # We have to copy the arguments around a bit more in this mode, # but on the other hand we don't need prepare_arguments() moving # them in precisely the final registers. Here we look around for @@ -502,7 +458,7 @@ # from the lower 32 bits of XMM0 self.mc.MOVD(self.resloc, xmm0) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP]. From noreply at buildbot.pypy.org Wed May 22 15:47:00 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 15:47:00 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: start implementing a callbuilder for arm (hf and sf), test_runner.py:test_call passes so far Message-ID: <20130522134700.9C25B1C331B@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64452:aae353caccc4 Date: 2013-05-22 08:44 -0500 http://bitbucket.org/pypy/pypy/changeset/aae353caccc4/ Log: start implementing a callbuilder for arm (hf and sf), test_runner.py:test_call passes so far diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/callbuilder.py @@ -0,0 +1,226 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.regalloc import check_imm_arg + + +class ARMCallbuilder(AbstractCallBuilder): + def __init__(self, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) + self.current_sp = 0 + + def push_gcmap(self): + assert not self.is_call_release_gil + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r0], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + assert not self.is_call_release_gil + self.asm._reload_frame_if_necessary(self.mc) + self.asm.pop_gcmap(self.mc) + + def emit_raw_call(self): + #the actual call + if self.fnloc.is_imm(): + self.mc.BL(self.fnloc.value) + return + if self.fnloc.is_stack(): + self.asm.mov_loc_loc(self.fnloc, r.ip) + self.fnloc = r.ip + assert self.fnloc.is_reg() + self.mc.BLX(self.fnloc.value) + + def restore_stack_pointer(self): + # readjust the sp in case we passed some args on the stack + assert self.current_sp % 8 == 0 # sanity check + if self.current_sp != 0: + self._adjust_sp(self.current_sp) + self.current_sp = 0 + + def _push_stack_args(self, stack_args, on_stack): + assert on_stack % 8 == 0 + #then we push every thing on the stack + for i in range(len(stack_args) - 1, -1, -1): + arg = stack_args[i] + if arg is None: + self.mc.PUSH([r.ip.value]) + else: + self.asm.regalloc_push(arg) + self.current_sp -= on_stack + + def _adjust_sp(self, n): + assert n < 0 + n = abs(n) + + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n, cond=fcond) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value, cond=fcond) + + +class SoftFloatCallBuilder(ARMCallbuilder): + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None: + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + self.asm._ensure_result_bit_extension(resloc, + self.ressize, self.ressigned) + + + def _collect_stack_args(self, arglocs): + n_args = len(arglocs) + reg_args = count_reg_args(arglocs) + # all arguments past the 4th go on the stack + # first we need to prepare the list so it stays aligned + stack_args = [] + count = 0 + on_stack = 0 + if n_args > reg_args: + for i in range(reg_args, n_args): + arg = arglocs[i] + if arg.type != FLOAT: + count += 1 + on_stack += 1 + else: + on_stack += 2 + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + if count % 2 != 0: + on_stack += 1 + stack_args.append(None) + if on_stack > 0: + self._push_stack_args(stack_args, on_stack*WORD) + + def prepare_arguments(self): + reg_args = count_reg_args(arglocs) + self._collect_and_push_stack_args(arglocs) + # collect variables that need to go in registers and the registers they + # will be stored in + num = 0 + count = 0 + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(reg_args): + arg = arglocs[i] + if arg.type == FLOAT and count % 2 != 0: + num += 1 + count = 0 + reg = r.caller_resp[num] + + if arg.type == FLOAT: + float_locs.append((arg, reg)) + else: + non_float_locs.append(arg) + non_float_regs.append(reg) + + if arg.type == FLOAT: + num += 2 + else: + num += 1 + count += 1 + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments. + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs: + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + + for loc, reg in float_locs: + self.asm.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) + +class HardFloatCallBuilder(ARMCallbuilder): + + def prepare_arguments(self): + non_float_locs = [] + non_float_regs = [] + float_locs = [] + float_regs = [] + stack_args = [] + + arglocs = self.arglocs + argtypes = self.argtypes + + count = 0 # stack alignment counter + on_stack = 0 + for arg in arglocs: + if arg.type != FLOAT: + if len(non_float_regs) < len(r.argument_regs): + reg = r.argument_regs[len(non_float_regs)] + non_float_locs.append(arg) + non_float_regs.append(reg) + else: # non-float argument that needs to go on the stack + count += 1 + on_stack += 1 + stack_args.append(arg) + else: + if len(float_regs) < len(r.vfp_argument_regs): + reg = r.vfp_argument_regs[len(float_regs)] + float_locs.append(arg) + float_regs.append(reg) + else: # float argument that needs to go on the stack + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + on_stack += 2 + # align the stack + if count % 2 != 0: + stack_args.append(None) + on_stack += 1 + self._push_stack_args(stack_args, on_stack*WORD) + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments. + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs: + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + # remap values stored in vfp registers + remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip) + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None and resloc.is_reg(): + self.asm._ensure_result_bit_extension(resloc, + self.ressize, self.ressigned) + + + +def get_callbuilder(cpu, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + if cpu.cpuinfo.hf_abi: + return HardFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) + else: + return SoftFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -13,8 +13,7 @@ gen_emit_float_cmp_op, gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, - saved_registers, - count_reg_args) + saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout @@ -31,8 +30,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.arm import callbuilder class ArmGuardToken(GuardToken): @@ -339,214 +337,32 @@ return fcond def emit_op_call(self, op, arglocs, regalloc, fcond): - resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + return self._emit_call(op, arglocs, fcond=fcond) + + def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): + # args = [resloc, size, sign, args...] + from rpython.jit.backend.llsupport.descr import CallDescr + + cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3], arglocs[4:], arglocs[0]) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - cond = self._emit_call(adr, arglist, - fcond, resloc, (size, signed)) - return cond + assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[1] + assert sizeloc.is_imm() + cb.ressize = sizeloc.value + signloc = arglocs[2] + assert signloc.is_imm() + cb.ressign = signloc.value - def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None, - result_info=(-1, -1), - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True): - if self.cpu.cpuinfo.hf_abi: - stack_args, adr = self._setup_call_hf(adr, arglocs, fcond, - resloc, result_info) + if is_call_release_gil: + cb.emit_call_release_gil() else: - stack_args, adr = self._setup_call_sf(adr, arglocs, fcond, - resloc, result_info) - - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - #the actual call - if adr.is_imm(): - self.mc.BL(adr.value) - elif adr.is_stack(): - self.mov_loc_loc(adr, r.ip) - adr = r.ip - else: - assert adr.is_reg() - if adr.is_reg(): - self.mc.BLX(adr.value) - self._restore_sp(stack_args, fcond) - - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg() and not self.cpu.cpuinfo.hf_abi: - # move result to the allocated register - self.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg() and result_info != (-1, -1): - self._ensure_result_bit_extension(resloc, result_info[0], - result_info[1]) - if can_collect: - self._reload_frame_if_necessary(self.mc) - self.pop_gcmap(self.mc) + cb.emit() return fcond - def _restore_sp(self, stack_args, fcond): - # readjust the sp in case we passed some args on the stack - if len(stack_args) > 0: - n = 0 - for arg in stack_args: - if arg is None or arg.type != FLOAT: - n += WORD - else: - n += DOUBLE_WORD - self._adjust_sp(-n, fcond=fcond) - assert n % 8 == 0 # sanity check - - def _adjust_sp(self, n, cb=None, fcond=c.AL, base_reg=r.sp): - if cb is None: - cb = self.mc - if n < 0: - n = -n - rev = True - else: - rev = False - if n <= 0xFF and fcond == c.AL: - if rev: - cb.ADD_ri(r.sp.value, base_reg.value, n) - else: - cb.SUB_ri(r.sp.value, base_reg.value, n) - else: - cb.gen_load_int(r.ip.value, n, cond=fcond) - if rev: - cb.ADD_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - else: - cb.SUB_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - - - def _collect_stack_args_sf(self, arglocs): - n_args = len(arglocs) - reg_args = count_reg_args(arglocs) - # all arguments past the 4th go on the stack - # first we need to prepare the list so it stays aligned - stack_args = [] - count = 0 - if n_args > reg_args: - for i in range(reg_args, n_args): - arg = arglocs[i] - if arg.type != FLOAT: - count += 1 - else: - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - if count % 2 != 0: - stack_args.append(None) - return stack_args - - def _push_stack_args(self, stack_args): - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.regalloc_push(arg) - - def _setup_call_sf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - reg_args = count_reg_args(arglocs) - stack_args = self._collect_stack_args_sf(arglocs) - self._push_stack_args(stack_args) - # collect variables that need to go in registers and the registers they - # will be stored in - num = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - for i in range(reg_args): - arg = arglocs[i] - if arg.type == FLOAT and count % 2 != 0: - num += 1 - count = 0 - reg = r.caller_resp[num] - - if arg.type == FLOAT: - float_locs.append((arg, reg)) - else: - non_float_locs.append(arg) - non_float_regs.append(reg) - - if arg.type == FLOAT: - num += 2 - else: - num += 1 - count += 1 - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - - for loc, reg in float_locs: - self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) - return stack_args, adr - - def _setup_call_hf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - count = 0 # stack alignment counter - for arg in arglocs: - if arg.type != FLOAT: - if len(non_float_regs) < len(r.argument_regs): - reg = r.argument_regs[len(non_float_regs)] - non_float_locs.append(arg) - non_float_regs.append(reg) - else: # non-float argument that needs to go on the stack - count += 1 - stack_args.append(arg) - else: - if len(float_regs) < len(r.vfp_argument_regs): - reg = r.vfp_argument_regs[len(float_regs)] - float_locs.append(arg) - float_regs.append(reg) - else: # float argument that needs to go on the stack - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - # align the stack - if count % 2 != 0: - stack_args.append(None) - self._push_stack_args(stack_args) - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - # remap values stored in vfp registers - remap_frame_layout(self, float_locs, float_regs, r.vfp_ip) - - return stack_args, adr - def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs self.mov_loc_loc(argloc, resloc) @@ -1037,9 +853,8 @@ length_loc = bytes_loc # call memcpy() regalloc.before_call() - self._emit_call(imm(self.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.simple_call_no_collect(imm(self.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.rm.possibly_free_var(length_box) regalloc.rm.possibly_free_var(dstaddr_box) regalloc.rm.possibly_free_var(srcaddr_box) @@ -1131,10 +946,10 @@ return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self._emit_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], resloc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self._emit_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, resloc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') @@ -1213,16 +1028,10 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] + callargs = arglocs[2:numargs + 3] # extract the arguments to the call + assert 0, 'xxx revisit this' # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed)) + self._emit_call(op, callargs, fcond) self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) return fcond @@ -1237,38 +1046,39 @@ fcond): self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - # do the call - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed), - can_collect=False) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - self.pop_gcmap(self.mc) # remove the gcmap saved above - + self._emit_call(op, arglocs, result_loc, is_call_release_gil=True) self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) return fcond + # first, close the stack in the sense of the asmgcc GC root tracker + #gcrootmap = self.cpu.gc_ll_descr.gcrootmap + #numargs = op.numargs() + #callargs = arglocs[2:numargs + 1] # extract the arguments to the call + #adr = arglocs[1] + #resloc = arglocs[0] + + #if gcrootmap: + # # we put the gcmap now into the frame before releasing the GIL, + # # and pop it below after reacquiring the GIL. The assumption + # # is that this gcmap describes correctly the situation at any + # # point in-between: all values containing GC pointers should + # # be safely saved out of registers by now, and will not be + # # manipulated by any of the following CALLs. + # gcmap = self._regalloc.get_gcmap(noregs=True) + # self.push_gcmap(self.mc, gcmap, store=True) + # self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) + ## do the call + #descr = op.getdescr() + #size = descr.get_result_size() + #signed = descr.is_result_signed() + ## + #self._emit_call(adr, callargs, fcond, + # resloc, (size, signed), + # is_call_release_gil=True) + ## then reopen the stack + #if gcrootmap: + # self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) + # self.pop_gcmap(self.mc) # remove the gcmap saved above + def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): # Save caller saved registers and do the call @@ -1276,7 +1086,7 @@ assert gcrootmap.is_shadow_stack with saved_registers(self.mc, regalloc.rm.save_around_call_regs): self._emit_call(imm(self.releasegil_addr), [], - fcond, can_collect=False) + fcond, is_call_release_gil=True) def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): # save the previous result into the stack temporarily, in case it is in @@ -1294,7 +1104,7 @@ # call the reopenstack() function (also reacquiring the GIL) with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): self._emit_call(imm(self.reacqgil_addr), [], fcond, - can_collect=False) + is_call_release_gil=True) self._reload_frame_if_necessary(self.mc) def _store_force_index(self, guard_op): diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -34,6 +34,7 @@ from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr from rpython.rlib.rarithmetic import r_uint +from rpython.jit.backend.llsupport.descr import CallDescr # xxx hack: set a default value for TargetToken._ll_loop_code. If 0, we know @@ -555,9 +556,12 @@ return self._prepare_call(op) def _prepare_call(self, op, force_store=[], save_all_regs=False): - args = [None] * (op.numargs() + 1) + args = [None] * (op.numargs() + 3) + calldescr = op.getdescr() + assert isinstance(calldescr, CallDescr) + assert len(calldescr.arg_classes) == op.numargs() - 1 for i in range(op.numargs()): - args[i + 1] = self.loc(op.getarg(i)) + args[i + 3] = self.loc(op.getarg(i)) # spill variables that need to be saved around calls self.vfprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -568,6 +572,15 @@ if op.result: resloc = self.after_call(op.result) args[0] = resloc + + size = calldescr.get_result_size() + sign = calldescr.is_result_signed() + if sign: + sign_loc = imm(1) + else: + sign_loc = imm(0) + args[1] = imm(size) + args[2] = sign_loc self.before_call_called = True return args @@ -1151,6 +1164,7 @@ prepare_guard_call_release_gil = prepare_guard_call_may_force def prepare_guard_call_assembler(self, op, guard_op, fcond): + assert 0, 'xxx needs checking' locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) call_locs = self._prepare_call(op, save_all_regs=True) From noreply at buildbot.pypy.org Wed May 22 16:40:51 2013 From: noreply at buildbot.pypy.org (bivab) Date: Wed, 22 May 2013 16:40:51 +0200 (CEST) Subject: [pypy-commit] pypy default: backout bf86c92ce059 Message-ID: <20130522144051.60DA11C331B@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64453:84874bf5c723 Date: 2013-05-22 16:39 +0200 http://bitbucket.org/pypy/pypy/changeset/84874bf5c723/ Log: backout bf86c92ce059 diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -18,9 +18,9 @@ _is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) if sys.platform.startswith("linux") and _is_x86: - DEFL_ROOTFINDER = "asmgcc" + DEFL_ROOTFINDER_WITHJIT = "asmgcc" else: - DEFL_ROOTFINDER = "shadowstack" + DEFL_ROOTFINDER_WITHJIT = "shadowstack" IS_64_BITS = sys.maxint > 2147483647 @@ -94,7 +94,7 @@ ChoiceOption("gcrootfinder", "Strategy for finding GC Roots (framework GCs only)", ["n/a", "shadowstack", "asmgcc"], - DEFL_ROOTFINDER, + "shadowstack", cmdline="--gcrootfinder", requires={ "shadowstack": [("translation.gctransformer", "framework")], @@ -117,7 +117,7 @@ BoolOption("jit", "generate a JIT", default=False, suggests=[("translation.gc", DEFL_GC), - ("translation.gcrootfinder", DEFL_ROOTFINDER), + ("translation.gcrootfinder", DEFL_ROOTFINDER_WITHJIT), ("translation.list_comprehension_operations", True)]), ChoiceOption("jit_backend", "choose the backend for the JIT", ["auto", "x86", "x86-without-sse2", 'arm'], From noreply at buildbot.pypy.org Wed May 22 17:33:47 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 22 May 2013 17:33:47 +0200 (CEST) Subject: [pypy-commit] cffi default: Bump the version number of 0.7. Message-ID: <20130522153347.5833C1C0328@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1254:708b37a61df4 Date: 2013-05-22 16:46 +0200 http://bitbucket.org/cffi/cffi/changeset/708b37a61df4/ Log: Bump the version number of 0.7. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -5106,7 +5106,7 @@ if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) INITERROR; - v = PyText_FromString("0.6"); + v = PyText_FromString("0.7"); if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) INITERROR; diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -2745,4 +2745,4 @@ def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.6" + assert __version__ == "0.7" diff --git a/cffi/__init__.py b/cffi/__init__.py --- a/cffi/__init__.py +++ b/cffi/__init__.py @@ -4,5 +4,5 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "0.6" -__version_info__ = (0, 6) +__version__ = "0.7" +__version_info__ = (0, 7) diff --git a/doc/source/conf.py b/doc/source/conf.py --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -45,9 +45,9 @@ # built documents. # # The short X.Y version. -version = '0.6' +version = '0.7' # The full version, including alpha/beta/rc tags. -release = '0.6' +release = '0.7' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -90,7 +90,7 @@ Download and Installation: -* http://pypi.python.org/packages/source/c/cffi/cffi-0.6.tar.gz +* http://pypi.python.org/packages/source/c/cffi/cffi-0.7.tar.gz - Or grab the most current version by following the instructions below. diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -81,7 +81,7 @@ setup( name='cffi', description='Foreign Function Interface for Python calling C code.', - version='0.6', + version='0.7', packages=['cffi'], zip_safe=False, From noreply at buildbot.pypy.org Wed May 22 17:33:48 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 22 May 2013 17:33:48 +0200 (CEST) Subject: [pypy-commit] cffi default: issue 87: first stab Message-ID: <20130522153348.A09D41C334B@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1255:014387613928 Date: 2013-05-22 17:33 +0200 http://bitbucket.org/cffi/cffi/changeset/014387613928/ Log: issue 87: first stab diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -91,6 +91,7 @@ #define CT_IS_LONGDOUBLE 65536 #define CT_IS_BOOL 131072 #define CT_IS_FILE 262144 +#define CT_IS_VOID_PTR 524288 #define CT_PRIMITIVE_ANY (CT_PRIMITIVE_SIGNED | \ CT_PRIMITIVE_UNSIGNED | \ CT_PRIMITIVE_CHAR | \ @@ -1392,6 +1393,10 @@ if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) { Py_DECREF(((CDataObject_own_structptr *)cd)->structobj); } + else if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { + PyObject *x = (PyObject *)(cd->c_data + 42); + Py_DECREF(x); + } else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cd->c_data; @@ -1506,11 +1511,25 @@ return result; } +static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x) +{ + PyObject *res, *s = PyObject_Repr(x); + if (s == NULL) + return NULL; + res = PyText_FromFormat("", + cd->c_type->ct_name, text, PyText_AsUTF8(s)); + Py_DECREF(s); + return res; +} + static PyObject *cdataowning_repr(CDataObject *cd) { Py_ssize_t size; - if (cd->c_type->ct_flags & CT_POINTER) + if (cd->c_type->ct_flags & CT_POINTER) { + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) + goto handle_repr; size = cd->c_type->ct_itemdescr->ct_size; + } else if (cd->c_type->ct_flags & CT_ARRAY) size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) @@ -1523,18 +1542,17 @@ callback_repr: { - PyObject *s, *res; PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data; if (args == NULL) return cdata_repr(cd); - - s = PyObject_Repr(PyTuple_GET_ITEM(args, 1)); - if (s == NULL) - return NULL; - res = PyText_FromFormat("", - cd->c_type->ct_name, PyText_AsUTF8(s)); - Py_DECREF(s); - return res; + else + return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1)); + } + + handle_repr: + { + PyObject *x = (PyObject *)(cd->c_data + 42); + return _cdata_repr2(cd, "handle to", x); } } @@ -3248,6 +3266,8 @@ td->ct_flags = CT_POINTER; if (ctitem->ct_flags & (CT_STRUCT|CT_UNION)) td->ct_flags |= CT_IS_PTR_TO_OWNED; + if (ctitem->ct_flags & CT_VOID) + td->ct_flags |= CT_IS_VOID_PTR; if ((ctitem->ct_flags & CT_VOID) || ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) && ctitem->ct_size == sizeof(char))) @@ -4647,6 +4667,55 @@ return Py_None; } +static PyObject *b_newp_handle(PyObject *self, PyObject *args) +{ + CTypeDescrObject *ct; + CDataObject *cd; + PyObject *x; + if (!PyArg_ParseTuple(args, "O!O", &CTypeDescr_Type, &ct, &x)) + return NULL; + + if (!(ct->ct_flags & CT_IS_VOID_PTR)) { + PyErr_Format(PyExc_TypeError, "needs 'void *', got '%s'", ct->ct_name); + return NULL; + } + + cd = allocate_owning_object(sizeof(CDataObject), ct); + if (cd == NULL) + return NULL; + + Py_INCREF(x); + cd->c_data = ((char *)x) - 42; + return (PyObject *)cd; +} + +static PyObject *b_from_handle(PyObject *self, PyObject *arg) +{ + CTypeDescrObject *ct; + char *raw; + PyObject *x; + if (!CData_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); + return NULL; + } + ct = ((CDataObject *)arg)->c_type; + raw = ((CDataObject *)arg)->c_data; + if (!(ct->ct_flags & CT_CAST_ANYTHING)) { + PyErr_Format(PyExc_TypeError, + "expected a 'cdata' object with a 'void *' out of " + "new_handle(), got '%s'", ct->ct_name); + return NULL; + } + if (!raw) { + PyErr_SetString(PyExc_RuntimeError, + "cannot use from_handle() on NULL pointer"); + return NULL; + } + x = (PyObject *)(raw + 42); + Py_INCREF(x); + return x; +} + static PyObject *b__get_types(PyObject *self, PyObject *noarg) { return PyTuple_Pack(2, (PyObject *)&CData_Type, @@ -4890,6 +4959,8 @@ {"buffer", b_buffer, METH_VARARGS}, {"get_errno", b_get_errno, METH_NOARGS}, {"set_errno", b_set_errno, METH_VARARGS}, + {"newp_handle", b_newp_handle, METH_VARARGS}, + {"from_handle", b_from_handle, METH_O}, {"_get_types", b__get_types, METH_NOARGS}, {"_testfunc", b__testfunc, METH_VARARGS}, {NULL, NULL} /* Sentinel */ diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -2743,6 +2743,32 @@ assert x != cast(BIntP, 12344) assert hash(x) == hash(cast(BIntP, 12345)) +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + + def test_version(): # this test is here mostly for PyPy assert __version__ == "0.7" diff --git a/cffi/api.py b/cffi/api.py --- a/cffi/api.py +++ b/cffi/api.py @@ -73,15 +73,15 @@ if name.startswith('RTLD_'): setattr(self, name, getattr(backend, name)) # - BVoidP = self._get_cached_btype(model.voidp_type) + self.BVoidP = self._get_cached_btype(model.voidp_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(BVoidP, 0) + FFI.NULL = self.cast(self.BVoidP, 0) FFI.CData, FFI.CType = backend._get_types() else: # ctypes backend: attach these constants to the instance - self.NULL = self.cast(BVoidP, 0) + self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() def cdef(self, csource, override=False): @@ -346,6 +346,12 @@ self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.append(']') + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + def _make_ffi_library(ffi, libname, flags): import os diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py --- a/testing/test_ffi_backend.py +++ b/testing/test_ffi_backend.py @@ -27,3 +27,12 @@ assert ffi.typeof("long(*)(long, long**, ...)").cname == ( "long(*)(long, long * *, ...)") assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True + + def test_new_handle(self): + ffi = FFI(backend=self.Backend()) + o = [2, 3, 4] + p = ffi.new_handle(o) + assert ffi.typeof(p) == ffi.typeof("void *") + assert ffi.from_handle(p) is o + assert ffi.from_handle(ffi.cast("char *", p)) is o + py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) From noreply at buildbot.pypy.org Wed May 22 18:12:32 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:32 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: hg merge default Message-ID: <20130522161232.1CA9D1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64454:c365929ecf63 Date: 2013-05-22 15:47 +0200 http://bitbucket.org/pypy/pypy/changeset/c365929ecf63/ Log: hg merge default diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -663,6 +663,15 @@ class2type[base] = w_type self._interplevel_classes[w_type] = base + # register other things + from pypy.objspace.std.dictmultiobject import W_DictMultiObject + from pypy.objspace.std.listobject import W_ListObject + from pypy.objspace.std.setobject import W_SetObject + + self._interplevel_classes[self.w_dict] = W_DictMultiObject + self._interplevel_classes[self.w_list] = W_ListObject + self._interplevel_classes[self.w_set] = W_SetObject + @specialize.memo() def _get_interplevel_cls(self, w_type): if not hasattr(self, "_interplevel_classes"): From noreply at buildbot.pypy.org Wed May 22 18:12:33 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:33 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Add tuple to _interplevel_classes. Message-ID: <20130522161233.7BBB61C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64455:5412c2d0776e Date: 2013-05-22 15:50 +0200 http://bitbucket.org/pypy/pypy/changeset/5412c2d0776e/ Log: Add tuple to _interplevel_classes. diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -664,13 +664,10 @@ self._interplevel_classes[w_type] = base # register other things - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - from pypy.objspace.std.listobject import W_ListObject - from pypy.objspace.std.setobject import W_SetObject - self._interplevel_classes[self.w_dict] = W_DictMultiObject self._interplevel_classes[self.w_list] = W_ListObject self._interplevel_classes[self.w_set] = W_SetObject + self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject @specialize.memo() def _get_interplevel_cls(self, w_type): From noreply at buildbot.pypy.org Wed May 22 18:12:34 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:34 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Add more jit unroll predicates. Message-ID: <20130522161234.D157D1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64456:85528249a156 Date: 2013-05-22 17:21 +0200 http://bitbucket.org/pypy/pypy/changeset/85528249a156/ Log: Add more jit unroll predicates. diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -17,7 +17,11 @@ UNROLL_CUTOFF = 10 -def tuple_unroll_condition(self, space, other): +def _unroll_condition(self): + return jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) + + +def _unroll_condition_cmp(self, space, other): return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF)) @@ -96,7 +100,7 @@ return space.w_NotImplemented return _compare_tuples(self, space, w_other) - @jit.look_inside_iff(tuple_unroll_condition) + @jit.look_inside_iff(_unroll_condition_cmp) def _compare_tuples(self, space, w_other): items1 = self.tolist() items2 = w_other.tolist() @@ -115,8 +119,7 @@ descr_gt = _make_tuple_comparison('gt') descr_ge = _make_tuple_comparison('ge') - @jit.look_inside_iff(lambda self, space, w_obj: - jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF)) + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) def descr_contains(self, space, w_obj): for w_item in self.tolist(): if space.eq_w(w_item, w_obj): @@ -167,6 +170,7 @@ def descr_getnewargs(self, space): return space.newtuple([space.newtuple(self.tolist())]) + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) def descr_count(self, space, w_obj): """count(obj) -> number of times obj appears in the tuple""" count = 0 @@ -177,6 +181,7 @@ @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), w_stop=gateway.WrappedDefault(sys.maxint)) + @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) def descr_index(self, space, w_obj, w_start, w_stop): """index(obj, [start, [stop]]) -> first index that obj appears in the tuple @@ -191,7 +196,8 @@ raise OperationError(space.w_ValueError, space.wrap("tuple.index(x): x not in tuple")) -W_AbstractTupleObject.typedef = StdTypeDef("tuple", +W_AbstractTupleObject.typedef = StdTypeDef( + "tuple", __doc__ = '''tuple() -> an empty tuple tuple(sequence) -> tuple initialized from sequence's items @@ -240,8 +246,7 @@ def length(self): return len(self.wrappeditems) - @jit.look_inside_iff(lambda self, space: jit.loop_unrolling_heuristic( - self.wrappeditems, len(self.wrappeditems), UNROLL_CUTOFF)) + @jit.look_inside_iff(lambda self, _1: _unroll_condition(self)) def descr_hash(self, space): # this is the CPython 2.4 algorithm (changed from 2.3) mult = 1000003 @@ -260,7 +265,7 @@ return space.w_NotImplemented return self._descr_eq(space, w_other) - @jit.look_inside_iff(tuple_unroll_condition) + @jit.look_inside_iff(_unroll_condition_cmp) def _descr_eq(self, space, w_other): items1 = self.wrappeditems items2 = w_other.tolist() From noreply at buildbot.pypy.org Wed May 22 18:12:36 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:36 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: style fixes Message-ID: <20130522161236.1436E1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64457:352a63d3b2ae Date: 2013-05-22 17:52 +0200 http://bitbucket.org/pypy/pypy/changeset/352a63d3b2ae/ Log: style fixes diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -86,8 +86,7 @@ myval = space.wrap(myval) if not space.eq_w(myval, otherval): return space.w_False - else: - return space.w_True + return space.w_True for i in iter_n: myval = getattr(self, 'value%s' % i) @@ -98,8 +97,7 @@ else: if myval != otherval: return space.w_False - else: - return space.w_True + return space.w_True descr_ne = negate(descr_eq) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -11,7 +11,6 @@ from rpython.rlib import jit from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rarithmetic import intmask -from rpython.tool.sourcetools import func_with_new_name UNROLL_CUTOFF = 10 @@ -29,13 +28,13 @@ class W_AbstractTupleObject(W_Root): __slots__ = () - def __repr__(w_self): + def __repr__(self): """representation for debugging purposes""" - reprlist = [repr(w_item) for w_item in w_self.tolist()] - return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) + reprlist = [repr(w_item) for w_item in self.tolist()] + return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] + def unwrap(self, space): + items = [space.unwrap(w_item) for w_item in self.tolist()] return tuple(items) def tolist(self): @@ -112,7 +111,8 @@ # No more items to compare -- compare sizes return space.newbool(op(len(items1), len(items2))) - return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') + compare_tuples.__name__ = 'descr_' + name + return compare_tuples descr_lt = _make_tuple_comparison('lt') descr_le = _make_tuple_comparison('le') @@ -233,9 +233,9 @@ class W_TupleObject(W_AbstractTupleObject): _immutable_fields_ = ['wrappeditems[*]'] - def __init__(w_self, wrappeditems): + def __init__(self, wrappeditems): make_sure_not_resized(wrappeditems) - w_self.wrappeditems = wrappeditems # a list of wrapped values + self.wrappeditems = wrappeditems # a list of wrapped values def tolist(self): return self.wrappeditems From noreply at buildbot.pypy.org Wed May 22 18:12:37 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:37 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove some misleading comments. Message-ID: <20130522161237.994981C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64458:42b01e72477d Date: 2013-05-22 18:01 +0200 http://bitbucket.org/pypy/pypy/changeset/42b01e72477d/ Log: Remove some misleading comments. diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -52,7 +52,6 @@ getitems_copy = func_with_new_name(tolist, 'getitems_copy') def descr_hash(self, space): - # XXX duplicate logic from tupleobject.py mult = 1000003 x = 0x345678 z = nValues diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -74,8 +74,6 @@ def descr_repr(self, space): items = self.tolist() - # XXX this is quite innefficient, still better than calling - # it via applevel if len(items) == 1: return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") tmp = ", ".join([space.str_w(space.repr(item)) for item in items]) @@ -248,7 +246,6 @@ @jit.look_inside_iff(lambda self, _1: _unroll_condition(self)) def descr_hash(self, space): - # this is the CPython 2.4 algorithm (changed from 2.3) mult = 1000003 x = 0x345678 z = len(self.wrappeditems) From noreply at buildbot.pypy.org Wed May 22 18:12:38 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:38 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Remove this comment, too. Message-ID: <20130522161238.E0EC11C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64459:fdc2d31e59f2 Date: 2013-05-22 18:04 +0200 http://bitbucket.org/pypy/pypy/changeset/fdc2d31e59f2/ Log: Remove this comment, too. diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -233,13 +233,13 @@ def __init__(self, wrappeditems): make_sure_not_resized(wrappeditems) - self.wrappeditems = wrappeditems # a list of wrapped values + self.wrappeditems = wrappeditems def tolist(self): return self.wrappeditems def getitems_copy(self): - return self.wrappeditems[:] # returns a resizable list + return self.wrappeditems[:] # returns a resizable list def length(self): return len(self.wrappeditems) From noreply at buildbot.pypy.org Wed May 22 18:12:40 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:40 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: hg merge default Message-ID: <20130522161240.2170F1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64460:ed1f2d516133 Date: 2013-05-22 18:07 +0200 http://bitbucket.org/pypy/pypy/changeset/ed1f2d516133/ Log: hg merge default diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -18,9 +18,9 @@ _is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) if sys.platform.startswith("linux") and _is_x86: - DEFL_ROOTFINDER = "asmgcc" + DEFL_ROOTFINDER_WITHJIT = "asmgcc" else: - DEFL_ROOTFINDER = "shadowstack" + DEFL_ROOTFINDER_WITHJIT = "shadowstack" IS_64_BITS = sys.maxint > 2147483647 @@ -94,7 +94,7 @@ ChoiceOption("gcrootfinder", "Strategy for finding GC Roots (framework GCs only)", ["n/a", "shadowstack", "asmgcc"], - DEFL_ROOTFINDER, + "shadowstack", cmdline="--gcrootfinder", requires={ "shadowstack": [("translation.gctransformer", "framework")], @@ -117,7 +117,7 @@ BoolOption("jit", "generate a JIT", default=False, suggests=[("translation.gc", DEFL_GC), - ("translation.gcrootfinder", DEFL_ROOTFINDER), + ("translation.gcrootfinder", DEFL_ROOTFINDER_WITHJIT), ("translation.list_comprehension_operations", True)]), ChoiceOption("jit_backend", "choose the backend for the JIT", ["auto", "x86", "x86-without-sse2", 'arm'], From noreply at buildbot.pypy.org Wed May 22 18:12:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:41 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Document branch. Message-ID: <20130522161241.562D51C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64461:691029723a3e Date: 2013-05-22 18:08 +0200 http://bitbucket.org/pypy/pypy/changeset/691029723a3e/ Log: Document branch. 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 @@ -28,3 +28,6 @@ .. branch: arm-stacklet Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple From noreply at buildbot.pypy.org Wed May 22 18:12:42 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:42 +0200 (CEST) Subject: [pypy-commit] pypy remove-tuple-smm: Close to-be-merged branch. Message-ID: <20130522161242.73CFF1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-tuple-smm Changeset: r64462:58da542ff319 Date: 2013-05-22 18:09 +0200 http://bitbucket.org/pypy/pypy/changeset/58da542ff319/ Log: Close to-be-merged branch. From noreply at buildbot.pypy.org Wed May 22 18:12:44 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:44 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge remove-tuple-smm Message-ID: <20130522161244.0B3F21C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64463:34b7c90d0438 Date: 2013-05-22 18:09 +0200 http://bitbucket.org/pypy/pypy/changeset/34b7c90d0438/ Log: hg merge remove-tuple-smm diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -215,10 +215,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), 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 @@ -28,3 +28,6 @@ .. branch: arm-stacklet Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -14,7 +14,6 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -310,31 +309,30 @@ w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): + if space.isinstance_w(w_prefix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_prefix)]) + return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + w_start, w_stop) + w_prefix = space.wrap(space.bufferstr_new_w(w_prefix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) -def str_startswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_prefix)]) - return stringobject.str_startswith__String_Tuple_ANY_ANY(space, w_str, w_prefix, - w_start, w_stop) - def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): + if space.isinstance_w(w_suffix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_suffix)]) + return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) -def str_endswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_suffix)]) - return stringobject.str_endswith__String_Tuple_ANY_ANY(space, w_str, w_suffix, - w_start, w_stop) - def str_join__Bytearray_ANY(space, w_self, w_list): list_w = space.listview(w_list) if not list_w: diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -23,7 +23,7 @@ from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.floatobject import W_FloatObject -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject @@ -288,14 +288,17 @@ raise_exception(space, 'bad marshal data') register(TYPE_STRINGREF, unmarshal_stringref) -def marshal_w__Tuple(space, w_tuple, m): - items = w_tuple.wrappeditems +def marshal_tuple(space, w_tuple, m): + if not isinstance(w_tuple, W_AbstractTupleObject): + raise_exception(space, "unmarshallable object") + items = w_tuple.tolist() m.put_tuple_w(TYPE_TUPLE, items) +handled_by_any.append(('tuple', marshal_tuple)) -def unmarshal_Tuple(space, u, tc): +def unmarshal_tuple(space, u, tc): items_w = u.get_tuple_w() return space.newtuple(items_w) -register(TYPE_TUPLE, unmarshal_Tuple) +register(TYPE_TUPLE, unmarshal_tuple) def marshal_list(space, w_list, m): if not isinstance(w_list, W_ListObject): diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -15,8 +15,6 @@ _registered_implementations.add(implcls) option_to_typename = { - "withspecialisedtuple" : ["specialisedtupleobject.W_SpecialisedTupleObject"], - "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], "withstrbuf" : ["strbufobject.W_StringBufferObject"], } @@ -38,7 +36,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -79,6 +76,7 @@ # not-multimethod based types + self.pythontypes.append(tupleobject.W_TupleObject.typedef) self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) @@ -90,7 +88,6 @@ boolobject.W_BoolObject: [], intobject.W_IntObject: [], floatobject.W_FloatObject: [], - tupleobject.W_TupleObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -109,7 +106,6 @@ self.imported_but_not_registered = { stringobject.W_StringObject: True, - tupleobject.W_TupleObject: True, } for option, value in config.objspace.std: if option.startswith("with") and option in option_to_typename: @@ -190,15 +186,6 @@ (unicodeobject.W_UnicodeObject, strbufobject.delegate_buf2unicode) ] - if config.objspace.std.withsmalltuple: - from pypy.objspace.std import smalltupleobject - self.typeorder[smalltupleobject.W_SmallTupleObject] += [ - (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] - - if config.objspace.std.withspecialisedtuple: - from pypy.objspace.std import specialisedtupleobject - self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ - (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] # put W_Root everywhere self.typeorder[W_Root] = [] diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -281,7 +281,7 @@ return newlong(self, val) def newtuple(self, list_w): - from pypy.objspace.std.tupletype import wraptuple + from pypy.objspace.std.tupleobject import wraptuple assert isinstance(list_w, list) make_sure_not_resized(list_w) return wraptuple(self, list_w) @@ -664,13 +664,10 @@ self._interplevel_classes[w_type] = base # register other things - from pypy.objspace.std.dictmultiobject import W_DictMultiObject - from pypy.objspace.std.listobject import W_ListObject - from pypy.objspace.std.setobject import W_SetObject - self._interplevel_classes[self.w_dict] = W_DictMultiObject self._interplevel_classes[self.w_list] = W_ListObject self._interplevel_classes[self.w_set] = W_SetObject + self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject @specialize.memo() def _get_interplevel_cls(self, w_type): diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/smalltupleobject.py +++ /dev/null @@ -1,161 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement -from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.interpreter import gateway -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib.unroll import unrolling_iterable -from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject - -class W_SmallTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] - return tuple(items) - -def make_specialized_class(n): - iter_n = unrolling_iterable(range(n)) - class cls(W_SmallTupleObject): - - def __init__(self, values): - assert len(values) == n - for i in iter_n: - setattr(self, 'w_value%s' % i, values[i]) - - def tolist(self): - l = [None] * n - for i in iter_n: - l[i] = getattr(self, 'w_value%s' % i) - return l - - # same source code, but builds and returns a resizable list - getitems_copy = func_with_new_name(tolist, 'getitems_copy') - - def length(self): - return n - - def getitem(self, index): - for i in iter_n: - if index == i: - return getattr(self,'w_value%s' % i) - raise IndexError - - def setitem(self, index, w_item): - for i in iter_n: - if index == i: - setattr(self, 'w_value%s' % i, w_item) - return - raise IndexError - - def eq(self, space, w_other): - if n != w_other.length(): - return space.w_False - for i in iter_n: - item1 = getattr(self,'w_value%s' % i) - item2 = w_other.getitem(i) - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - - def hash(self, space): - mult = 1000003 - x = 0x345678 - z = n - for i in iter_n: - w_item = getattr(self, 'w_value%s' % i) - y = space.int_w(space.hash(w_item)) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return space.wrap(intmask(x)) - - cls.__name__ = "W_SmallTupleObject%s" % n - return cls - -W_SmallTupleObject2 = make_specialized_class(2) -W_SmallTupleObject3 = make_specialized_class(3) -W_SmallTupleObject4 = make_specialized_class(4) -W_SmallTupleObject5 = make_specialized_class(5) -W_SmallTupleObject6 = make_specialized_class(6) -W_SmallTupleObject7 = make_specialized_class(7) -W_SmallTupleObject8 = make_specialized_class(8) - -registerimplementation(W_SmallTupleObject) - -def delegate_SmallTuple2Tuple(space, w_small): - return W_TupleObject(w_small.tolist()) - -def len__SmallTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SmallTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SmallTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_smalltuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SmallTuple_ANY(space, w_tuple, w_times): - return mul_smalltuple_times(space, w_tuple, w_times) - -def mul__ANY_SmallTuple(space, w_times, w_tuple): - return mul_smalltuple_times(space, w_tuple, w_times) - -def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def hash__SmallTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -1,63 +1,23 @@ from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.tupleobject import W_AbstractTupleObject -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.util import negate +from rpython.rlib.objectmodel import compute_hash from rpython.rlib.rarithmetic import intmask -from rpython.rlib.objectmodel import compute_hash from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name + class NotSpecialised(Exception): pass -class W_SpecialisedTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - __slots__ = [] - - def __repr__(self): - """ representation for debugging purposes """ - reprlist = [repr(item) for item in self._to_unwrapped_list()] - return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def _to_unwrapped_list(self): - "NOT_RPYTHON" - raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(self, space): - return tuple(self._to_unwrapped_list()) - - def delegating(self): - pass # for tests only - def make_specialised_class(typetuple): assert type(typetuple) == tuple - + nValues = len(typetuple) iter_n = unrolling_iterable(range(nValues)) - - class cls(W_SpecialisedTupleObject): + + class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space assert len(values_w) == nValues @@ -80,7 +40,7 @@ return nValues def tolist(self): - list_w = [None] * nValues + list_w = [None] * nValues for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -91,18 +51,7 @@ # same source code, but builds and returns a resizable list getitems_copy = func_with_new_name(tolist, 'getitems_copy') - def _to_unwrapped_list(self): - "NOT_RPYTHON" - list_w = [None] * nValues - for i in iter_n: - value = getattr(self, 'value%s' % i) - if typetuple[i] == object: - value = self.space.unwrap(value) - list_w[i] = value - return list_w - - def hash(self, space): - # XXX duplicate logic from tupleobject.py + def descr_hash(self, space): mult = 1000003 x = 0x345678 z = nValues @@ -123,50 +72,45 @@ x += 97531 return space.wrap(intmask(x)) - def _eq(self, w_other): + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplementedError if not isinstance(w_other, cls): - # if we are not comparing same types, give up - raise FailedToImplement + if nValues != w_other.length(): + return space.w_False + for i in iter_n: + myval = getattr(self, 'value%s' % i) + otherval = w_other.getitem(space, i) + if typetuple[i] != object: + myval = space.wrap(myval) + if not space.eq_w(myval, otherval): + return space.w_False + return space.w_True + for i in iter_n: - myval = getattr(self, 'value%s' % i) + myval = getattr(self, 'value%s' % i) otherval = getattr(w_other, 'value%s' % i) if typetuple[i] == object: if not self.space.eq_w(myval, otherval): - return False + return space.w_False else: if myval != otherval: - return False - else: - return True + return space.w_False + return space.w_True - def eq(self, space, w_other): - return space.newbool(self._eq(w_other)) + descr_ne = negate(descr_eq) - def ne(self, space, w_other): - return space.newbool(not self._eq(w_other)) - -## def _compare(self, compare_op, w_other): -## if not isinstance(w_other, cls): -## raise FailedToImplement -## ncmp = min(self.length(), w_other.length()) -## for i in iter_n: -## if typetuple[i] == Any:#like space.eq on wrapped or two params? -## raise FailedToImplement -## if ncmp > i: -## l_val = getattr(self, 'value%s' % i) -## r_val = getattr(w_other, 'value%s' % i) -## if l_val != r_val: -## return compare_op(l_val, r_val) -## return compare_op(self.length(), w_other.length()) - - def getitem(self, index): + def getitem(self, space, index): + if index < 0: + index += nValues for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) if typetuple[i] != object: - value = self.space.wrap(value) + value = space.wrap(value) return value - raise IndexError + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) cls.__name__ = ('W_SpecialisedTupleObject_' + ''.join([t.__name__[0] for t in typetuple])) @@ -177,129 +121,21 @@ _specialisations = [] Cls_ii = make_specialised_class((int, int)) -#Cls_is = make_specialised_class((int, str)) -#Cls_io = make_specialised_class((int, object)) -#Cls_si = make_specialised_class((str, int)) -#Cls_ss = make_specialised_class((str, str)) -#Cls_so = make_specialised_class((str, object)) -#Cls_oi = make_specialised_class((object, int)) -#Cls_os = make_specialised_class((object, str)) Cls_oo = make_specialised_class((object, object)) Cls_ff = make_specialised_class((float, float)) -#Cls_ooo = make_specialised_class((object, object, object)) def makespecialisedtuple(space, list_w): if len(list_w) == 2: w_arg1, w_arg2 = list_w w_type1 = space.type(w_arg1) - #w_type2 = space.type(w_arg2) - # if w_type1 is space.w_int: w_type2 = space.type(w_arg2) if w_type2 is space.w_int: return Cls_ii(space, w_arg1, w_arg2) - #elif w_type2 is space.w_str: - # return Cls_is(space, w_arg1, w_arg2) - #else: - # return Cls_io(space, w_arg1, w_arg2) - # - #elif w_type1 is space.w_str: - # if w_type2 is space.w_int: - # return Cls_si(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_ss(space, w_arg1, w_arg2) - # else: - # return Cls_so(space, w_arg1, w_arg2) - # elif w_type1 is space.w_float: w_type2 = space.type(w_arg2) if w_type2 is space.w_float: return Cls_ff(space, w_arg1, w_arg2) - # - #else: - # if w_type2 is space.w_int: - # return Cls_oi(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_os(space, w_arg1, w_arg2) - # else: return Cls_oo(space, w_arg1, w_arg2) - # - #elif len(list_w) == 3: - # return Cls_ooo(space, list_w[0], list_w[1], list_w[2]) else: raise NotSpecialised - -# ____________________________________________________________ - -registerimplementation(W_SpecialisedTupleObject) - -def delegate_SpecialisedTuple2Tuple(space, w_specialised): - w_specialised.delegating() - return W_TupleObject(w_specialised.tolist()) - -def len__SpecialisedTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SpecialisedTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SpecialisedTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_specialisedtuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SpecialisedTuple_ANY(space, w_tuple, w_times): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def mul__ANY_SpecialisedTuple(space, w_times, w_tuple): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.ne(space, w_tuple2) - -##from operator import lt, le, ge, gt - -##def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(lt, w_tuple2)) - -##def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(le, w_tuple2)) - -##def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(ge, w_tuple2)) - -##def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(gt, w_tuple2)) - -def hash__SpecialisedTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -12,7 +12,6 @@ from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringtype import ( joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) -from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib import jit from rpython.rlib.objectmodel import ( compute_hash, compute_unique_id, specialize) @@ -684,7 +683,9 @@ w_end, True) return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) -def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): +def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): + if not space.isinstance_w(w_suffixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): @@ -702,7 +703,9 @@ w_end, True) return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) -def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): +def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): + if not space.isinstance_w(w_prefixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ /dev/null @@ -1,84 +0,0 @@ -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject -from pypy.interpreter.error import OperationError -from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject -from pypy.tool.pytest.objspace import gettestobjspace - -class AppTestW_SmallTupleObject(AppTestW_TupleObject): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def setup_class(cls): - cls.w_issmall = cls.space.appexec([], """(): - import __pypy__ - def issmall(obj): - assert "SmallTuple" in __pypy__.internal_repr(obj) - return issmall - """) - - def test_smalltuple(self): - self.issmall((1,2)) - self.issmall((1,2,3)) - - def test_slicing_to_small(self): - self.issmall((1, 2, 3)[0:2]) # SmallTuple2 - self.issmall((1, 2, 3)[0:2:1]) - - self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3 - self.issmall((1, 2, 3, 4)[0:3:1]) - - def test_adding_to_small(self): - self.issmall((1,)+(2,)) # SmallTuple2 - self.issmall((1,1)+(2,)) # SmallTuple3 - self.issmall((1,)+(2,3)) - - def test_multiply_to_small(self): - self.issmall((1,)*2) - self.issmall((1,)*3) - - def test_slicing_from_small(self): - assert (1,2)[0:1:1] == (1,) - assert (1,2,3)[0:2:1] == (1,2) - - def test_eq(self): - a = (1,2,3) - b = (1,2,3) - assert a == b - - c = (1,3,2) - assert a != c - - def test_hash(self): - a = (1,2,3) - b = (1,2,3) - assert hash(a) == hash(b) - - c = (1,3,2) - assert hash(a) != hash(c) - -class TestW_SmallTupleObject(): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def test_issmalltupleobject(self): - w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - assert isinstance(w_tuple, W_SmallTupleObject) - - def test_hash_agains_normal_tuple(self): - normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) - w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) - w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - assert isinstance(w_smalltuple, W_SmallTupleObject) - assert isinstance(w_tuple, W_TupleObject) - assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) - - def test_setitem(self): - w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - w_smalltuple.setitem(0, self.space.wrap(5)) - list_w = w_smalltuple.tolist() - assert len(list_w) == 2 - assert self.space.eq_w(list_w[0], self.space.wrap(5)) - assert self.space.eq_w(list_w[1], self.space.wrap(2)) diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -1,11 +1,7 @@ -import py, sys +from pypy.objspace.std.specialisedtupleobject import _specialisations +from pypy.objspace.std.test import test_tupleobject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject -from pypy.objspace.std.specialisedtupleobject import _specialisations -from pypy.interpreter.error import OperationError from pypy.tool.pytest.objspace import gettestobjspace -from pypy.objspace.std.test import test_tupleobject -from pypy.interpreter import gateway for cls in _specialisations: @@ -18,62 +14,43 @@ def test_isspecialisedtupleobjectintint(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert isinstance(w_tuple, W_SpecialisedTupleObject_ii) - + def test_isnotspecialisedtupleobject(self): w_tuple = self.space.newtuple([self.space.wrap({})]) - assert not isinstance(w_tuple, W_SpecialisedTupleObject) - + assert not 'W_SpecialisedTupleObject' in type(w_tuple).__name__ + def test_specialisedtupleclassname(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii' def test_hash_against_normal_tuple(self): - N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": False}) - S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) - def hash_test(values, must_be_specialized=True): - N_values_w = [N_space.wrap(value) for value in values] - S_values_w = [S_space.wrap(value) for value in values] - N_w_tuple = N_space.newtuple(N_values_w) - S_w_tuple = S_space.newtuple(S_values_w) + N_values_w = [self.space.wrap(value) for value in values] + S_values_w = [self.space.wrap(value) for value in values] + N_w_tuple = W_TupleObject(N_values_w) + S_w_tuple = self.space.newtuple(S_values_w) if must_be_specialized: - assert isinstance(S_w_tuple, W_SpecialisedTupleObject) - assert isinstance(N_w_tuple, W_TupleObject) - assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) - assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) + assert 'W_SpecialisedTupleObject' in type(S_w_tuple).__name__ + assert self.space.is_true(self.space.eq(N_w_tuple, S_w_tuple)) + assert self.space.is_true( + self.space.eq(self.space.hash(N_w_tuple), + self.space.hash(S_w_tuple))) - hash_test([1,2]) - hash_test([1.5,2.8]) - hash_test([1.0,2.0]) - hash_test(['arbitrary','strings']) - hash_test([1,(1,2,3,4)]) - hash_test([1,(1,2)]) - hash_test([1,('a',2)]) - hash_test([1,()]) - hash_test([1,2,3], must_be_specialized=False) + hash_test([1, 2]) + hash_test([1.5, 2.8]) + hash_test([1.0, 2.0]) + hash_test(['arbitrary', 'strings']) + hash_test([1, (1, 2, 3, 4)]) + hash_test([1, (1, 2)]) + hash_test([1, ('a', 2)]) + hash_test([1, ()]) + hash_test([1, 2, 3], must_be_specialized=False) class AppTestW_SpecialisedTupleObject: spaceconfig = {"objspace.std.withspecialisedtuple": True} - def setup_class(cls): - def forbid_delegation(space, w_tuple): - def delegation_forbidden(): - # haaaack - co = sys._getframe(2).f_code - if co.co_name.startswith('_mm_repr_tuple'): - return - raise OperationError(space.w_ReferenceError, w_tuple) - w_tuple.delegating = delegation_forbidden - return w_tuple - if cls.runappdirect: - cls.w_forbid_delegation = lambda self, x: x - cls.test_delegation = lambda self: skip("runappdirect") - else: - cls.w_forbid_delegation = cls.space.wrap( - gateway.interp2app(forbid_delegation)) - def w_isspecialised(self, obj, expected=''): import __pypy__ r = __pypy__.internal_repr(obj) @@ -101,16 +78,12 @@ obj = (1, 2, 3) assert self.isspecialised(obj, '_ooo') - def test_delegation(self): - t = self.forbid_delegation((42, 43)) - raises(ReferenceError, t.__getslice__, 0, 1) - def test_len(self): - t = self.forbid_delegation((42,43)) + t = (42, 43) assert len(t) == 2 def test_notspecialisedtuple(self): - assert not self.isspecialised((42,43,44,45)) + assert not self.isspecialised((42, 43, 44, 45)) assert not self.isspecialised((1.5,)) def test_slicing_to_specialised(self): @@ -133,79 +106,79 @@ def test_eq_no_delegation(self): t = (1,) - a = self.forbid_delegation(t + (2,)) + a = t + (2,) b = (1, 2) assert a == b c = (2, 1) assert not a == c - def test_eq_can_delegate(self): - a = (1,2) - b = (1,3,2) + def test_eq_can_delegate(self): + a = (1, 2) + b = (1, 3, 2) assert not a == b values = [2, 2L, 2.0, 1, 1L, 1.0] for x in values: for y in values: - assert ((1,2) == (x,y)) == (1 == x and 2 == y) + assert ((1, 2) == (x, y)) == (1 == x and 2 == y) def test_neq(self): - a = self.forbid_delegation((1,2)) + a = (1, 2) b = (1,) - b = b+(2,) + b = b + (2,) assert not a != b - - c = (1,3) + + c = (1, 3) assert a != c - + def test_ordering(self): - a = (1,2) #self.forbid_delegation((1,2)) --- code commented out - assert a < (2,2) - assert a < (1,3) - assert not a < (1,2) + a = (1, 2) + assert a < (2, 2) + assert a < (1, 3) + assert not a < (1, 2) - assert a <= (2,2) - assert a <= (1,2) - assert not a <= (1,1) - - assert a >= (0,2) - assert a >= (1,2) - assert not a >= (1,3) - - assert a > (0,2) - assert a > (1,1) - assert not a > (1,3) + assert a <= (2, 2) + assert a <= (1, 2) + assert not a <= (1, 1) - assert (2,2) > a - assert (1,3) > a - assert not (1,2) > a - - assert (2,2) >= a - assert (1,2) >= a - assert not (1,1) >= a - - assert (0,2) <= a - assert (1,2) <= a - assert not (1,3) <= a - - assert (0,2) < a - assert (1,1) < a - assert not (1,3) < a + assert a >= (0, 2) + assert a >= (1, 2) + assert not a >= (1, 3) + + assert a > (0, 2) + assert a > (1, 1) + assert not a > (1, 3) + + assert (2, 2) > a + assert (1, 3) > a + assert not (1, 2) > a + + assert (2, 2) >= a + assert (1, 2) >= a + assert not (1, 1) >= a + + assert (0, 2) <= a + assert (1, 2) <= a + assert not (1, 3) <= a + + assert (0, 2) < a + assert (1, 1) < a + assert not (1, 3) < a def test_hash(self): - a = (1,2) + a = (1, 2) b = (1,) - b += (2,) # else a and b refer to same constant + b += (2,) # else a and b refer to same constant assert hash(a) == hash(b) - c = (2,4) + c = (2, 4) assert hash(a) != hash(c) assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L)) def test_getitem(self): - t = self.forbid_delegation((5,3)) + t = (5, 3) assert (t)[0] == 5 assert (t)[1] == 3 assert (t)[-1] == 3 @@ -216,14 +189,14 @@ def test_three_tuples(self): if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - b = self.forbid_delegation((1, 2, 3)) + b = (1, 2, 3) c = (1,) d = c + (2, 3) assert self.isspecialised(d) assert b == d def test_mongrel(self): - a = self.forbid_delegation((2.2, '333')) + a = (2.2, '333') assert self.isspecialised(a) assert len(a) == 2 assert a[0] == 2.2 and a[1] == '333' @@ -233,7 +206,7 @@ # if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - a = self.forbid_delegation((1, 2.2, '333')) + a = (1, 2.2, '333') assert self.isspecialised(a) assert len(a) == 3 assert a[0] == 1 and a[1] == 2.2 and a[2] == '333' diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -1,17 +1,16 @@ -#from __future__ import nested_scopes +from pypy.interpreter.error import OperationError from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.interpreter.error import OperationError + class TestW_TupleObject: - def test_is_true(self): w = self.space.wrap w_tuple = W_TupleObject([]) - assert self.space.is_true(w_tuple) == False + assert self.space.is_true(w_tuple) is False w_tuple = W_TupleObject([w(5)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True w_tuple = W_TupleObject([w(5), w(3)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True def test_len(self): w = self.space.wrap @@ -19,7 +18,7 @@ assert self.space.eq_w(self.space.len(w_tuple), w(0)) w_tuple = W_TupleObject([w(5)]) assert self.space.eq_w(self.space.len(w_tuple), w(1)) - w_tuple = W_TupleObject([w(5), w(3), w(99)]*111) + w_tuple = W_TupleObject([w(5), w(3), w(99)] * 111) assert self.space.eq_w(self.space.len(w_tuple), w(333)) def test_getitem(self): @@ -65,7 +64,7 @@ w_tuple2 = W_TupleObject([w(-7)] * 111) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple1), W_TupleObject([w(5), w(3), w(99), - w(5), w(3), w(99)])) + w(5), w(3), w(99)])) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple2), W_TupleObject([w(5), w(3), w(99)] + [w(-7)] * 111)) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple0), w_tuple1) @@ -77,7 +76,7 @@ arg = w(2) n = 3 w_tup = W_TupleObject([arg]) - w_tup3 = W_TupleObject([arg]*n) + w_tup3 = W_TupleObject([arg] * n) w_res = self.space.mul(w_tup, w(n)) assert self.space.eq_w(w_tup3, w_res) # commute @@ -91,26 +90,26 @@ w = self.space.wrap def test1(testtuple, start, stop, step, expected): - w_slice = self.space.newslice(w(start), w(stop), w(step)) + w_slice = self.space.newslice(w(start), w(stop), w(step)) w_tuple = W_TupleObject([w(i) for i in testtuple]) w_result = self.space.getitem(w_tuple, w_slice) assert self.space.unwrap(w_result) == expected - - for testtuple in [(), (5,3,99), tuple(range(5,555,10))]: + + for testtuple in [(), (5, 3, 99), tuple(range(5, 555, 10))]: for start in [-2, -1, 0, 1, 10]: for end in [-1, 0, 2, 999]: test1(testtuple, start, end, 1, testtuple[start:end]) - test1((5,7,1,4), 3, 1, -2, (4,)) - test1((5,7,1,4), 3, 0, -2, (4, 7)) - test1((5,7,1,4), 3, -1, -2, ()) - test1((5,7,1,4), -2, 11, 2, (1,)) - test1((5,7,1,4), -3, 11, 2, (7, 4)) - test1((5,7,1,4), -5, 11, 2, (5, 1)) + test1((5, 7, 1, 4), 3, 1, -2, (4,)) + test1((5, 7, 1, 4), 3, 0, -2, (4, 7)) + test1((5, 7, 1, 4), 3, -1, -2, ()) + test1((5, 7, 1, 4), -2, 11, 2, (1,)) + test1((5, 7, 1, 4), -3, 11, 2, (7, 4)) + test1((5, 7, 1, 4), -5, 11, 2, (5, 1)) def test_eq(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -126,9 +125,10 @@ self.space.w_True) assert self.space.eq_w(self.space.eq(w_tuple2, w_tuple3), self.space.w_False) + def test_ne(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -144,9 +144,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ne(w_tuple2, w_tuple3), self.space.w_True) + def test_lt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -165,10 +166,10 @@ self.space.w_True) assert self.space.eq_w(self.space.lt(w_tuple4, w_tuple3), self.space.w_True) - + def test_ge(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -187,10 +188,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ge(w_tuple4, w_tuple3), self.space.w_False) - + def test_gt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -209,10 +210,10 @@ self.space.w_False) assert self.space.eq_w(self.space.gt(w_tuple4, w_tuple3), self.space.w_False) - + def test_le(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -234,28 +235,27 @@ class AppTestW_TupleObject: - def test_is_true(self): assert not () assert (5,) - assert (5,3) + assert (5, 3) def test_len(self): assert len(()) == 0 assert len((5,)) == 1 - assert len((5,3,99,1,2,3,4,5,6)) == 9 + assert len((5, 3, 99, 1, 2, 3, 4, 5, 6)) == 9 def test_getitem(self): - assert (5,3)[0] == 5 - assert (5,3)[1] == 3 - assert (5,3)[-1] == 3 - assert (5,3)[-2] == 5 - raises(IndexError, "(5,3)[2]") + assert (5, 3)[0] == 5 + assert (5, 3)[1] == 3 + assert (5, 3)[-1] == 3 + assert (5, 3)[-2] == 5 + raises(IndexError, "(5, 3)[2]") raises(IndexError, "(5,)[1]") raises(IndexError, "()[0]") def test_iter(self): - t = (5,3,99) + t = (5, 3, 99) i = iter(t) assert i.next() == 5 assert i.next() == 3 @@ -263,7 +263,7 @@ raises(StopIteration, i.next) def test_contains(self): - t = (5,3,99) + t = (5, 3, 99) assert 5 in t assert 99 in t assert not 11 in t @@ -271,35 +271,35 @@ def test_add(self): t0 = () - t1 = (5,3,99) + t1 = (5, 3, 99) assert t0 + t0 == t0 assert t1 + t0 == t1 - assert t1 + t1 == (5,3,99,5,3,99) + assert t1 + t1 == (5, 3, 99, 5, 3, 99) def test_mul(self): assert () * 10 == () - assert (5,) * 3 == (5,5,5) - assert (5,2) * 2 == (5,2,5,2) + assert (5,) * 3 == (5, 5, 5) + assert (5, 2) * 2 == (5, 2, 5, 2) def test_mul_identity(self): - t = (1,2,3) + t = (1, 2, 3) assert (t * 1) is t def test_mul_subtype(self): class T(tuple): pass - t = T([1,2,3]) + t = T([1, 2, 3]) assert (t * 1) is not t assert (t * 1) == t def test_getslice_2(self): - assert (5,2,3)[1:2] == (2,) + assert (5, 2, 3)[1:2] == (2,) def test_eq(self): t0 = () - t1 = (5,3,99) - t2 = (5,3,99) - t3 = (5,3,99,-1) - t4 = (5,3,9,1) + t1 = (5, 3, 99) + t2 = (5, 3, 99) + t3 = (5, 3, 99, -1) + t4 = (5, 3, 9, 1) assert not t0 == t1 assert t0 != t1 assert t1 == t2 @@ -321,15 +321,15 @@ # check that hash behaves as in 2.4 for at least 31 bits assert hash(()) & 0x7fffffff == 0x35d373 assert hash((12,)) & 0x7fffffff == 0x1cca0557 - assert hash((12,34)) & 0x7fffffff == 0x153e2a41 + assert hash((12, 34)) & 0x7fffffff == 0x153e2a41 def test_getnewargs(self): - assert () .__getnewargs__() == ((),) + assert () .__getnewargs__() == ((),) def test_repr(self): assert repr((1,)) == '(1,)' assert repr(()) == '()' - assert repr((1,2,3)) == '(1, 2, 3)' + assert repr((1, 2, 3)) == '(1, 2, 3)' def test_getslice(self): assert ('a', 'b', 'c').__getslice__(-17, 2) == ('a', 'b') diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,212 +1,297 @@ +import sys +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate +from rpython.rlib import jit +from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib import jit -from rpython.tool.sourcetools import func_with_new_name + UNROLL_CUTOFF = 10 -class W_AbstractTupleObject(W_Object): + +def _unroll_condition(self): + return jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) + + +def _unroll_condition_cmp(self, space, other): + return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF)) + + +class W_AbstractTupleObject(W_Root): __slots__ = () + def __repr__(self): + """representation for debugging purposes""" + reprlist = [repr(w_item) for w_item in self.tolist()] + return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) + + def unwrap(self, space): + items = [space.unwrap(w_item) for w_item in self.tolist()] + return tuple(items) + def tolist(self): - "Returns the items, as a fixed-size list." + """Returns the items, as a fixed-size list.""" raise NotImplementedError def getitems_copy(self): - "Returns a copy of the items, as a resizable list." + """Returns a copy of the items, as a resizable list.""" raise NotImplementedError + def length(self): + raise NotImplementedError + + def getitem(self, space, item): + raise NotImplementedError + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + + def descr_iter(self, space): + from pypy.objspace.std import iterobject + return iterobject.W_FastTupleIterObject(self, self.tolist()) + + @staticmethod + def descr_new(space, w_tupletype, w_sequence=None): + if w_sequence is None: + tuple_w = [] + elif (space.is_w(w_tupletype, space.w_tuple) and + space.is_w(space.type(w_sequence), space.w_tuple)): + return w_sequence + else: + tuple_w = space.fixedview(w_sequence) + w_obj = space.allocate_instance(W_TupleObject, w_tupletype) + W_TupleObject.__init__(w_obj, tuple_w) + return w_obj + + def descr_repr(self, space): + items = self.tolist() + if len(items) == 1: + return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") + tmp = ", ".join([space.str_w(space.repr(item)) for item in items]) + return space.wrap("(" + tmp + ")") + + def descr_hash(self, space): + raise NotImplementedError + + def descr_eq(self, space, w_other): + raise NotImplementedError + + def descr_ne(self, space, w_other): + raise NotImplementedError + + def _make_tuple_comparison(name): + import operator + op = getattr(operator, name) + + def compare_tuples(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return _compare_tuples(self, space, w_other) + + @jit.look_inside_iff(_unroll_condition_cmp) + def _compare_tuples(self, space, w_other): + items1 = self.tolist() + items2 = w_other.tolist() + ncmp = min(len(items1), len(items2)) + # Search for the first index where items are different + for p in range(ncmp): + if not space.eq_w(items1[p], items2[p]): + return getattr(space, name)(items1[p], items2[p]) + # No more items to compare -- compare sizes + return space.newbool(op(len(items1), len(items2))) + + compare_tuples.__name__ = 'descr_' + name + return compare_tuples + + descr_lt = _make_tuple_comparison('lt') + descr_le = _make_tuple_comparison('le') + descr_gt = _make_tuple_comparison('gt') + descr_ge = _make_tuple_comparison('ge') + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_contains(self, space, w_obj): + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + return space.w_True + return space.w_False + + def descr_add(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + items1 = self.tolist() + items2 = w_other.tolist() + return space.newtuple(items1 + items2) + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + if times == 1 and space.type(self) == space.w_tuple: + return self + items = self.tolist() + return space.newtuple(items * times) + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + return self._getslice(space, w_index) + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") + return self.getitem(space, index) + + def _getslice(self, space, w_index): + items = self.tolist() + length = len(items) + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = items[start] + start += step + return space.newtuple(subitems) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + return space.newtuple(self.tolist()[start:stop]) + + def descr_getnewargs(self, space): + return space.newtuple([space.newtuple(self.tolist())]) + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_count(self, space, w_obj): + """count(obj) -> number of times obj appears in the tuple""" + count = 0 + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + count += 1 + return space.wrap(count) + + @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), + w_stop=gateway.WrappedDefault(sys.maxint)) + @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) + def descr_index(self, space, w_obj, w_start, w_stop): + """index(obj, [start, [stop]]) -> first index that obj appears in the + tuple + """ + length = self.length() + start, stop = slicetype.unwrap_start_stop(space, length, w_start, + w_stop) + for i in range(start, min(stop, length)): + w_item = self.tolist()[i] + if space.eq_w(w_item, w_obj): + return space.wrap(i) + raise OperationError(space.w_ValueError, + space.wrap("tuple.index(x): x not in tuple")) + +W_AbstractTupleObject.typedef = StdTypeDef( + "tuple", + __doc__ = '''tuple() -> an empty tuple +tuple(sequence) -> tuple initialized from sequence's items + +If the argument is a tuple, the return value is the same object.''', + __new__ = interp2app(W_AbstractTupleObject.descr_new), + __repr__ = interp2app(W_AbstractTupleObject.descr_repr), + __hash__ = interpindirect2app(W_AbstractTupleObject.descr_hash), + + __eq__ = interpindirect2app(W_AbstractTupleObject.descr_eq), + __ne__ = interpindirect2app(W_AbstractTupleObject.descr_ne), + __lt__ = interp2app(W_AbstractTupleObject.descr_lt), + __le__ = interp2app(W_AbstractTupleObject.descr_le), + __gt__ = interp2app(W_AbstractTupleObject.descr_gt), + __ge__ = interp2app(W_AbstractTupleObject.descr_ge), + + __len__ = interp2app(W_AbstractTupleObject.descr_len), + __iter__ = interp2app(W_AbstractTupleObject.descr_iter), + __contains__ = interp2app(W_AbstractTupleObject.descr_contains), + + __add__ = interp2app(W_AbstractTupleObject.descr_add), + __mul__ = interp2app(W_AbstractTupleObject.descr_mul), + __rmul__ = interp2app(W_AbstractTupleObject.descr_mul), + + __getitem__ = interp2app(W_AbstractTupleObject.descr_getitem), + __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice), + + __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs), + count = interp2app(W_AbstractTupleObject.descr_count), + index = interp2app(W_AbstractTupleObject.descr_index) +) + class W_TupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef _immutable_fields_ = ['wrappeditems[*]'] - def __init__(w_self, wrappeditems): + def __init__(self, wrappeditems): make_sure_not_resized(wrappeditems) - w_self.wrappeditems = wrappeditems # a list of wrapped values - - def __repr__(w_self): - """ representation for debugging purposes """ - reprlist = [repr(w_item) for w_item in w_self.wrappeditems] - return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] - return tuple(items) + self.wrappeditems = wrappeditems def tolist(self): return self.wrappeditems def getitems_copy(self): - return self.wrappeditems[:] # returns a resizable list + return self.wrappeditems[:] # returns a resizable list -registerimplementation(W_TupleObject) + def length(self): + return len(self.wrappeditems) + @jit.look_inside_iff(lambda self, _1: _unroll_condition(self)) + def descr_hash(self, space): + mult = 1000003 + x = 0x345678 + z = len(self.wrappeditems) + for w_item in self.wrappeditems: + y = space.hash_w(w_item) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) -def len__Tuple(space, w_tuple): - result = len(w_tuple.wrappeditems) - return wrapint(space, result) + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) -def getitem__Tuple_ANY(space, w_tuple, w_index): - # getindex_w should get a second argument space.w_IndexError, - # but that doesn't exist the first time this is called. - try: - w_IndexError = space.w_IndexError - except AttributeError: - w_IndexError = None - index = space.getindex_w(w_index, w_IndexError, "tuple index") - try: - return w_tuple.wrappeditems[index] - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) + @jit.look_inside_iff(_unroll_condition_cmp) + def _descr_eq(self, space, w_other): + items1 = self.wrappeditems + items2 = w_other.tolist() + lgt1 = len(items1) + lgt2 = len(items2) + if lgt1 != lgt2: + return space.w_False + for i in range(lgt1): + item1 = items1[i] + item2 = items2[i] + if not space.eq_w(item1, item2): + return space.w_False + return space.w_True -def getitem__Tuple_Slice(space, w_tuple, w_slice): - items = w_tuple.wrappeditems - length = len(items) - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = items[start] - start += step - return space.newtuple(subitems) + descr_ne = negate(descr_eq) -def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return space.newtuple(w_tuple.wrappeditems[start:stop]) + def getitem(self, space, index): + try: + return self.wrappeditems[index] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) - at jit.look_inside_iff(lambda space, w_tuple, w_obj: - jit.loop_unrolling_heuristic(w_tuple, len(w_tuple.wrappeditems), UNROLL_CUTOFF)) -def contains__Tuple_ANY(space, w_tuple, w_obj): - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - return space.w_True - return space.w_False -def iter__Tuple(space, w_tuple): - from pypy.objspace.std import iterobject - return iterobject.W_FastTupleIterObject(w_tuple, w_tuple.wrappeditems) - -def add__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - return space.newtuple(items1 + items2) - -def mul_tuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.wrappeditems - return space.newtuple(items * times) - -def mul__Tuple_ANY(space, w_tuple, w_times): - return mul_tuple_times(space, w_tuple, w_times) - -def mul__ANY_Tuple(space, w_times, w_tuple): - return mul_tuple_times(space, w_tuple, w_times) - -def tuple_unroll_condition(space, w_tuple1, w_tuple2): - return jit.loop_unrolling_heuristic(w_tuple1, len(w_tuple1.wrappeditems), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_tuple2, len(w_tuple2.wrappeditems), UNROLL_CUTOFF) - - at jit.look_inside_iff(tuple_unroll_condition) -def eq__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - lgt1 = len(items1) - lgt2 = len(items2) - if lgt1 != lgt2: - return space.w_False - for i in range(lgt1): - item1 = items1[i] - item2 = items2[i] - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - -def _make_tuple_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(tuple_unroll_condition) - def compare_tuples(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - ncmp = min(len(items1), len(items2)) - # Search for the first index where items are different - for p in range(ncmp): - if not space.eq_w(items1[p], items2[p]): - return getattr(space, name)(items1[p], items2[p]) - # No more items to compare -- compare sizes - return space.newbool(op(len(items1), len(items2))) - return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') - -lt__Tuple_Tuple = _make_tuple_comparison('lt') -le__Tuple_Tuple = _make_tuple_comparison('le') -gt__Tuple_Tuple = _make_tuple_comparison('gt') -ge__Tuple_Tuple = _make_tuple_comparison('ge') - -def repr__Tuple(space, w_tuple): - items = w_tuple.wrappeditems - # XXX this is quite innefficient, still better than calling - # it via applevel - if len(items) == 1: - return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") - return space.wrap("(" + - (", ".join([space.str_w(space.repr(item)) for item in items])) - + ")") - -def hash__Tuple(space, w_tuple): - return space.wrap(hash_tuple(space, w_tuple.wrappeditems)) - - at jit.look_inside_iff(lambda space, wrappeditems: - jit.loop_unrolling_heuristic(wrappeditems, len(wrappeditems), UNROLL_CUTOFF)) -def hash_tuple(space, wrappeditems): - # this is the CPython 2.4 algorithm (changed from 2.3) - mult = 1000003 - x = 0x345678 - z = len(wrappeditems) - for w_item in wrappeditems: - y = space.hash_w(w_item) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return intmask(x) - -def getnewargs__Tuple(space, w_tuple): - return space.newtuple([space.newtuple(w_tuple.wrappeditems)]) - -def tuple_count__Tuple_ANY(space, w_tuple, w_obj): - count = 0 - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - count += 1 - return space.wrap(count) - -def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) - for i in range(start, min(stop, length)): - w_item = w_tuple.wrappeditems[i] - if space.eq_w(w_item, w_obj): - return space.wrap(i) - raise OperationError(space.w_ValueError, - space.wrap("tuple.index(x): x not in tuple")) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) +def wraptuple(space, list_w): + if space.config.objspace.std.withspecialisedtuple: + from specialisedtupleobject import makespecialisedtuple, NotSpecialised + try: + return makespecialisedtuple(space, list_w) + except NotSpecialised: + pass + return W_TupleObject(list_w) diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py deleted file mode 100644 --- a/pypy/objspace/std/tupletype.py +++ /dev/null @@ -1,70 +0,0 @@ -import sys -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -def wraptuple(space, list_w): - from pypy.objspace.std.tupleobject import W_TupleObject - - if space.config.objspace.std.withspecialisedtuple: - from specialisedtupleobject import makespecialisedtuple, NotSpecialised - try: - return makespecialisedtuple(space, list_w) - except NotSpecialised: - pass - - if space.config.objspace.std.withsmalltuple: - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 - if len(list_w) == 2: - return W_SmallTupleObject2(list_w) - if len(list_w) == 3: - return W_SmallTupleObject3(list_w) - if len(list_w) == 4: - return W_SmallTupleObject4(list_w) - if len(list_w) == 5: - return W_SmallTupleObject5(list_w) - if len(list_w) == 6: - return W_SmallTupleObject6(list_w) - if len(list_w) == 7: - return W_SmallTupleObject7(list_w) - if len(list_w) == 8: - return W_SmallTupleObject8(list_w) - return W_TupleObject(list_w) - -tuple_count = SMM("count", 2, - doc="count(obj) -> number of times obj appears in the tuple") - -tuple_index = SMM("index", 4, defaults=(0, sys.maxint), - doc="index(obj, [start, [stop]]) -> first index that obj " - "appears in the tuple") - - -def descr__new__(space, w_tupletype, w_sequence=None): - from pypy.objspace.std.tupleobject import W_TupleObject - if w_sequence is None: - tuple_w = [] - elif (space.is_w(w_tupletype, space.w_tuple) and - space.is_w(space.type(w_sequence), space.w_tuple)): - return w_sequence - else: - tuple_w = space.fixedview(w_sequence) - w_obj = space.allocate_instance(W_TupleObject, w_tupletype) - W_TupleObject.__init__(w_obj, tuple_w) - return w_obj - -# ____________________________________________________________ - -tuple_typedef = StdTypeDef("tuple", - __doc__ = '''tuple() -> an empty tuple -tuple(sequence) -> tuple initialized from sequence's items - -If the argument is a tuple, the return value is the same object.''', - __new__ = gateway.interp2app(descr__new__), - ) -tuple_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -12,7 +12,6 @@ W_StringObject, make_rsplit_with_delim) from pypy.objspace.std.stringtype import stringendswith, stringstartswith from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.objectmodel import ( @@ -501,8 +500,10 @@ # with additional parameters as rpython) return space.newbool(stringstartswith(self, w_substr._value, start, end)) -def unicode_startswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_prefixes, +def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_prefixes, w_start, w_end): + if not space.isinstance_w(w_prefixes, space.w_tuple): + raise FailedToImplement unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): @@ -511,8 +512,10 @@ return space.w_True return space.w_False -def unicode_endswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_suffixes, +def unicode_endswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_suffixes, w_start, w_end): + if not space.isinstance_w(w_suffixes, space.w_tuple): + raise FailedToImplement unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): From noreply at buildbot.pypy.org Wed May 22 18:12:45 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:12:45 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: hg merge default Message-ID: <20130522161245.82AE41C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64464:5169cc6f97fc Date: 2013-05-22 18:10 +0200 http://bitbucket.org/pypy/pypy/changeset/5169cc6f97fc/ Log: hg merge default diff too long, truncating to 2000 out of 2237 lines diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -215,10 +215,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), @@ -364,8 +360,6 @@ # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] - if config.translation.platform == 'arm' and '_continuation' in modules: - modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -25,3 +25,9 @@ .. branch: remove-list-smm-2 Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -14,7 +14,6 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -310,31 +309,30 @@ w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): + if space.isinstance_w(w_prefix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_prefix)]) + return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + w_start, w_stop) + w_prefix = space.wrap(space.bufferstr_new_w(w_prefix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) -def str_startswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_prefix)]) - return stringobject.str_startswith__String_Tuple_ANY_ANY(space, w_str, w_prefix, - w_start, w_stop) - def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): + if space.isinstance_w(w_suffix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_suffix)]) + return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) -def str_endswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_suffix)]) - return stringobject.str_endswith__String_Tuple_ANY_ANY(space, w_str, w_suffix, - w_start, w_stop) - def str_join__Bytearray_ANY(space, w_self, w_list): list_w = space.listview(w_list) if not list_w: diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -23,7 +23,7 @@ from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.floatobject import W_FloatObject -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject @@ -288,14 +288,17 @@ raise_exception(space, 'bad marshal data') register(TYPE_STRINGREF, unmarshal_stringref) -def marshal_w__Tuple(space, w_tuple, m): - items = w_tuple.wrappeditems +def marshal_tuple(space, w_tuple, m): + if not isinstance(w_tuple, W_AbstractTupleObject): + raise_exception(space, "unmarshallable object") + items = w_tuple.tolist() m.put_tuple_w(TYPE_TUPLE, items) +handled_by_any.append(('tuple', marshal_tuple)) -def unmarshal_Tuple(space, u, tc): +def unmarshal_tuple(space, u, tc): items_w = u.get_tuple_w() return space.newtuple(items_w) -register(TYPE_TUPLE, unmarshal_Tuple) +register(TYPE_TUPLE, unmarshal_tuple) def marshal_list(space, w_list, m): if not isinstance(w_list, W_ListObject): diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -15,8 +15,6 @@ _registered_implementations.add(implcls) option_to_typename = { - "withspecialisedtuple" : ["specialisedtupleobject.W_SpecialisedTupleObject"], - "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], "withstrbuf" : ["strbufobject.W_StringBufferObject"], } @@ -38,7 +36,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -78,6 +75,7 @@ # not-multimethod based types + self.pythontypes.append(tupleobject.W_TupleObject.typedef) self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) @@ -90,7 +88,6 @@ boolobject.W_BoolObject: [], intobject.W_IntObject: [], floatobject.W_FloatObject: [], - tupleobject.W_TupleObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -105,7 +102,6 @@ self.imported_but_not_registered = { stringobject.W_StringObject: True, - tupleobject.W_TupleObject: True, } for option, value in config.objspace.std: if option.startswith("with") and option in option_to_typename: @@ -186,15 +182,6 @@ (unicodeobject.W_UnicodeObject, strbufobject.delegate_buf2unicode) ] - if config.objspace.std.withsmalltuple: - from pypy.objspace.std import smalltupleobject - self.typeorder[smalltupleobject.W_SmallTupleObject] += [ - (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] - - if config.objspace.std.withspecialisedtuple: - from pypy.objspace.std import specialisedtupleobject - self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ - (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] # put W_Root everywhere self.typeorder[W_Root] = [] diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -281,7 +281,7 @@ return newlong(self, val) def newtuple(self, list_w): - from pypy.objspace.std.tupletype import wraptuple + from pypy.objspace.std.tupleobject import wraptuple assert isinstance(list_w, list) make_sure_not_resized(list_w) return wraptuple(self, list_w) @@ -663,6 +663,12 @@ class2type[base] = w_type self._interplevel_classes[w_type] = base + # register other things + self._interplevel_classes[self.w_dict] = W_DictMultiObject + self._interplevel_classes[self.w_list] = W_ListObject + self._interplevel_classes[self.w_set] = W_SetObject + self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + @specialize.memo() def _get_interplevel_cls(self, w_type): if not hasattr(self, "_interplevel_classes"): diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/smalltupleobject.py +++ /dev/null @@ -1,161 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement -from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.interpreter import gateway -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib.unroll import unrolling_iterable -from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject - -class W_SmallTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] - return tuple(items) - -def make_specialized_class(n): - iter_n = unrolling_iterable(range(n)) - class cls(W_SmallTupleObject): - - def __init__(self, values): - assert len(values) == n - for i in iter_n: - setattr(self, 'w_value%s' % i, values[i]) - - def tolist(self): - l = [None] * n - for i in iter_n: - l[i] = getattr(self, 'w_value%s' % i) - return l - - # same source code, but builds and returns a resizable list - getitems_copy = func_with_new_name(tolist, 'getitems_copy') - - def length(self): - return n - - def getitem(self, index): - for i in iter_n: - if index == i: - return getattr(self,'w_value%s' % i) - raise IndexError - - def setitem(self, index, w_item): - for i in iter_n: - if index == i: - setattr(self, 'w_value%s' % i, w_item) - return - raise IndexError - - def eq(self, space, w_other): - if n != w_other.length(): - return space.w_False - for i in iter_n: - item1 = getattr(self,'w_value%s' % i) - item2 = w_other.getitem(i) - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - - def hash(self, space): - mult = 1000003 - x = 0x345678 - z = n - for i in iter_n: - w_item = getattr(self, 'w_value%s' % i) - y = space.int_w(space.hash(w_item)) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return space.wrap(intmask(x)) - - cls.__name__ = "W_SmallTupleObject%s" % n - return cls - -W_SmallTupleObject2 = make_specialized_class(2) -W_SmallTupleObject3 = make_specialized_class(3) -W_SmallTupleObject4 = make_specialized_class(4) -W_SmallTupleObject5 = make_specialized_class(5) -W_SmallTupleObject6 = make_specialized_class(6) -W_SmallTupleObject7 = make_specialized_class(7) -W_SmallTupleObject8 = make_specialized_class(8) - -registerimplementation(W_SmallTupleObject) - -def delegate_SmallTuple2Tuple(space, w_small): - return W_TupleObject(w_small.tolist()) - -def len__SmallTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SmallTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SmallTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_smalltuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SmallTuple_ANY(space, w_tuple, w_times): - return mul_smalltuple_times(space, w_tuple, w_times) - -def mul__ANY_SmallTuple(space, w_times, w_tuple): - return mul_smalltuple_times(space, w_tuple, w_times) - -def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def hash__SmallTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -1,63 +1,23 @@ from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.tupleobject import W_AbstractTupleObject -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.util import negate +from rpython.rlib.objectmodel import compute_hash from rpython.rlib.rarithmetic import intmask -from rpython.rlib.objectmodel import compute_hash from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name + class NotSpecialised(Exception): pass -class W_SpecialisedTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - __slots__ = [] - - def __repr__(self): - """ representation for debugging purposes """ - reprlist = [repr(item) for item in self._to_unwrapped_list()] - return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def _to_unwrapped_list(self): - "NOT_RPYTHON" - raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(self, space): - return tuple(self._to_unwrapped_list()) - - def delegating(self): - pass # for tests only - def make_specialised_class(typetuple): assert type(typetuple) == tuple - + nValues = len(typetuple) iter_n = unrolling_iterable(range(nValues)) - - class cls(W_SpecialisedTupleObject): + + class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space assert len(values_w) == nValues @@ -80,7 +40,7 @@ return nValues def tolist(self): - list_w = [None] * nValues + list_w = [None] * nValues for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -91,18 +51,7 @@ # same source code, but builds and returns a resizable list getitems_copy = func_with_new_name(tolist, 'getitems_copy') - def _to_unwrapped_list(self): - "NOT_RPYTHON" - list_w = [None] * nValues - for i in iter_n: - value = getattr(self, 'value%s' % i) - if typetuple[i] == object: - value = self.space.unwrap(value) - list_w[i] = value - return list_w - - def hash(self, space): - # XXX duplicate logic from tupleobject.py + def descr_hash(self, space): mult = 1000003 x = 0x345678 z = nValues @@ -123,50 +72,45 @@ x += 97531 return space.wrap(intmask(x)) - def _eq(self, w_other): + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplementedError if not isinstance(w_other, cls): - # if we are not comparing same types, give up - raise FailedToImplement + if nValues != w_other.length(): + return space.w_False + for i in iter_n: + myval = getattr(self, 'value%s' % i) + otherval = w_other.getitem(space, i) + if typetuple[i] != object: + myval = space.wrap(myval) + if not space.eq_w(myval, otherval): + return space.w_False + return space.w_True + for i in iter_n: - myval = getattr(self, 'value%s' % i) + myval = getattr(self, 'value%s' % i) otherval = getattr(w_other, 'value%s' % i) if typetuple[i] == object: if not self.space.eq_w(myval, otherval): - return False + return space.w_False else: if myval != otherval: - return False - else: - return True + return space.w_False + return space.w_True - def eq(self, space, w_other): - return space.newbool(self._eq(w_other)) + descr_ne = negate(descr_eq) - def ne(self, space, w_other): - return space.newbool(not self._eq(w_other)) - -## def _compare(self, compare_op, w_other): -## if not isinstance(w_other, cls): -## raise FailedToImplement -## ncmp = min(self.length(), w_other.length()) -## for i in iter_n: -## if typetuple[i] == Any:#like space.eq on wrapped or two params? -## raise FailedToImplement -## if ncmp > i: -## l_val = getattr(self, 'value%s' % i) -## r_val = getattr(w_other, 'value%s' % i) -## if l_val != r_val: -## return compare_op(l_val, r_val) -## return compare_op(self.length(), w_other.length()) - - def getitem(self, index): + def getitem(self, space, index): + if index < 0: + index += nValues for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) if typetuple[i] != object: - value = self.space.wrap(value) + value = space.wrap(value) return value - raise IndexError + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) cls.__name__ = ('W_SpecialisedTupleObject_' + ''.join([t.__name__[0] for t in typetuple])) @@ -177,129 +121,21 @@ _specialisations = [] Cls_ii = make_specialised_class((int, int)) -#Cls_is = make_specialised_class((int, str)) -#Cls_io = make_specialised_class((int, object)) -#Cls_si = make_specialised_class((str, int)) -#Cls_ss = make_specialised_class((str, str)) -#Cls_so = make_specialised_class((str, object)) -#Cls_oi = make_specialised_class((object, int)) -#Cls_os = make_specialised_class((object, str)) Cls_oo = make_specialised_class((object, object)) Cls_ff = make_specialised_class((float, float)) -#Cls_ooo = make_specialised_class((object, object, object)) def makespecialisedtuple(space, list_w): if len(list_w) == 2: w_arg1, w_arg2 = list_w w_type1 = space.type(w_arg1) - #w_type2 = space.type(w_arg2) - # if w_type1 is space.w_int: w_type2 = space.type(w_arg2) if w_type2 is space.w_int: return Cls_ii(space, w_arg1, w_arg2) - #elif w_type2 is space.w_str: - # return Cls_is(space, w_arg1, w_arg2) - #else: - # return Cls_io(space, w_arg1, w_arg2) - # - #elif w_type1 is space.w_str: - # if w_type2 is space.w_int: - # return Cls_si(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_ss(space, w_arg1, w_arg2) - # else: - # return Cls_so(space, w_arg1, w_arg2) - # elif w_type1 is space.w_float: w_type2 = space.type(w_arg2) if w_type2 is space.w_float: return Cls_ff(space, w_arg1, w_arg2) - # - #else: - # if w_type2 is space.w_int: - # return Cls_oi(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_os(space, w_arg1, w_arg2) - # else: return Cls_oo(space, w_arg1, w_arg2) - # - #elif len(list_w) == 3: - # return Cls_ooo(space, list_w[0], list_w[1], list_w[2]) else: raise NotSpecialised - -# ____________________________________________________________ - -registerimplementation(W_SpecialisedTupleObject) - -def delegate_SpecialisedTuple2Tuple(space, w_specialised): - w_specialised.delegating() - return W_TupleObject(w_specialised.tolist()) - -def len__SpecialisedTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SpecialisedTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SpecialisedTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_specialisedtuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SpecialisedTuple_ANY(space, w_tuple, w_times): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def mul__ANY_SpecialisedTuple(space, w_times, w_tuple): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.ne(space, w_tuple2) - -##from operator import lt, le, ge, gt - -##def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(lt, w_tuple2)) - -##def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(le, w_tuple2)) - -##def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(ge, w_tuple2)) - -##def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(gt, w_tuple2)) - -def hash__SpecialisedTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -12,7 +12,6 @@ from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringtype import ( joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) -from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib import jit from rpython.rlib.objectmodel import ( compute_hash, compute_unique_id, specialize) @@ -684,7 +683,9 @@ w_end, True) return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) -def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): +def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): + if not space.isinstance_w(w_suffixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): @@ -702,7 +703,9 @@ w_end, True) return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) -def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): +def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): + if not space.isinstance_w(w_prefixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ /dev/null @@ -1,84 +0,0 @@ -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject -from pypy.interpreter.error import OperationError -from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject -from pypy.tool.pytest.objspace import gettestobjspace - -class AppTestW_SmallTupleObject(AppTestW_TupleObject): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def setup_class(cls): - cls.w_issmall = cls.space.appexec([], """(): - import __pypy__ - def issmall(obj): - assert "SmallTuple" in __pypy__.internal_repr(obj) - return issmall - """) - - def test_smalltuple(self): - self.issmall((1,2)) - self.issmall((1,2,3)) - - def test_slicing_to_small(self): - self.issmall((1, 2, 3)[0:2]) # SmallTuple2 - self.issmall((1, 2, 3)[0:2:1]) - - self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3 - self.issmall((1, 2, 3, 4)[0:3:1]) - - def test_adding_to_small(self): - self.issmall((1,)+(2,)) # SmallTuple2 - self.issmall((1,1)+(2,)) # SmallTuple3 - self.issmall((1,)+(2,3)) - - def test_multiply_to_small(self): - self.issmall((1,)*2) - self.issmall((1,)*3) - - def test_slicing_from_small(self): - assert (1,2)[0:1:1] == (1,) - assert (1,2,3)[0:2:1] == (1,2) - - def test_eq(self): - a = (1,2,3) - b = (1,2,3) - assert a == b - - c = (1,3,2) - assert a != c - - def test_hash(self): - a = (1,2,3) - b = (1,2,3) - assert hash(a) == hash(b) - - c = (1,3,2) - assert hash(a) != hash(c) - -class TestW_SmallTupleObject(): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def test_issmalltupleobject(self): - w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - assert isinstance(w_tuple, W_SmallTupleObject) - - def test_hash_agains_normal_tuple(self): - normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) - w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) - w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - assert isinstance(w_smalltuple, W_SmallTupleObject) - assert isinstance(w_tuple, W_TupleObject) - assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) - - def test_setitem(self): - w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - w_smalltuple.setitem(0, self.space.wrap(5)) - list_w = w_smalltuple.tolist() - assert len(list_w) == 2 - assert self.space.eq_w(list_w[0], self.space.wrap(5)) - assert self.space.eq_w(list_w[1], self.space.wrap(2)) diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -1,11 +1,7 @@ -import py, sys +from pypy.objspace.std.specialisedtupleobject import _specialisations +from pypy.objspace.std.test import test_tupleobject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject -from pypy.objspace.std.specialisedtupleobject import _specialisations -from pypy.interpreter.error import OperationError from pypy.tool.pytest.objspace import gettestobjspace -from pypy.objspace.std.test import test_tupleobject -from pypy.interpreter import gateway for cls in _specialisations: @@ -18,62 +14,43 @@ def test_isspecialisedtupleobjectintint(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert isinstance(w_tuple, W_SpecialisedTupleObject_ii) - + def test_isnotspecialisedtupleobject(self): w_tuple = self.space.newtuple([self.space.wrap({})]) - assert not isinstance(w_tuple, W_SpecialisedTupleObject) - + assert not 'W_SpecialisedTupleObject' in type(w_tuple).__name__ + def test_specialisedtupleclassname(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii' def test_hash_against_normal_tuple(self): - N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": False}) - S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) - def hash_test(values, must_be_specialized=True): - N_values_w = [N_space.wrap(value) for value in values] - S_values_w = [S_space.wrap(value) for value in values] - N_w_tuple = N_space.newtuple(N_values_w) - S_w_tuple = S_space.newtuple(S_values_w) + N_values_w = [self.space.wrap(value) for value in values] + S_values_w = [self.space.wrap(value) for value in values] + N_w_tuple = W_TupleObject(N_values_w) + S_w_tuple = self.space.newtuple(S_values_w) if must_be_specialized: - assert isinstance(S_w_tuple, W_SpecialisedTupleObject) - assert isinstance(N_w_tuple, W_TupleObject) - assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) - assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) + assert 'W_SpecialisedTupleObject' in type(S_w_tuple).__name__ + assert self.space.is_true(self.space.eq(N_w_tuple, S_w_tuple)) + assert self.space.is_true( + self.space.eq(self.space.hash(N_w_tuple), + self.space.hash(S_w_tuple))) - hash_test([1,2]) - hash_test([1.5,2.8]) - hash_test([1.0,2.0]) - hash_test(['arbitrary','strings']) - hash_test([1,(1,2,3,4)]) - hash_test([1,(1,2)]) - hash_test([1,('a',2)]) - hash_test([1,()]) - hash_test([1,2,3], must_be_specialized=False) + hash_test([1, 2]) + hash_test([1.5, 2.8]) + hash_test([1.0, 2.0]) + hash_test(['arbitrary', 'strings']) + hash_test([1, (1, 2, 3, 4)]) + hash_test([1, (1, 2)]) + hash_test([1, ('a', 2)]) + hash_test([1, ()]) + hash_test([1, 2, 3], must_be_specialized=False) class AppTestW_SpecialisedTupleObject: spaceconfig = {"objspace.std.withspecialisedtuple": True} - def setup_class(cls): - def forbid_delegation(space, w_tuple): - def delegation_forbidden(): - # haaaack - co = sys._getframe(2).f_code - if co.co_name.startswith('_mm_repr_tuple'): - return - raise OperationError(space.w_ReferenceError, w_tuple) - w_tuple.delegating = delegation_forbidden - return w_tuple - if cls.runappdirect: - cls.w_forbid_delegation = lambda self, x: x - cls.test_delegation = lambda self: skip("runappdirect") - else: - cls.w_forbid_delegation = cls.space.wrap( - gateway.interp2app(forbid_delegation)) - def w_isspecialised(self, obj, expected=''): import __pypy__ r = __pypy__.internal_repr(obj) @@ -101,16 +78,12 @@ obj = (1, 2, 3) assert self.isspecialised(obj, '_ooo') - def test_delegation(self): - t = self.forbid_delegation((42, 43)) - raises(ReferenceError, t.__getslice__, 0, 1) - def test_len(self): - t = self.forbid_delegation((42,43)) + t = (42, 43) assert len(t) == 2 def test_notspecialisedtuple(self): - assert not self.isspecialised((42,43,44,45)) + assert not self.isspecialised((42, 43, 44, 45)) assert not self.isspecialised((1.5,)) def test_slicing_to_specialised(self): @@ -133,79 +106,79 @@ def test_eq_no_delegation(self): t = (1,) - a = self.forbid_delegation(t + (2,)) + a = t + (2,) b = (1, 2) assert a == b c = (2, 1) assert not a == c - def test_eq_can_delegate(self): - a = (1,2) - b = (1,3,2) + def test_eq_can_delegate(self): + a = (1, 2) + b = (1, 3, 2) assert not a == b values = [2, 2L, 2.0, 1, 1L, 1.0] for x in values: for y in values: - assert ((1,2) == (x,y)) == (1 == x and 2 == y) + assert ((1, 2) == (x, y)) == (1 == x and 2 == y) def test_neq(self): - a = self.forbid_delegation((1,2)) + a = (1, 2) b = (1,) - b = b+(2,) + b = b + (2,) assert not a != b - - c = (1,3) + + c = (1, 3) assert a != c - + def test_ordering(self): - a = (1,2) #self.forbid_delegation((1,2)) --- code commented out - assert a < (2,2) - assert a < (1,3) - assert not a < (1,2) + a = (1, 2) + assert a < (2, 2) + assert a < (1, 3) + assert not a < (1, 2) - assert a <= (2,2) - assert a <= (1,2) - assert not a <= (1,1) - - assert a >= (0,2) - assert a >= (1,2) - assert not a >= (1,3) - - assert a > (0,2) - assert a > (1,1) - assert not a > (1,3) + assert a <= (2, 2) + assert a <= (1, 2) + assert not a <= (1, 1) - assert (2,2) > a - assert (1,3) > a - assert not (1,2) > a - - assert (2,2) >= a - assert (1,2) >= a - assert not (1,1) >= a - - assert (0,2) <= a - assert (1,2) <= a - assert not (1,3) <= a - - assert (0,2) < a - assert (1,1) < a - assert not (1,3) < a + assert a >= (0, 2) + assert a >= (1, 2) + assert not a >= (1, 3) + + assert a > (0, 2) + assert a > (1, 1) + assert not a > (1, 3) + + assert (2, 2) > a + assert (1, 3) > a + assert not (1, 2) > a + + assert (2, 2) >= a + assert (1, 2) >= a + assert not (1, 1) >= a + + assert (0, 2) <= a + assert (1, 2) <= a + assert not (1, 3) <= a + + assert (0, 2) < a + assert (1, 1) < a + assert not (1, 3) < a def test_hash(self): - a = (1,2) + a = (1, 2) b = (1,) - b += (2,) # else a and b refer to same constant + b += (2,) # else a and b refer to same constant assert hash(a) == hash(b) - c = (2,4) + c = (2, 4) assert hash(a) != hash(c) assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L)) def test_getitem(self): - t = self.forbid_delegation((5,3)) + t = (5, 3) assert (t)[0] == 5 assert (t)[1] == 3 assert (t)[-1] == 3 @@ -216,14 +189,14 @@ def test_three_tuples(self): if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - b = self.forbid_delegation((1, 2, 3)) + b = (1, 2, 3) c = (1,) d = c + (2, 3) assert self.isspecialised(d) assert b == d def test_mongrel(self): - a = self.forbid_delegation((2.2, '333')) + a = (2.2, '333') assert self.isspecialised(a) assert len(a) == 2 assert a[0] == 2.2 and a[1] == '333' @@ -233,7 +206,7 @@ # if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - a = self.forbid_delegation((1, 2.2, '333')) + a = (1, 2.2, '333') assert self.isspecialised(a) assert len(a) == 3 assert a[0] == 1 and a[1] == 2.2 and a[2] == '333' diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -1,17 +1,16 @@ -#from __future__ import nested_scopes +from pypy.interpreter.error import OperationError from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.interpreter.error import OperationError + class TestW_TupleObject: - def test_is_true(self): w = self.space.wrap w_tuple = W_TupleObject([]) - assert self.space.is_true(w_tuple) == False + assert self.space.is_true(w_tuple) is False w_tuple = W_TupleObject([w(5)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True w_tuple = W_TupleObject([w(5), w(3)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True def test_len(self): w = self.space.wrap @@ -19,7 +18,7 @@ assert self.space.eq_w(self.space.len(w_tuple), w(0)) w_tuple = W_TupleObject([w(5)]) assert self.space.eq_w(self.space.len(w_tuple), w(1)) - w_tuple = W_TupleObject([w(5), w(3), w(99)]*111) + w_tuple = W_TupleObject([w(5), w(3), w(99)] * 111) assert self.space.eq_w(self.space.len(w_tuple), w(333)) def test_getitem(self): @@ -65,7 +64,7 @@ w_tuple2 = W_TupleObject([w(-7)] * 111) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple1), W_TupleObject([w(5), w(3), w(99), - w(5), w(3), w(99)])) + w(5), w(3), w(99)])) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple2), W_TupleObject([w(5), w(3), w(99)] + [w(-7)] * 111)) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple0), w_tuple1) @@ -77,7 +76,7 @@ arg = w(2) n = 3 w_tup = W_TupleObject([arg]) - w_tup3 = W_TupleObject([arg]*n) + w_tup3 = W_TupleObject([arg] * n) w_res = self.space.mul(w_tup, w(n)) assert self.space.eq_w(w_tup3, w_res) # commute @@ -91,26 +90,26 @@ w = self.space.wrap def test1(testtuple, start, stop, step, expected): - w_slice = self.space.newslice(w(start), w(stop), w(step)) + w_slice = self.space.newslice(w(start), w(stop), w(step)) w_tuple = W_TupleObject([w(i) for i in testtuple]) w_result = self.space.getitem(w_tuple, w_slice) assert self.space.unwrap(w_result) == expected - - for testtuple in [(), (5,3,99), tuple(range(5,555,10))]: + + for testtuple in [(), (5, 3, 99), tuple(range(5, 555, 10))]: for start in [-2, -1, 0, 1, 10]: for end in [-1, 0, 2, 999]: test1(testtuple, start, end, 1, testtuple[start:end]) - test1((5,7,1,4), 3, 1, -2, (4,)) - test1((5,7,1,4), 3, 0, -2, (4, 7)) - test1((5,7,1,4), 3, -1, -2, ()) - test1((5,7,1,4), -2, 11, 2, (1,)) - test1((5,7,1,4), -3, 11, 2, (7, 4)) - test1((5,7,1,4), -5, 11, 2, (5, 1)) + test1((5, 7, 1, 4), 3, 1, -2, (4,)) + test1((5, 7, 1, 4), 3, 0, -2, (4, 7)) + test1((5, 7, 1, 4), 3, -1, -2, ()) + test1((5, 7, 1, 4), -2, 11, 2, (1,)) + test1((5, 7, 1, 4), -3, 11, 2, (7, 4)) + test1((5, 7, 1, 4), -5, 11, 2, (5, 1)) def test_eq(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -126,9 +125,10 @@ self.space.w_True) assert self.space.eq_w(self.space.eq(w_tuple2, w_tuple3), self.space.w_False) + def test_ne(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -144,9 +144,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ne(w_tuple2, w_tuple3), self.space.w_True) + def test_lt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -165,10 +166,10 @@ self.space.w_True) assert self.space.eq_w(self.space.lt(w_tuple4, w_tuple3), self.space.w_True) - + def test_ge(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -187,10 +188,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ge(w_tuple4, w_tuple3), self.space.w_False) - + def test_gt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -209,10 +210,10 @@ self.space.w_False) assert self.space.eq_w(self.space.gt(w_tuple4, w_tuple3), self.space.w_False) - + def test_le(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -234,28 +235,27 @@ class AppTestW_TupleObject: - def test_is_true(self): assert not () assert (5,) - assert (5,3) + assert (5, 3) def test_len(self): assert len(()) == 0 assert len((5,)) == 1 - assert len((5,3,99,1,2,3,4,5,6)) == 9 + assert len((5, 3, 99, 1, 2, 3, 4, 5, 6)) == 9 def test_getitem(self): - assert (5,3)[0] == 5 - assert (5,3)[1] == 3 - assert (5,3)[-1] == 3 - assert (5,3)[-2] == 5 - raises(IndexError, "(5,3)[2]") + assert (5, 3)[0] == 5 + assert (5, 3)[1] == 3 + assert (5, 3)[-1] == 3 + assert (5, 3)[-2] == 5 + raises(IndexError, "(5, 3)[2]") raises(IndexError, "(5,)[1]") raises(IndexError, "()[0]") def test_iter(self): - t = (5,3,99) + t = (5, 3, 99) i = iter(t) assert i.next() == 5 assert i.next() == 3 @@ -263,7 +263,7 @@ raises(StopIteration, i.next) def test_contains(self): - t = (5,3,99) + t = (5, 3, 99) assert 5 in t assert 99 in t assert not 11 in t @@ -271,35 +271,35 @@ def test_add(self): t0 = () - t1 = (5,3,99) + t1 = (5, 3, 99) assert t0 + t0 == t0 assert t1 + t0 == t1 - assert t1 + t1 == (5,3,99,5,3,99) + assert t1 + t1 == (5, 3, 99, 5, 3, 99) def test_mul(self): assert () * 10 == () - assert (5,) * 3 == (5,5,5) - assert (5,2) * 2 == (5,2,5,2) + assert (5,) * 3 == (5, 5, 5) + assert (5, 2) * 2 == (5, 2, 5, 2) def test_mul_identity(self): - t = (1,2,3) + t = (1, 2, 3) assert (t * 1) is t def test_mul_subtype(self): class T(tuple): pass - t = T([1,2,3]) + t = T([1, 2, 3]) assert (t * 1) is not t assert (t * 1) == t def test_getslice_2(self): - assert (5,2,3)[1:2] == (2,) + assert (5, 2, 3)[1:2] == (2,) def test_eq(self): t0 = () - t1 = (5,3,99) - t2 = (5,3,99) - t3 = (5,3,99,-1) - t4 = (5,3,9,1) + t1 = (5, 3, 99) + t2 = (5, 3, 99) + t3 = (5, 3, 99, -1) + t4 = (5, 3, 9, 1) assert not t0 == t1 assert t0 != t1 assert t1 == t2 @@ -321,15 +321,15 @@ # check that hash behaves as in 2.4 for at least 31 bits assert hash(()) & 0x7fffffff == 0x35d373 assert hash((12,)) & 0x7fffffff == 0x1cca0557 - assert hash((12,34)) & 0x7fffffff == 0x153e2a41 + assert hash((12, 34)) & 0x7fffffff == 0x153e2a41 def test_getnewargs(self): - assert () .__getnewargs__() == ((),) + assert () .__getnewargs__() == ((),) def test_repr(self): assert repr((1,)) == '(1,)' assert repr(()) == '()' - assert repr((1,2,3)) == '(1, 2, 3)' + assert repr((1, 2, 3)) == '(1, 2, 3)' def test_getslice(self): assert ('a', 'b', 'c').__getslice__(-17, 2) == ('a', 'b') diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,212 +1,297 @@ +import sys +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate +from rpython.rlib import jit +from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib import jit -from rpython.tool.sourcetools import func_with_new_name + UNROLL_CUTOFF = 10 -class W_AbstractTupleObject(W_Object): + +def _unroll_condition(self): + return jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) + + +def _unroll_condition_cmp(self, space, other): + return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF)) + + +class W_AbstractTupleObject(W_Root): __slots__ = () + def __repr__(self): + """representation for debugging purposes""" + reprlist = [repr(w_item) for w_item in self.tolist()] + return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) + + def unwrap(self, space): + items = [space.unwrap(w_item) for w_item in self.tolist()] + return tuple(items) + def tolist(self): - "Returns the items, as a fixed-size list." + """Returns the items, as a fixed-size list.""" raise NotImplementedError def getitems_copy(self): - "Returns a copy of the items, as a resizable list." + """Returns a copy of the items, as a resizable list.""" raise NotImplementedError + def length(self): + raise NotImplementedError + + def getitem(self, space, item): + raise NotImplementedError + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + + def descr_iter(self, space): + from pypy.objspace.std import iterobject + return iterobject.W_FastTupleIterObject(self, self.tolist()) + + @staticmethod + def descr_new(space, w_tupletype, w_sequence=None): + if w_sequence is None: + tuple_w = [] + elif (space.is_w(w_tupletype, space.w_tuple) and + space.is_w(space.type(w_sequence), space.w_tuple)): + return w_sequence + else: + tuple_w = space.fixedview(w_sequence) + w_obj = space.allocate_instance(W_TupleObject, w_tupletype) + W_TupleObject.__init__(w_obj, tuple_w) + return w_obj + + def descr_repr(self, space): + items = self.tolist() + if len(items) == 1: + return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") + tmp = ", ".join([space.str_w(space.repr(item)) for item in items]) + return space.wrap("(" + tmp + ")") + + def descr_hash(self, space): + raise NotImplementedError + + def descr_eq(self, space, w_other): + raise NotImplementedError + + def descr_ne(self, space, w_other): + raise NotImplementedError + + def _make_tuple_comparison(name): + import operator + op = getattr(operator, name) + + def compare_tuples(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return _compare_tuples(self, space, w_other) + + @jit.look_inside_iff(_unroll_condition_cmp) + def _compare_tuples(self, space, w_other): + items1 = self.tolist() + items2 = w_other.tolist() + ncmp = min(len(items1), len(items2)) + # Search for the first index where items are different + for p in range(ncmp): + if not space.eq_w(items1[p], items2[p]): + return getattr(space, name)(items1[p], items2[p]) + # No more items to compare -- compare sizes + return space.newbool(op(len(items1), len(items2))) + + compare_tuples.__name__ = 'descr_' + name + return compare_tuples + + descr_lt = _make_tuple_comparison('lt') + descr_le = _make_tuple_comparison('le') + descr_gt = _make_tuple_comparison('gt') + descr_ge = _make_tuple_comparison('ge') + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_contains(self, space, w_obj): + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + return space.w_True + return space.w_False + + def descr_add(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + items1 = self.tolist() + items2 = w_other.tolist() + return space.newtuple(items1 + items2) + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + if times == 1 and space.type(self) == space.w_tuple: + return self + items = self.tolist() + return space.newtuple(items * times) + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + return self._getslice(space, w_index) + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") + return self.getitem(space, index) + + def _getslice(self, space, w_index): + items = self.tolist() + length = len(items) + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = items[start] + start += step + return space.newtuple(subitems) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + return space.newtuple(self.tolist()[start:stop]) + + def descr_getnewargs(self, space): + return space.newtuple([space.newtuple(self.tolist())]) + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_count(self, space, w_obj): + """count(obj) -> number of times obj appears in the tuple""" + count = 0 + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + count += 1 + return space.wrap(count) + + @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), + w_stop=gateway.WrappedDefault(sys.maxint)) + @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) + def descr_index(self, space, w_obj, w_start, w_stop): + """index(obj, [start, [stop]]) -> first index that obj appears in the + tuple + """ + length = self.length() + start, stop = slicetype.unwrap_start_stop(space, length, w_start, + w_stop) + for i in range(start, min(stop, length)): + w_item = self.tolist()[i] + if space.eq_w(w_item, w_obj): + return space.wrap(i) + raise OperationError(space.w_ValueError, + space.wrap("tuple.index(x): x not in tuple")) + +W_AbstractTupleObject.typedef = StdTypeDef( + "tuple", + __doc__ = '''tuple() -> an empty tuple +tuple(sequence) -> tuple initialized from sequence's items + +If the argument is a tuple, the return value is the same object.''', + __new__ = interp2app(W_AbstractTupleObject.descr_new), + __repr__ = interp2app(W_AbstractTupleObject.descr_repr), + __hash__ = interpindirect2app(W_AbstractTupleObject.descr_hash), + + __eq__ = interpindirect2app(W_AbstractTupleObject.descr_eq), + __ne__ = interpindirect2app(W_AbstractTupleObject.descr_ne), + __lt__ = interp2app(W_AbstractTupleObject.descr_lt), + __le__ = interp2app(W_AbstractTupleObject.descr_le), + __gt__ = interp2app(W_AbstractTupleObject.descr_gt), + __ge__ = interp2app(W_AbstractTupleObject.descr_ge), + + __len__ = interp2app(W_AbstractTupleObject.descr_len), + __iter__ = interp2app(W_AbstractTupleObject.descr_iter), + __contains__ = interp2app(W_AbstractTupleObject.descr_contains), + + __add__ = interp2app(W_AbstractTupleObject.descr_add), + __mul__ = interp2app(W_AbstractTupleObject.descr_mul), + __rmul__ = interp2app(W_AbstractTupleObject.descr_mul), + + __getitem__ = interp2app(W_AbstractTupleObject.descr_getitem), + __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice), + + __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs), + count = interp2app(W_AbstractTupleObject.descr_count), + index = interp2app(W_AbstractTupleObject.descr_index) +) + class W_TupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef _immutable_fields_ = ['wrappeditems[*]'] - def __init__(w_self, wrappeditems): + def __init__(self, wrappeditems): make_sure_not_resized(wrappeditems) - w_self.wrappeditems = wrappeditems # a list of wrapped values - - def __repr__(w_self): - """ representation for debugging purposes """ - reprlist = [repr(w_item) for w_item in w_self.wrappeditems] - return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] - return tuple(items) + self.wrappeditems = wrappeditems def tolist(self): return self.wrappeditems def getitems_copy(self): - return self.wrappeditems[:] # returns a resizable list + return self.wrappeditems[:] # returns a resizable list -registerimplementation(W_TupleObject) + def length(self): + return len(self.wrappeditems) + @jit.look_inside_iff(lambda self, _1: _unroll_condition(self)) + def descr_hash(self, space): + mult = 1000003 + x = 0x345678 + z = len(self.wrappeditems) + for w_item in self.wrappeditems: + y = space.hash_w(w_item) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) -def len__Tuple(space, w_tuple): - result = len(w_tuple.wrappeditems) - return wrapint(space, result) + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) -def getitem__Tuple_ANY(space, w_tuple, w_index): - # getindex_w should get a second argument space.w_IndexError, - # but that doesn't exist the first time this is called. - try: - w_IndexError = space.w_IndexError - except AttributeError: - w_IndexError = None - index = space.getindex_w(w_index, w_IndexError, "tuple index") - try: - return w_tuple.wrappeditems[index] - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) + @jit.look_inside_iff(_unroll_condition_cmp) + def _descr_eq(self, space, w_other): + items1 = self.wrappeditems + items2 = w_other.tolist() + lgt1 = len(items1) + lgt2 = len(items2) + if lgt1 != lgt2: + return space.w_False + for i in range(lgt1): + item1 = items1[i] + item2 = items2[i] + if not space.eq_w(item1, item2): + return space.w_False + return space.w_True -def getitem__Tuple_Slice(space, w_tuple, w_slice): - items = w_tuple.wrappeditems - length = len(items) - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = items[start] - start += step - return space.newtuple(subitems) + descr_ne = negate(descr_eq) -def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return space.newtuple(w_tuple.wrappeditems[start:stop]) + def getitem(self, space, index): + try: + return self.wrappeditems[index] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) - at jit.look_inside_iff(lambda space, w_tuple, w_obj: - jit.loop_unrolling_heuristic(w_tuple, len(w_tuple.wrappeditems), UNROLL_CUTOFF)) -def contains__Tuple_ANY(space, w_tuple, w_obj): - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - return space.w_True - return space.w_False -def iter__Tuple(space, w_tuple): - from pypy.objspace.std import iterobject - return iterobject.W_FastTupleIterObject(w_tuple, w_tuple.wrappeditems) - -def add__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - return space.newtuple(items1 + items2) - -def mul_tuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.wrappeditems - return space.newtuple(items * times) - -def mul__Tuple_ANY(space, w_tuple, w_times): - return mul_tuple_times(space, w_tuple, w_times) - -def mul__ANY_Tuple(space, w_times, w_tuple): - return mul_tuple_times(space, w_tuple, w_times) - -def tuple_unroll_condition(space, w_tuple1, w_tuple2): - return jit.loop_unrolling_heuristic(w_tuple1, len(w_tuple1.wrappeditems), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_tuple2, len(w_tuple2.wrappeditems), UNROLL_CUTOFF) - - at jit.look_inside_iff(tuple_unroll_condition) -def eq__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - lgt1 = len(items1) - lgt2 = len(items2) - if lgt1 != lgt2: - return space.w_False - for i in range(lgt1): - item1 = items1[i] - item2 = items2[i] - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - -def _make_tuple_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(tuple_unroll_condition) - def compare_tuples(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - ncmp = min(len(items1), len(items2)) - # Search for the first index where items are different - for p in range(ncmp): - if not space.eq_w(items1[p], items2[p]): - return getattr(space, name)(items1[p], items2[p]) - # No more items to compare -- compare sizes - return space.newbool(op(len(items1), len(items2))) - return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') - -lt__Tuple_Tuple = _make_tuple_comparison('lt') -le__Tuple_Tuple = _make_tuple_comparison('le') -gt__Tuple_Tuple = _make_tuple_comparison('gt') -ge__Tuple_Tuple = _make_tuple_comparison('ge') - -def repr__Tuple(space, w_tuple): - items = w_tuple.wrappeditems - # XXX this is quite innefficient, still better than calling - # it via applevel - if len(items) == 1: - return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") - return space.wrap("(" + - (", ".join([space.str_w(space.repr(item)) for item in items])) - + ")") - -def hash__Tuple(space, w_tuple): - return space.wrap(hash_tuple(space, w_tuple.wrappeditems)) - - at jit.look_inside_iff(lambda space, wrappeditems: - jit.loop_unrolling_heuristic(wrappeditems, len(wrappeditems), UNROLL_CUTOFF)) -def hash_tuple(space, wrappeditems): - # this is the CPython 2.4 algorithm (changed from 2.3) - mult = 1000003 - x = 0x345678 - z = len(wrappeditems) - for w_item in wrappeditems: - y = space.hash_w(w_item) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return intmask(x) - -def getnewargs__Tuple(space, w_tuple): - return space.newtuple([space.newtuple(w_tuple.wrappeditems)]) - -def tuple_count__Tuple_ANY(space, w_tuple, w_obj): - count = 0 - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - count += 1 - return space.wrap(count) - -def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) - for i in range(start, min(stop, length)): - w_item = w_tuple.wrappeditems[i] - if space.eq_w(w_item, w_obj): - return space.wrap(i) - raise OperationError(space.w_ValueError, - space.wrap("tuple.index(x): x not in tuple")) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) +def wraptuple(space, list_w): + if space.config.objspace.std.withspecialisedtuple: + from specialisedtupleobject import makespecialisedtuple, NotSpecialised + try: + return makespecialisedtuple(space, list_w) + except NotSpecialised: + pass + return W_TupleObject(list_w) diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py deleted file mode 100644 --- a/pypy/objspace/std/tupletype.py +++ /dev/null @@ -1,70 +0,0 @@ -import sys -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -def wraptuple(space, list_w): - from pypy.objspace.std.tupleobject import W_TupleObject - - if space.config.objspace.std.withspecialisedtuple: - from specialisedtupleobject import makespecialisedtuple, NotSpecialised - try: - return makespecialisedtuple(space, list_w) - except NotSpecialised: - pass - - if space.config.objspace.std.withsmalltuple: - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 - if len(list_w) == 2: - return W_SmallTupleObject2(list_w) - if len(list_w) == 3: - return W_SmallTupleObject3(list_w) - if len(list_w) == 4: - return W_SmallTupleObject4(list_w) - if len(list_w) == 5: - return W_SmallTupleObject5(list_w) - if len(list_w) == 6: - return W_SmallTupleObject6(list_w) - if len(list_w) == 7: - return W_SmallTupleObject7(list_w) - if len(list_w) == 8: - return W_SmallTupleObject8(list_w) - return W_TupleObject(list_w) - -tuple_count = SMM("count", 2, - doc="count(obj) -> number of times obj appears in the tuple") - -tuple_index = SMM("index", 4, defaults=(0, sys.maxint), - doc="index(obj, [start, [stop]]) -> first index that obj " - "appears in the tuple") - - -def descr__new__(space, w_tupletype, w_sequence=None): - from pypy.objspace.std.tupleobject import W_TupleObject - if w_sequence is None: - tuple_w = [] - elif (space.is_w(w_tupletype, space.w_tuple) and - space.is_w(space.type(w_sequence), space.w_tuple)): - return w_sequence - else: - tuple_w = space.fixedview(w_sequence) - w_obj = space.allocate_instance(W_TupleObject, w_tupletype) - W_TupleObject.__init__(w_obj, tuple_w) - return w_obj - -# ____________________________________________________________ - -tuple_typedef = StdTypeDef("tuple", - __doc__ = '''tuple() -> an empty tuple -tuple(sequence) -> tuple initialized from sequence's items - -If the argument is a tuple, the return value is the same object.''', - __new__ = gateway.interp2app(descr__new__), - ) -tuple_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -12,7 +12,6 @@ W_StringObject, make_rsplit_with_delim) from pypy.objspace.std.stringtype import stringendswith, stringstartswith from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.objectmodel import ( @@ -501,8 +500,10 @@ # with additional parameters as rpython) return space.newbool(stringstartswith(self, w_substr._value, start, end)) -def unicode_startswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_prefixes, +def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_prefixes, w_start, w_end): + if not space.isinstance_w(w_prefixes, space.w_tuple): + raise FailedToImplement unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): @@ -511,8 +512,10 @@ From noreply at buildbot.pypy.org Wed May 22 18:41:27 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:41:27 +0200 (CEST) Subject: [pypy-commit] pypy default: Actually test specialisedtuple here. Message-ID: <20130522164127.F0D3E1C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64465:579793632631 Date: 2013-05-22 18:37 +0200 http://bitbucket.org/pypy/pypy/changeset/579793632631/ Log: Actually test specialisedtuple here. diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -216,4 +216,4 @@ class AppTestAll(test_tupleobject.AppTestW_TupleObject): - pass + spaceconfig = {"objspace.std.withspecialisedtuple": True} From noreply at buildbot.pypy.org Wed May 22 18:41:29 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 18:41:29 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix for ``((1, 2) == object())`` returning space.w_NotImplementedError. Message-ID: <20130522164129.3F2D71C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64466:5bcf229de77c Date: 2013-05-22 18:38 +0200 http://bitbucket.org/pypy/pypy/changeset/5bcf229de77c/ Log: Test and fix for ``((1, 2) == object())`` returning space.w_NotImplementedError. diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -74,7 +74,7 @@ def descr_eq(self, space, w_other): if not isinstance(w_other, W_AbstractTupleObject): - return space.w_NotImplementedError + return space.w_NotImplemented if not isinstance(w_other, cls): if nValues != w_other.length(): return space.w_False diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -399,3 +399,11 @@ assert ((5,) != (N,)) is True assert ((5,) > (N,)) is False assert ((5,) >= (N,)) is False + + def test_eq_other_type(self): + assert (() == object()) is False + assert ((1,) == object()) is False + assert ((1, 2) == object()) is False + assert (() != object()) is True + assert ((1,) != object()) is True + assert ((1, 2) != object()) is True From noreply at buildbot.pypy.org Wed May 22 19:19:26 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 19:19:26 +0200 (CEST) Subject: [pypy-commit] pypy default: In the JIT frontend don't emit writes to young objects where they are constant 0s. Message-ID: <20130522171926.DD95D1C331F@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64467:0ad2bd9495a1 Date: 2013-05-22 10:18 -0700 http://bitbucket.org/pypy/pypy/changeset/0ad2bd9495a1/ Log: In the JIT frontend don't emit writes to young objects where they are constant 0s. diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -621,7 +621,8 @@ tobox = self.metainterp.heapcache.getfield(box, fielddescr) if tobox is valuebox: return - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + if tobox is not None or not self.metainterp.heapcache.is_unescaped(box) or not isinstance(valuebox, Const) or valuebox.nonnull(): + self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) self.metainterp.heapcache.setfield(box, valuebox, fielddescr) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -645,3 +645,20 @@ res = self.interp_operations(fn, [1]) assert res == -1 self.check_operations_history(guard_class=0) + + def test_dont_record_setfield_gc_zeros(self): + class A(object): + pass + + def make_a(): + return A() + make_a._dont_inline_ = True + + def fn(n): + a = make_a() + a.x = jit.promote(n) + return a.x + + res = self.interp_operations(fn, [0]) + assert res == 0 + self.check_operations_history(setfield_gc=0) From noreply at buildbot.pypy.org Wed May 22 19:19:28 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 19:19:28 +0200 (CEST) Subject: [pypy-commit] pypy default: merged upstream Message-ID: <20130522171928.894EE1C331F@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64468:95554fe88250 Date: 2013-05-22 10:18 -0700 http://bitbucket.org/pypy/pypy/changeset/95554fe88250/ Log: merged upstream diff too long, truncating to 2000 out of 2121 lines diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -215,10 +215,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), @@ -364,8 +360,6 @@ # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] - if config.translation.platform == 'arm' and '_continuation' in modules: - modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -25,3 +25,9 @@ .. branch: remove-list-smm-2 Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -14,7 +14,6 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -310,31 +309,30 @@ w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): + if space.isinstance_w(w_prefix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_prefix)]) + return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + w_start, w_stop) + w_prefix = space.wrap(space.bufferstr_new_w(w_prefix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) -def str_startswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_prefix)]) - return stringobject.str_startswith__String_Tuple_ANY_ANY(space, w_str, w_prefix, - w_start, w_stop) - def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): + if space.isinstance_w(w_suffix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_suffix)]) + return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) -def str_endswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_suffix)]) - return stringobject.str_endswith__String_Tuple_ANY_ANY(space, w_str, w_suffix, - w_start, w_stop) - def str_join__Bytearray_ANY(space, w_self, w_list): list_w = space.listview(w_list) if not list_w: diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -23,7 +23,7 @@ from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.floatobject import W_FloatObject -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject @@ -288,14 +288,17 @@ raise_exception(space, 'bad marshal data') register(TYPE_STRINGREF, unmarshal_stringref) -def marshal_w__Tuple(space, w_tuple, m): - items = w_tuple.wrappeditems +def marshal_tuple(space, w_tuple, m): + if not isinstance(w_tuple, W_AbstractTupleObject): + raise_exception(space, "unmarshallable object") + items = w_tuple.tolist() m.put_tuple_w(TYPE_TUPLE, items) +handled_by_any.append(('tuple', marshal_tuple)) -def unmarshal_Tuple(space, u, tc): +def unmarshal_tuple(space, u, tc): items_w = u.get_tuple_w() return space.newtuple(items_w) -register(TYPE_TUPLE, unmarshal_Tuple) +register(TYPE_TUPLE, unmarshal_tuple) def marshal_list(space, w_list, m): if not isinstance(w_list, W_ListObject): diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -15,8 +15,6 @@ _registered_implementations.add(implcls) option_to_typename = { - "withspecialisedtuple" : ["specialisedtupleobject.W_SpecialisedTupleObject"], - "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], "withstrbuf" : ["strbufobject.W_StringBufferObject"], } @@ -38,7 +36,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -79,6 +76,7 @@ # not-multimethod based types + self.pythontypes.append(tupleobject.W_TupleObject.typedef) self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) @@ -90,7 +88,6 @@ boolobject.W_BoolObject: [], intobject.W_IntObject: [], floatobject.W_FloatObject: [], - tupleobject.W_TupleObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -109,7 +106,6 @@ self.imported_but_not_registered = { stringobject.W_StringObject: True, - tupleobject.W_TupleObject: True, } for option, value in config.objspace.std: if option.startswith("with") and option in option_to_typename: @@ -190,15 +186,6 @@ (unicodeobject.W_UnicodeObject, strbufobject.delegate_buf2unicode) ] - if config.objspace.std.withsmalltuple: - from pypy.objspace.std import smalltupleobject - self.typeorder[smalltupleobject.W_SmallTupleObject] += [ - (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] - - if config.objspace.std.withspecialisedtuple: - from pypy.objspace.std import specialisedtupleobject - self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ - (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] # put W_Root everywhere self.typeorder[W_Root] = [] diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -281,7 +281,7 @@ return newlong(self, val) def newtuple(self, list_w): - from pypy.objspace.std.tupletype import wraptuple + from pypy.objspace.std.tupleobject import wraptuple assert isinstance(list_w, list) make_sure_not_resized(list_w) return wraptuple(self, list_w) @@ -663,6 +663,12 @@ class2type[base] = w_type self._interplevel_classes[w_type] = base + # register other things + self._interplevel_classes[self.w_dict] = W_DictMultiObject + self._interplevel_classes[self.w_list] = W_ListObject + self._interplevel_classes[self.w_set] = W_SetObject + self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + @specialize.memo() def _get_interplevel_cls(self, w_type): if not hasattr(self, "_interplevel_classes"): diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/smalltupleobject.py +++ /dev/null @@ -1,161 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement -from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.interpreter import gateway -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib.unroll import unrolling_iterable -from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject - -class W_SmallTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] - return tuple(items) - -def make_specialized_class(n): - iter_n = unrolling_iterable(range(n)) - class cls(W_SmallTupleObject): - - def __init__(self, values): - assert len(values) == n - for i in iter_n: - setattr(self, 'w_value%s' % i, values[i]) - - def tolist(self): - l = [None] * n - for i in iter_n: - l[i] = getattr(self, 'w_value%s' % i) - return l - - # same source code, but builds and returns a resizable list - getitems_copy = func_with_new_name(tolist, 'getitems_copy') - - def length(self): - return n - - def getitem(self, index): - for i in iter_n: - if index == i: - return getattr(self,'w_value%s' % i) - raise IndexError - - def setitem(self, index, w_item): - for i in iter_n: - if index == i: - setattr(self, 'w_value%s' % i, w_item) - return - raise IndexError - - def eq(self, space, w_other): - if n != w_other.length(): - return space.w_False - for i in iter_n: - item1 = getattr(self,'w_value%s' % i) - item2 = w_other.getitem(i) - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - - def hash(self, space): - mult = 1000003 - x = 0x345678 - z = n - for i in iter_n: - w_item = getattr(self, 'w_value%s' % i) - y = space.int_w(space.hash(w_item)) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return space.wrap(intmask(x)) - - cls.__name__ = "W_SmallTupleObject%s" % n - return cls - -W_SmallTupleObject2 = make_specialized_class(2) -W_SmallTupleObject3 = make_specialized_class(3) -W_SmallTupleObject4 = make_specialized_class(4) -W_SmallTupleObject5 = make_specialized_class(5) -W_SmallTupleObject6 = make_specialized_class(6) -W_SmallTupleObject7 = make_specialized_class(7) -W_SmallTupleObject8 = make_specialized_class(8) - -registerimplementation(W_SmallTupleObject) - -def delegate_SmallTuple2Tuple(space, w_small): - return W_TupleObject(w_small.tolist()) - -def len__SmallTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SmallTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SmallTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_smalltuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SmallTuple_ANY(space, w_tuple, w_times): - return mul_smalltuple_times(space, w_tuple, w_times) - -def mul__ANY_SmallTuple(space, w_times, w_tuple): - return mul_smalltuple_times(space, w_tuple, w_times) - -def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def hash__SmallTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -1,63 +1,23 @@ from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.tupleobject import W_AbstractTupleObject -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.util import negate +from rpython.rlib.objectmodel import compute_hash from rpython.rlib.rarithmetic import intmask -from rpython.rlib.objectmodel import compute_hash from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name + class NotSpecialised(Exception): pass -class W_SpecialisedTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - __slots__ = [] - - def __repr__(self): - """ representation for debugging purposes """ - reprlist = [repr(item) for item in self._to_unwrapped_list()] - return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def _to_unwrapped_list(self): - "NOT_RPYTHON" - raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(self, space): - return tuple(self._to_unwrapped_list()) - - def delegating(self): - pass # for tests only - def make_specialised_class(typetuple): assert type(typetuple) == tuple - + nValues = len(typetuple) iter_n = unrolling_iterable(range(nValues)) - - class cls(W_SpecialisedTupleObject): + + class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space assert len(values_w) == nValues @@ -80,7 +40,7 @@ return nValues def tolist(self): - list_w = [None] * nValues + list_w = [None] * nValues for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -91,18 +51,7 @@ # same source code, but builds and returns a resizable list getitems_copy = func_with_new_name(tolist, 'getitems_copy') - def _to_unwrapped_list(self): - "NOT_RPYTHON" - list_w = [None] * nValues - for i in iter_n: - value = getattr(self, 'value%s' % i) - if typetuple[i] == object: - value = self.space.unwrap(value) - list_w[i] = value - return list_w - - def hash(self, space): - # XXX duplicate logic from tupleobject.py + def descr_hash(self, space): mult = 1000003 x = 0x345678 z = nValues @@ -123,50 +72,45 @@ x += 97531 return space.wrap(intmask(x)) - def _eq(self, w_other): + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented if not isinstance(w_other, cls): - # if we are not comparing same types, give up - raise FailedToImplement + if nValues != w_other.length(): + return space.w_False + for i in iter_n: + myval = getattr(self, 'value%s' % i) + otherval = w_other.getitem(space, i) + if typetuple[i] != object: + myval = space.wrap(myval) + if not space.eq_w(myval, otherval): + return space.w_False + return space.w_True + for i in iter_n: - myval = getattr(self, 'value%s' % i) + myval = getattr(self, 'value%s' % i) otherval = getattr(w_other, 'value%s' % i) if typetuple[i] == object: if not self.space.eq_w(myval, otherval): - return False + return space.w_False else: if myval != otherval: - return False - else: - return True + return space.w_False + return space.w_True - def eq(self, space, w_other): - return space.newbool(self._eq(w_other)) + descr_ne = negate(descr_eq) - def ne(self, space, w_other): - return space.newbool(not self._eq(w_other)) - -## def _compare(self, compare_op, w_other): -## if not isinstance(w_other, cls): -## raise FailedToImplement -## ncmp = min(self.length(), w_other.length()) -## for i in iter_n: -## if typetuple[i] == Any:#like space.eq on wrapped or two params? -## raise FailedToImplement -## if ncmp > i: -## l_val = getattr(self, 'value%s' % i) -## r_val = getattr(w_other, 'value%s' % i) -## if l_val != r_val: -## return compare_op(l_val, r_val) -## return compare_op(self.length(), w_other.length()) - - def getitem(self, index): + def getitem(self, space, index): + if index < 0: + index += nValues for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) if typetuple[i] != object: - value = self.space.wrap(value) + value = space.wrap(value) return value - raise IndexError + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) cls.__name__ = ('W_SpecialisedTupleObject_' + ''.join([t.__name__[0] for t in typetuple])) @@ -177,129 +121,21 @@ _specialisations = [] Cls_ii = make_specialised_class((int, int)) -#Cls_is = make_specialised_class((int, str)) -#Cls_io = make_specialised_class((int, object)) -#Cls_si = make_specialised_class((str, int)) -#Cls_ss = make_specialised_class((str, str)) -#Cls_so = make_specialised_class((str, object)) -#Cls_oi = make_specialised_class((object, int)) -#Cls_os = make_specialised_class((object, str)) Cls_oo = make_specialised_class((object, object)) Cls_ff = make_specialised_class((float, float)) -#Cls_ooo = make_specialised_class((object, object, object)) def makespecialisedtuple(space, list_w): if len(list_w) == 2: w_arg1, w_arg2 = list_w w_type1 = space.type(w_arg1) - #w_type2 = space.type(w_arg2) - # if w_type1 is space.w_int: w_type2 = space.type(w_arg2) if w_type2 is space.w_int: return Cls_ii(space, w_arg1, w_arg2) - #elif w_type2 is space.w_str: - # return Cls_is(space, w_arg1, w_arg2) - #else: - # return Cls_io(space, w_arg1, w_arg2) - # - #elif w_type1 is space.w_str: - # if w_type2 is space.w_int: - # return Cls_si(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_ss(space, w_arg1, w_arg2) - # else: - # return Cls_so(space, w_arg1, w_arg2) - # elif w_type1 is space.w_float: w_type2 = space.type(w_arg2) if w_type2 is space.w_float: return Cls_ff(space, w_arg1, w_arg2) - # - #else: - # if w_type2 is space.w_int: - # return Cls_oi(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_os(space, w_arg1, w_arg2) - # else: return Cls_oo(space, w_arg1, w_arg2) - # - #elif len(list_w) == 3: - # return Cls_ooo(space, list_w[0], list_w[1], list_w[2]) else: raise NotSpecialised - -# ____________________________________________________________ - -registerimplementation(W_SpecialisedTupleObject) - -def delegate_SpecialisedTuple2Tuple(space, w_specialised): - w_specialised.delegating() - return W_TupleObject(w_specialised.tolist()) - -def len__SpecialisedTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SpecialisedTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SpecialisedTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_specialisedtuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SpecialisedTuple_ANY(space, w_tuple, w_times): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def mul__ANY_SpecialisedTuple(space, w_times, w_tuple): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.ne(space, w_tuple2) - -##from operator import lt, le, ge, gt - -##def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(lt, w_tuple2)) - -##def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(le, w_tuple2)) - -##def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(ge, w_tuple2)) - -##def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(gt, w_tuple2)) - -def hash__SpecialisedTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -12,7 +12,6 @@ from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringtype import ( joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) -from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib import jit from rpython.rlib.objectmodel import ( compute_hash, compute_unique_id, specialize) @@ -684,7 +683,9 @@ w_end, True) return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) -def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): +def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): + if not space.isinstance_w(w_suffixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): @@ -702,7 +703,9 @@ w_end, True) return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) -def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): +def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): + if not space.isinstance_w(w_prefixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ /dev/null @@ -1,84 +0,0 @@ -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject -from pypy.interpreter.error import OperationError -from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject -from pypy.tool.pytest.objspace import gettestobjspace - -class AppTestW_SmallTupleObject(AppTestW_TupleObject): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def setup_class(cls): - cls.w_issmall = cls.space.appexec([], """(): - import __pypy__ - def issmall(obj): - assert "SmallTuple" in __pypy__.internal_repr(obj) - return issmall - """) - - def test_smalltuple(self): - self.issmall((1,2)) - self.issmall((1,2,3)) - - def test_slicing_to_small(self): - self.issmall((1, 2, 3)[0:2]) # SmallTuple2 - self.issmall((1, 2, 3)[0:2:1]) - - self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3 - self.issmall((1, 2, 3, 4)[0:3:1]) - - def test_adding_to_small(self): - self.issmall((1,)+(2,)) # SmallTuple2 - self.issmall((1,1)+(2,)) # SmallTuple3 - self.issmall((1,)+(2,3)) - - def test_multiply_to_small(self): - self.issmall((1,)*2) - self.issmall((1,)*3) - - def test_slicing_from_small(self): - assert (1,2)[0:1:1] == (1,) - assert (1,2,3)[0:2:1] == (1,2) - - def test_eq(self): - a = (1,2,3) - b = (1,2,3) - assert a == b - - c = (1,3,2) - assert a != c - - def test_hash(self): - a = (1,2,3) - b = (1,2,3) - assert hash(a) == hash(b) - - c = (1,3,2) - assert hash(a) != hash(c) - -class TestW_SmallTupleObject(): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def test_issmalltupleobject(self): - w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - assert isinstance(w_tuple, W_SmallTupleObject) - - def test_hash_agains_normal_tuple(self): - normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) - w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) - w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - assert isinstance(w_smalltuple, W_SmallTupleObject) - assert isinstance(w_tuple, W_TupleObject) - assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) - - def test_setitem(self): - w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - w_smalltuple.setitem(0, self.space.wrap(5)) - list_w = w_smalltuple.tolist() - assert len(list_w) == 2 - assert self.space.eq_w(list_w[0], self.space.wrap(5)) - assert self.space.eq_w(list_w[1], self.space.wrap(2)) diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -1,11 +1,7 @@ -import py, sys +from pypy.objspace.std.specialisedtupleobject import _specialisations +from pypy.objspace.std.test import test_tupleobject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject -from pypy.objspace.std.specialisedtupleobject import _specialisations -from pypy.interpreter.error import OperationError from pypy.tool.pytest.objspace import gettestobjspace -from pypy.objspace.std.test import test_tupleobject -from pypy.interpreter import gateway for cls in _specialisations: @@ -18,62 +14,43 @@ def test_isspecialisedtupleobjectintint(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert isinstance(w_tuple, W_SpecialisedTupleObject_ii) - + def test_isnotspecialisedtupleobject(self): w_tuple = self.space.newtuple([self.space.wrap({})]) - assert not isinstance(w_tuple, W_SpecialisedTupleObject) - + assert not 'W_SpecialisedTupleObject' in type(w_tuple).__name__ + def test_specialisedtupleclassname(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii' def test_hash_against_normal_tuple(self): - N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": False}) - S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) - def hash_test(values, must_be_specialized=True): - N_values_w = [N_space.wrap(value) for value in values] - S_values_w = [S_space.wrap(value) for value in values] - N_w_tuple = N_space.newtuple(N_values_w) - S_w_tuple = S_space.newtuple(S_values_w) + N_values_w = [self.space.wrap(value) for value in values] + S_values_w = [self.space.wrap(value) for value in values] + N_w_tuple = W_TupleObject(N_values_w) + S_w_tuple = self.space.newtuple(S_values_w) if must_be_specialized: - assert isinstance(S_w_tuple, W_SpecialisedTupleObject) - assert isinstance(N_w_tuple, W_TupleObject) - assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) - assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) + assert 'W_SpecialisedTupleObject' in type(S_w_tuple).__name__ + assert self.space.is_true(self.space.eq(N_w_tuple, S_w_tuple)) + assert self.space.is_true( + self.space.eq(self.space.hash(N_w_tuple), + self.space.hash(S_w_tuple))) - hash_test([1,2]) - hash_test([1.5,2.8]) - hash_test([1.0,2.0]) - hash_test(['arbitrary','strings']) - hash_test([1,(1,2,3,4)]) - hash_test([1,(1,2)]) - hash_test([1,('a',2)]) - hash_test([1,()]) - hash_test([1,2,3], must_be_specialized=False) + hash_test([1, 2]) + hash_test([1.5, 2.8]) + hash_test([1.0, 2.0]) + hash_test(['arbitrary', 'strings']) + hash_test([1, (1, 2, 3, 4)]) + hash_test([1, (1, 2)]) + hash_test([1, ('a', 2)]) + hash_test([1, ()]) + hash_test([1, 2, 3], must_be_specialized=False) class AppTestW_SpecialisedTupleObject: spaceconfig = {"objspace.std.withspecialisedtuple": True} - def setup_class(cls): - def forbid_delegation(space, w_tuple): - def delegation_forbidden(): - # haaaack - co = sys._getframe(2).f_code - if co.co_name.startswith('_mm_repr_tuple'): - return - raise OperationError(space.w_ReferenceError, w_tuple) - w_tuple.delegating = delegation_forbidden - return w_tuple - if cls.runappdirect: - cls.w_forbid_delegation = lambda self, x: x - cls.test_delegation = lambda self: skip("runappdirect") - else: - cls.w_forbid_delegation = cls.space.wrap( - gateway.interp2app(forbid_delegation)) - def w_isspecialised(self, obj, expected=''): import __pypy__ r = __pypy__.internal_repr(obj) @@ -101,16 +78,12 @@ obj = (1, 2, 3) assert self.isspecialised(obj, '_ooo') - def test_delegation(self): - t = self.forbid_delegation((42, 43)) - raises(ReferenceError, t.__getslice__, 0, 1) - def test_len(self): - t = self.forbid_delegation((42,43)) + t = (42, 43) assert len(t) == 2 def test_notspecialisedtuple(self): - assert not self.isspecialised((42,43,44,45)) + assert not self.isspecialised((42, 43, 44, 45)) assert not self.isspecialised((1.5,)) def test_slicing_to_specialised(self): @@ -133,79 +106,79 @@ def test_eq_no_delegation(self): t = (1,) - a = self.forbid_delegation(t + (2,)) + a = t + (2,) b = (1, 2) assert a == b c = (2, 1) assert not a == c - def test_eq_can_delegate(self): - a = (1,2) - b = (1,3,2) + def test_eq_can_delegate(self): + a = (1, 2) + b = (1, 3, 2) assert not a == b values = [2, 2L, 2.0, 1, 1L, 1.0] for x in values: for y in values: - assert ((1,2) == (x,y)) == (1 == x and 2 == y) + assert ((1, 2) == (x, y)) == (1 == x and 2 == y) def test_neq(self): - a = self.forbid_delegation((1,2)) + a = (1, 2) b = (1,) - b = b+(2,) + b = b + (2,) assert not a != b - - c = (1,3) + + c = (1, 3) assert a != c - + def test_ordering(self): - a = (1,2) #self.forbid_delegation((1,2)) --- code commented out - assert a < (2,2) - assert a < (1,3) - assert not a < (1,2) + a = (1, 2) + assert a < (2, 2) + assert a < (1, 3) + assert not a < (1, 2) - assert a <= (2,2) - assert a <= (1,2) - assert not a <= (1,1) - - assert a >= (0,2) - assert a >= (1,2) - assert not a >= (1,3) - - assert a > (0,2) - assert a > (1,1) - assert not a > (1,3) + assert a <= (2, 2) + assert a <= (1, 2) + assert not a <= (1, 1) - assert (2,2) > a - assert (1,3) > a - assert not (1,2) > a - - assert (2,2) >= a - assert (1,2) >= a - assert not (1,1) >= a - - assert (0,2) <= a - assert (1,2) <= a - assert not (1,3) <= a - - assert (0,2) < a - assert (1,1) < a - assert not (1,3) < a + assert a >= (0, 2) + assert a >= (1, 2) + assert not a >= (1, 3) + + assert a > (0, 2) + assert a > (1, 1) + assert not a > (1, 3) + + assert (2, 2) > a + assert (1, 3) > a + assert not (1, 2) > a + + assert (2, 2) >= a + assert (1, 2) >= a + assert not (1, 1) >= a + + assert (0, 2) <= a + assert (1, 2) <= a + assert not (1, 3) <= a + + assert (0, 2) < a + assert (1, 1) < a + assert not (1, 3) < a def test_hash(self): - a = (1,2) + a = (1, 2) b = (1,) - b += (2,) # else a and b refer to same constant + b += (2,) # else a and b refer to same constant assert hash(a) == hash(b) - c = (2,4) + c = (2, 4) assert hash(a) != hash(c) assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L)) def test_getitem(self): - t = self.forbid_delegation((5,3)) + t = (5, 3) assert (t)[0] == 5 assert (t)[1] == 3 assert (t)[-1] == 3 @@ -216,14 +189,14 @@ def test_three_tuples(self): if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - b = self.forbid_delegation((1, 2, 3)) + b = (1, 2, 3) c = (1,) d = c + (2, 3) assert self.isspecialised(d) assert b == d def test_mongrel(self): - a = self.forbid_delegation((2.2, '333')) + a = (2.2, '333') assert self.isspecialised(a) assert len(a) == 2 assert a[0] == 2.2 and a[1] == '333' @@ -233,7 +206,7 @@ # if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - a = self.forbid_delegation((1, 2.2, '333')) + a = (1, 2.2, '333') assert self.isspecialised(a) assert len(a) == 3 assert a[0] == 1 and a[1] == 2.2 and a[2] == '333' @@ -243,4 +216,4 @@ class AppTestAll(test_tupleobject.AppTestW_TupleObject): - pass + spaceconfig = {"objspace.std.withspecialisedtuple": True} diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -1,17 +1,16 @@ -#from __future__ import nested_scopes +from pypy.interpreter.error import OperationError from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.interpreter.error import OperationError + class TestW_TupleObject: - def test_is_true(self): w = self.space.wrap w_tuple = W_TupleObject([]) - assert self.space.is_true(w_tuple) == False + assert self.space.is_true(w_tuple) is False w_tuple = W_TupleObject([w(5)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True w_tuple = W_TupleObject([w(5), w(3)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True def test_len(self): w = self.space.wrap @@ -19,7 +18,7 @@ assert self.space.eq_w(self.space.len(w_tuple), w(0)) w_tuple = W_TupleObject([w(5)]) assert self.space.eq_w(self.space.len(w_tuple), w(1)) - w_tuple = W_TupleObject([w(5), w(3), w(99)]*111) + w_tuple = W_TupleObject([w(5), w(3), w(99)] * 111) assert self.space.eq_w(self.space.len(w_tuple), w(333)) def test_getitem(self): @@ -65,7 +64,7 @@ w_tuple2 = W_TupleObject([w(-7)] * 111) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple1), W_TupleObject([w(5), w(3), w(99), - w(5), w(3), w(99)])) + w(5), w(3), w(99)])) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple2), W_TupleObject([w(5), w(3), w(99)] + [w(-7)] * 111)) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple0), w_tuple1) @@ -77,7 +76,7 @@ arg = w(2) n = 3 w_tup = W_TupleObject([arg]) - w_tup3 = W_TupleObject([arg]*n) + w_tup3 = W_TupleObject([arg] * n) w_res = self.space.mul(w_tup, w(n)) assert self.space.eq_w(w_tup3, w_res) # commute @@ -91,26 +90,26 @@ w = self.space.wrap def test1(testtuple, start, stop, step, expected): - w_slice = self.space.newslice(w(start), w(stop), w(step)) + w_slice = self.space.newslice(w(start), w(stop), w(step)) w_tuple = W_TupleObject([w(i) for i in testtuple]) w_result = self.space.getitem(w_tuple, w_slice) assert self.space.unwrap(w_result) == expected - - for testtuple in [(), (5,3,99), tuple(range(5,555,10))]: + + for testtuple in [(), (5, 3, 99), tuple(range(5, 555, 10))]: for start in [-2, -1, 0, 1, 10]: for end in [-1, 0, 2, 999]: test1(testtuple, start, end, 1, testtuple[start:end]) - test1((5,7,1,4), 3, 1, -2, (4,)) - test1((5,7,1,4), 3, 0, -2, (4, 7)) - test1((5,7,1,4), 3, -1, -2, ()) - test1((5,7,1,4), -2, 11, 2, (1,)) - test1((5,7,1,4), -3, 11, 2, (7, 4)) - test1((5,7,1,4), -5, 11, 2, (5, 1)) + test1((5, 7, 1, 4), 3, 1, -2, (4,)) + test1((5, 7, 1, 4), 3, 0, -2, (4, 7)) + test1((5, 7, 1, 4), 3, -1, -2, ()) + test1((5, 7, 1, 4), -2, 11, 2, (1,)) + test1((5, 7, 1, 4), -3, 11, 2, (7, 4)) + test1((5, 7, 1, 4), -5, 11, 2, (5, 1)) def test_eq(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -126,9 +125,10 @@ self.space.w_True) assert self.space.eq_w(self.space.eq(w_tuple2, w_tuple3), self.space.w_False) + def test_ne(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -144,9 +144,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ne(w_tuple2, w_tuple3), self.space.w_True) + def test_lt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -165,10 +166,10 @@ self.space.w_True) assert self.space.eq_w(self.space.lt(w_tuple4, w_tuple3), self.space.w_True) - + def test_ge(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -187,10 +188,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ge(w_tuple4, w_tuple3), self.space.w_False) - + def test_gt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -209,10 +210,10 @@ self.space.w_False) assert self.space.eq_w(self.space.gt(w_tuple4, w_tuple3), self.space.w_False) - + def test_le(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -234,28 +235,27 @@ class AppTestW_TupleObject: - def test_is_true(self): assert not () assert (5,) - assert (5,3) + assert (5, 3) def test_len(self): assert len(()) == 0 assert len((5,)) == 1 - assert len((5,3,99,1,2,3,4,5,6)) == 9 + assert len((5, 3, 99, 1, 2, 3, 4, 5, 6)) == 9 def test_getitem(self): - assert (5,3)[0] == 5 - assert (5,3)[1] == 3 - assert (5,3)[-1] == 3 - assert (5,3)[-2] == 5 - raises(IndexError, "(5,3)[2]") + assert (5, 3)[0] == 5 + assert (5, 3)[1] == 3 + assert (5, 3)[-1] == 3 + assert (5, 3)[-2] == 5 + raises(IndexError, "(5, 3)[2]") raises(IndexError, "(5,)[1]") raises(IndexError, "()[0]") def test_iter(self): - t = (5,3,99) + t = (5, 3, 99) i = iter(t) assert i.next() == 5 assert i.next() == 3 @@ -263,7 +263,7 @@ raises(StopIteration, i.next) def test_contains(self): - t = (5,3,99) + t = (5, 3, 99) assert 5 in t assert 99 in t assert not 11 in t @@ -271,35 +271,35 @@ def test_add(self): t0 = () - t1 = (5,3,99) + t1 = (5, 3, 99) assert t0 + t0 == t0 assert t1 + t0 == t1 - assert t1 + t1 == (5,3,99,5,3,99) + assert t1 + t1 == (5, 3, 99, 5, 3, 99) def test_mul(self): assert () * 10 == () - assert (5,) * 3 == (5,5,5) - assert (5,2) * 2 == (5,2,5,2) + assert (5,) * 3 == (5, 5, 5) + assert (5, 2) * 2 == (5, 2, 5, 2) def test_mul_identity(self): - t = (1,2,3) + t = (1, 2, 3) assert (t * 1) is t def test_mul_subtype(self): class T(tuple): pass - t = T([1,2,3]) + t = T([1, 2, 3]) assert (t * 1) is not t assert (t * 1) == t def test_getslice_2(self): - assert (5,2,3)[1:2] == (2,) + assert (5, 2, 3)[1:2] == (2,) def test_eq(self): t0 = () - t1 = (5,3,99) - t2 = (5,3,99) - t3 = (5,3,99,-1) - t4 = (5,3,9,1) + t1 = (5, 3, 99) + t2 = (5, 3, 99) + t3 = (5, 3, 99, -1) + t4 = (5, 3, 9, 1) assert not t0 == t1 assert t0 != t1 assert t1 == t2 @@ -321,15 +321,15 @@ # check that hash behaves as in 2.4 for at least 31 bits assert hash(()) & 0x7fffffff == 0x35d373 assert hash((12,)) & 0x7fffffff == 0x1cca0557 - assert hash((12,34)) & 0x7fffffff == 0x153e2a41 + assert hash((12, 34)) & 0x7fffffff == 0x153e2a41 def test_getnewargs(self): - assert () .__getnewargs__() == ((),) + assert () .__getnewargs__() == ((),) def test_repr(self): assert repr((1,)) == '(1,)' assert repr(()) == '()' - assert repr((1,2,3)) == '(1, 2, 3)' + assert repr((1, 2, 3)) == '(1, 2, 3)' def test_getslice(self): assert ('a', 'b', 'c').__getslice__(-17, 2) == ('a', 'b') @@ -399,3 +399,11 @@ assert ((5,) != (N,)) is True assert ((5,) > (N,)) is False assert ((5,) >= (N,)) is False + + def test_eq_other_type(self): + assert (() == object()) is False + assert ((1,) == object()) is False + assert ((1, 2) == object()) is False + assert (() != object()) is True + assert ((1,) != object()) is True + assert ((1, 2) != object()) is True diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,212 +1,297 @@ +import sys +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate +from rpython.rlib import jit +from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib import jit -from rpython.tool.sourcetools import func_with_new_name + UNROLL_CUTOFF = 10 -class W_AbstractTupleObject(W_Object): + +def _unroll_condition(self): + return jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) + + +def _unroll_condition_cmp(self, space, other): + return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF)) + + +class W_AbstractTupleObject(W_Root): __slots__ = () + def __repr__(self): + """representation for debugging purposes""" + reprlist = [repr(w_item) for w_item in self.tolist()] + return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) + + def unwrap(self, space): + items = [space.unwrap(w_item) for w_item in self.tolist()] + return tuple(items) + def tolist(self): - "Returns the items, as a fixed-size list." + """Returns the items, as a fixed-size list.""" raise NotImplementedError def getitems_copy(self): - "Returns a copy of the items, as a resizable list." + """Returns a copy of the items, as a resizable list.""" raise NotImplementedError + def length(self): + raise NotImplementedError + + def getitem(self, space, item): + raise NotImplementedError + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + + def descr_iter(self, space): + from pypy.objspace.std import iterobject + return iterobject.W_FastTupleIterObject(self, self.tolist()) + + @staticmethod + def descr_new(space, w_tupletype, w_sequence=None): + if w_sequence is None: + tuple_w = [] + elif (space.is_w(w_tupletype, space.w_tuple) and + space.is_w(space.type(w_sequence), space.w_tuple)): + return w_sequence + else: + tuple_w = space.fixedview(w_sequence) + w_obj = space.allocate_instance(W_TupleObject, w_tupletype) + W_TupleObject.__init__(w_obj, tuple_w) + return w_obj + + def descr_repr(self, space): + items = self.tolist() + if len(items) == 1: + return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") + tmp = ", ".join([space.str_w(space.repr(item)) for item in items]) + return space.wrap("(" + tmp + ")") + + def descr_hash(self, space): + raise NotImplementedError + + def descr_eq(self, space, w_other): + raise NotImplementedError + + def descr_ne(self, space, w_other): + raise NotImplementedError + + def _make_tuple_comparison(name): + import operator + op = getattr(operator, name) + + def compare_tuples(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return _compare_tuples(self, space, w_other) + + @jit.look_inside_iff(_unroll_condition_cmp) + def _compare_tuples(self, space, w_other): + items1 = self.tolist() + items2 = w_other.tolist() + ncmp = min(len(items1), len(items2)) + # Search for the first index where items are different + for p in range(ncmp): + if not space.eq_w(items1[p], items2[p]): + return getattr(space, name)(items1[p], items2[p]) + # No more items to compare -- compare sizes + return space.newbool(op(len(items1), len(items2))) + + compare_tuples.__name__ = 'descr_' + name + return compare_tuples + + descr_lt = _make_tuple_comparison('lt') + descr_le = _make_tuple_comparison('le') + descr_gt = _make_tuple_comparison('gt') + descr_ge = _make_tuple_comparison('ge') + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_contains(self, space, w_obj): + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + return space.w_True + return space.w_False + + def descr_add(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + items1 = self.tolist() + items2 = w_other.tolist() + return space.newtuple(items1 + items2) + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + if times == 1 and space.type(self) == space.w_tuple: + return self + items = self.tolist() + return space.newtuple(items * times) + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + return self._getslice(space, w_index) + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") + return self.getitem(space, index) + + def _getslice(self, space, w_index): + items = self.tolist() + length = len(items) + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = items[start] + start += step + return space.newtuple(subitems) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + return space.newtuple(self.tolist()[start:stop]) + + def descr_getnewargs(self, space): + return space.newtuple([space.newtuple(self.tolist())]) + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_count(self, space, w_obj): + """count(obj) -> number of times obj appears in the tuple""" + count = 0 + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + count += 1 + return space.wrap(count) + + @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), + w_stop=gateway.WrappedDefault(sys.maxint)) + @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) + def descr_index(self, space, w_obj, w_start, w_stop): + """index(obj, [start, [stop]]) -> first index that obj appears in the + tuple + """ + length = self.length() + start, stop = slicetype.unwrap_start_stop(space, length, w_start, + w_stop) + for i in range(start, min(stop, length)): + w_item = self.tolist()[i] + if space.eq_w(w_item, w_obj): + return space.wrap(i) + raise OperationError(space.w_ValueError, + space.wrap("tuple.index(x): x not in tuple")) + +W_AbstractTupleObject.typedef = StdTypeDef( + "tuple", + __doc__ = '''tuple() -> an empty tuple +tuple(sequence) -> tuple initialized from sequence's items + +If the argument is a tuple, the return value is the same object.''', + __new__ = interp2app(W_AbstractTupleObject.descr_new), + __repr__ = interp2app(W_AbstractTupleObject.descr_repr), + __hash__ = interpindirect2app(W_AbstractTupleObject.descr_hash), + + __eq__ = interpindirect2app(W_AbstractTupleObject.descr_eq), + __ne__ = interpindirect2app(W_AbstractTupleObject.descr_ne), + __lt__ = interp2app(W_AbstractTupleObject.descr_lt), + __le__ = interp2app(W_AbstractTupleObject.descr_le), + __gt__ = interp2app(W_AbstractTupleObject.descr_gt), + __ge__ = interp2app(W_AbstractTupleObject.descr_ge), + + __len__ = interp2app(W_AbstractTupleObject.descr_len), + __iter__ = interp2app(W_AbstractTupleObject.descr_iter), + __contains__ = interp2app(W_AbstractTupleObject.descr_contains), + + __add__ = interp2app(W_AbstractTupleObject.descr_add), + __mul__ = interp2app(W_AbstractTupleObject.descr_mul), + __rmul__ = interp2app(W_AbstractTupleObject.descr_mul), + + __getitem__ = interp2app(W_AbstractTupleObject.descr_getitem), + __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice), + + __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs), + count = interp2app(W_AbstractTupleObject.descr_count), + index = interp2app(W_AbstractTupleObject.descr_index) +) + class W_TupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef _immutable_fields_ = ['wrappeditems[*]'] - def __init__(w_self, wrappeditems): + def __init__(self, wrappeditems): make_sure_not_resized(wrappeditems) - w_self.wrappeditems = wrappeditems # a list of wrapped values - - def __repr__(w_self): - """ representation for debugging purposes """ - reprlist = [repr(w_item) for w_item in w_self.wrappeditems] - return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] - return tuple(items) + self.wrappeditems = wrappeditems def tolist(self): return self.wrappeditems def getitems_copy(self): - return self.wrappeditems[:] # returns a resizable list + return self.wrappeditems[:] # returns a resizable list -registerimplementation(W_TupleObject) + def length(self): + return len(self.wrappeditems) + @jit.look_inside_iff(lambda self, _1: _unroll_condition(self)) + def descr_hash(self, space): + mult = 1000003 + x = 0x345678 + z = len(self.wrappeditems) + for w_item in self.wrappeditems: + y = space.hash_w(w_item) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) -def len__Tuple(space, w_tuple): - result = len(w_tuple.wrappeditems) - return wrapint(space, result) + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) -def getitem__Tuple_ANY(space, w_tuple, w_index): - # getindex_w should get a second argument space.w_IndexError, - # but that doesn't exist the first time this is called. - try: - w_IndexError = space.w_IndexError - except AttributeError: - w_IndexError = None - index = space.getindex_w(w_index, w_IndexError, "tuple index") - try: - return w_tuple.wrappeditems[index] - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) + @jit.look_inside_iff(_unroll_condition_cmp) + def _descr_eq(self, space, w_other): + items1 = self.wrappeditems + items2 = w_other.tolist() + lgt1 = len(items1) + lgt2 = len(items2) + if lgt1 != lgt2: + return space.w_False + for i in range(lgt1): + item1 = items1[i] + item2 = items2[i] + if not space.eq_w(item1, item2): + return space.w_False + return space.w_True -def getitem__Tuple_Slice(space, w_tuple, w_slice): - items = w_tuple.wrappeditems - length = len(items) - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = items[start] - start += step - return space.newtuple(subitems) + descr_ne = negate(descr_eq) -def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return space.newtuple(w_tuple.wrappeditems[start:stop]) + def getitem(self, space, index): + try: + return self.wrappeditems[index] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) - at jit.look_inside_iff(lambda space, w_tuple, w_obj: - jit.loop_unrolling_heuristic(w_tuple, len(w_tuple.wrappeditems), UNROLL_CUTOFF)) -def contains__Tuple_ANY(space, w_tuple, w_obj): - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - return space.w_True - return space.w_False -def iter__Tuple(space, w_tuple): - from pypy.objspace.std import iterobject - return iterobject.W_FastTupleIterObject(w_tuple, w_tuple.wrappeditems) - -def add__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - return space.newtuple(items1 + items2) - -def mul_tuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.wrappeditems - return space.newtuple(items * times) - -def mul__Tuple_ANY(space, w_tuple, w_times): - return mul_tuple_times(space, w_tuple, w_times) - -def mul__ANY_Tuple(space, w_times, w_tuple): - return mul_tuple_times(space, w_tuple, w_times) - -def tuple_unroll_condition(space, w_tuple1, w_tuple2): - return jit.loop_unrolling_heuristic(w_tuple1, len(w_tuple1.wrappeditems), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_tuple2, len(w_tuple2.wrappeditems), UNROLL_CUTOFF) - - at jit.look_inside_iff(tuple_unroll_condition) -def eq__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - lgt1 = len(items1) - lgt2 = len(items2) - if lgt1 != lgt2: - return space.w_False - for i in range(lgt1): - item1 = items1[i] - item2 = items2[i] - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - -def _make_tuple_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(tuple_unroll_condition) - def compare_tuples(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - ncmp = min(len(items1), len(items2)) - # Search for the first index where items are different - for p in range(ncmp): - if not space.eq_w(items1[p], items2[p]): - return getattr(space, name)(items1[p], items2[p]) - # No more items to compare -- compare sizes - return space.newbool(op(len(items1), len(items2))) - return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') - -lt__Tuple_Tuple = _make_tuple_comparison('lt') -le__Tuple_Tuple = _make_tuple_comparison('le') -gt__Tuple_Tuple = _make_tuple_comparison('gt') -ge__Tuple_Tuple = _make_tuple_comparison('ge') - -def repr__Tuple(space, w_tuple): - items = w_tuple.wrappeditems - # XXX this is quite innefficient, still better than calling - # it via applevel - if len(items) == 1: - return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") - return space.wrap("(" + - (", ".join([space.str_w(space.repr(item)) for item in items])) - + ")") - -def hash__Tuple(space, w_tuple): - return space.wrap(hash_tuple(space, w_tuple.wrappeditems)) - - at jit.look_inside_iff(lambda space, wrappeditems: - jit.loop_unrolling_heuristic(wrappeditems, len(wrappeditems), UNROLL_CUTOFF)) -def hash_tuple(space, wrappeditems): - # this is the CPython 2.4 algorithm (changed from 2.3) - mult = 1000003 - x = 0x345678 - z = len(wrappeditems) - for w_item in wrappeditems: - y = space.hash_w(w_item) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return intmask(x) - -def getnewargs__Tuple(space, w_tuple): - return space.newtuple([space.newtuple(w_tuple.wrappeditems)]) - -def tuple_count__Tuple_ANY(space, w_tuple, w_obj): - count = 0 - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - count += 1 - return space.wrap(count) - -def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) - for i in range(start, min(stop, length)): - w_item = w_tuple.wrappeditems[i] - if space.eq_w(w_item, w_obj): - return space.wrap(i) - raise OperationError(space.w_ValueError, - space.wrap("tuple.index(x): x not in tuple")) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) +def wraptuple(space, list_w): + if space.config.objspace.std.withspecialisedtuple: + from specialisedtupleobject import makespecialisedtuple, NotSpecialised + try: + return makespecialisedtuple(space, list_w) + except NotSpecialised: + pass + return W_TupleObject(list_w) diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py deleted file mode 100644 --- a/pypy/objspace/std/tupletype.py +++ /dev/null @@ -1,70 +0,0 @@ -import sys -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -def wraptuple(space, list_w): - from pypy.objspace.std.tupleobject import W_TupleObject - - if space.config.objspace.std.withspecialisedtuple: - from specialisedtupleobject import makespecialisedtuple, NotSpecialised - try: - return makespecialisedtuple(space, list_w) - except NotSpecialised: - pass - - if space.config.objspace.std.withsmalltuple: - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 - if len(list_w) == 2: - return W_SmallTupleObject2(list_w) - if len(list_w) == 3: - return W_SmallTupleObject3(list_w) - if len(list_w) == 4: - return W_SmallTupleObject4(list_w) - if len(list_w) == 5: - return W_SmallTupleObject5(list_w) - if len(list_w) == 6: - return W_SmallTupleObject6(list_w) - if len(list_w) == 7: - return W_SmallTupleObject7(list_w) - if len(list_w) == 8: - return W_SmallTupleObject8(list_w) - return W_TupleObject(list_w) - -tuple_count = SMM("count", 2, - doc="count(obj) -> number of times obj appears in the tuple") - -tuple_index = SMM("index", 4, defaults=(0, sys.maxint), - doc="index(obj, [start, [stop]]) -> first index that obj " - "appears in the tuple") - - -def descr__new__(space, w_tupletype, w_sequence=None): - from pypy.objspace.std.tupleobject import W_TupleObject - if w_sequence is None: - tuple_w = [] - elif (space.is_w(w_tupletype, space.w_tuple) and - space.is_w(space.type(w_sequence), space.w_tuple)): - return w_sequence - else: - tuple_w = space.fixedview(w_sequence) - w_obj = space.allocate_instance(W_TupleObject, w_tupletype) - W_TupleObject.__init__(w_obj, tuple_w) - return w_obj - -# ____________________________________________________________ - -tuple_typedef = StdTypeDef("tuple", - __doc__ = '''tuple() -> an empty tuple -tuple(sequence) -> tuple initialized from sequence's items - -If the argument is a tuple, the return value is the same object.''', - __new__ = gateway.interp2app(descr__new__), - ) -tuple_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -12,7 +12,6 @@ W_StringObject, make_rsplit_with_delim) from pypy.objspace.std.stringtype import stringendswith, stringstartswith From noreply at buildbot.pypy.org Wed May 22 19:20:26 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 19:20:26 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged default in Message-ID: <20130522172026.473091C331F@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64469:d50a9d7fed1e Date: 2013-05-22 10:19 -0700 http://bitbucket.org/pypy/pypy/changeset/d50a9d7fed1e/ Log: merged default in diff too long, truncating to 2000 out of 2158 lines diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -215,10 +215,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), @@ -364,8 +360,6 @@ # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] - if config.translation.platform == 'arm' and '_continuation' in modules: - modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -25,3 +25,9 @@ .. branch: remove-list-smm-2 Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -14,7 +14,6 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.tupleobject import W_TupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -310,31 +309,30 @@ w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): + if space.isinstance_w(w_prefix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_prefix)]) + return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + w_start, w_stop) + w_prefix = space.wrap(space.bufferstr_new_w(w_prefix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) -def str_startswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_prefix)]) - return stringobject.str_startswith__String_Tuple_ANY_ANY(space, w_str, w_prefix, - w_start, w_stop) - def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): + if space.isinstance_w(w_suffix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_suffix)]) + return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) -def str_endswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_suffix)]) - return stringobject.str_endswith__String_Tuple_ANY_ANY(space, w_str, w_suffix, - w_start, w_stop) - def str_join__Bytearray_ANY(space, w_self, w_list): list_w = space.listview(w_list) if not list_w: diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -23,7 +23,7 @@ from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.floatobject import W_FloatObject -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject @@ -288,14 +288,17 @@ raise_exception(space, 'bad marshal data') register(TYPE_STRINGREF, unmarshal_stringref) -def marshal_w__Tuple(space, w_tuple, m): - items = w_tuple.wrappeditems +def marshal_tuple(space, w_tuple, m): + if not isinstance(w_tuple, W_AbstractTupleObject): + raise_exception(space, "unmarshallable object") + items = w_tuple.tolist() m.put_tuple_w(TYPE_TUPLE, items) +handled_by_any.append(('tuple', marshal_tuple)) -def unmarshal_Tuple(space, u, tc): +def unmarshal_tuple(space, u, tc): items_w = u.get_tuple_w() return space.newtuple(items_w) -register(TYPE_TUPLE, unmarshal_Tuple) +register(TYPE_TUPLE, unmarshal_tuple) def marshal_list(space, w_list, m): if not isinstance(w_list, W_ListObject): diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -15,8 +15,6 @@ _registered_implementations.add(implcls) option_to_typename = { - "withspecialisedtuple" : ["specialisedtupleobject.W_SpecialisedTupleObject"], - "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], "withstrbuf" : ["strbufobject.W_StringBufferObject"], } @@ -38,7 +36,6 @@ from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef - from pypy.objspace.std.tupletype import tuple_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef @@ -79,6 +76,7 @@ # not-multimethod based types + self.pythontypes.append(tupleobject.W_TupleObject.typedef) self.pythontypes.append(listobject.W_ListObject.typedef) self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) @@ -90,7 +88,6 @@ boolobject.W_BoolObject: [], intobject.W_IntObject: [], floatobject.W_FloatObject: [], - tupleobject.W_TupleObject: [], stringobject.W_StringObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], @@ -109,7 +106,6 @@ self.imported_but_not_registered = { stringobject.W_StringObject: True, - tupleobject.W_TupleObject: True, } for option, value in config.objspace.std: if option.startswith("with") and option in option_to_typename: @@ -190,15 +186,6 @@ (unicodeobject.W_UnicodeObject, strbufobject.delegate_buf2unicode) ] - if config.objspace.std.withsmalltuple: - from pypy.objspace.std import smalltupleobject - self.typeorder[smalltupleobject.W_SmallTupleObject] += [ - (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] - - if config.objspace.std.withspecialisedtuple: - from pypy.objspace.std import specialisedtupleobject - self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ - (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] # put W_Root everywhere self.typeorder[W_Root] = [] diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -281,7 +281,7 @@ return newlong(self, val) def newtuple(self, list_w): - from pypy.objspace.std.tupletype import wraptuple + from pypy.objspace.std.tupleobject import wraptuple assert isinstance(list_w, list) make_sure_not_resized(list_w) return wraptuple(self, list_w) @@ -663,6 +663,12 @@ class2type[base] = w_type self._interplevel_classes[w_type] = base + # register other things + self._interplevel_classes[self.w_dict] = W_DictMultiObject + self._interplevel_classes[self.w_list] = W_ListObject + self._interplevel_classes[self.w_set] = W_SetObject + self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + @specialize.memo() def _get_interplevel_cls(self, w_type): if not hasattr(self, "_interplevel_classes"): diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/smalltupleobject.py +++ /dev/null @@ -1,161 +0,0 @@ -from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement -from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.interpreter import gateway -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib.unroll import unrolling_iterable -from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject - -class W_SmallTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.tolist()] - return tuple(items) - -def make_specialized_class(n): - iter_n = unrolling_iterable(range(n)) - class cls(W_SmallTupleObject): - - def __init__(self, values): - assert len(values) == n - for i in iter_n: - setattr(self, 'w_value%s' % i, values[i]) - - def tolist(self): - l = [None] * n - for i in iter_n: - l[i] = getattr(self, 'w_value%s' % i) - return l - - # same source code, but builds and returns a resizable list - getitems_copy = func_with_new_name(tolist, 'getitems_copy') - - def length(self): - return n - - def getitem(self, index): - for i in iter_n: - if index == i: - return getattr(self,'w_value%s' % i) - raise IndexError - - def setitem(self, index, w_item): - for i in iter_n: - if index == i: - setattr(self, 'w_value%s' % i, w_item) - return - raise IndexError - - def eq(self, space, w_other): - if n != w_other.length(): - return space.w_False - for i in iter_n: - item1 = getattr(self,'w_value%s' % i) - item2 = w_other.getitem(i) - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - - def hash(self, space): - mult = 1000003 - x = 0x345678 - z = n - for i in iter_n: - w_item = getattr(self, 'w_value%s' % i) - y = space.int_w(space.hash(w_item)) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return space.wrap(intmask(x)) - - cls.__name__ = "W_SmallTupleObject%s" % n - return cls - -W_SmallTupleObject2 = make_specialized_class(2) -W_SmallTupleObject3 = make_specialized_class(3) -W_SmallTupleObject4 = make_specialized_class(4) -W_SmallTupleObject5 = make_specialized_class(5) -W_SmallTupleObject6 = make_specialized_class(6) -W_SmallTupleObject7 = make_specialized_class(7) -W_SmallTupleObject8 = make_specialized_class(8) - -registerimplementation(W_SmallTupleObject) - -def delegate_SmallTuple2Tuple(space, w_small): - return W_TupleObject(w_small.tolist()) - -def len__SmallTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SmallTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SmallTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_smalltuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SmallTuple_ANY(space, w_tuple, w_times): - return mul_smalltuple_times(space, w_tuple, w_times) - -def mul__ANY_SmallTuple(space, w_times, w_tuple): - return mul_smalltuple_times(space, w_tuple, w_times) - -def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def hash__SmallTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -1,63 +1,23 @@ from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.tupleobject import W_AbstractTupleObject -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.util import negate +from rpython.rlib.objectmodel import compute_hash from rpython.rlib.rarithmetic import intmask -from rpython.rlib.objectmodel import compute_hash from rpython.rlib.unroll import unrolling_iterable from rpython.tool.sourcetools import func_with_new_name + class NotSpecialised(Exception): pass -class W_SpecialisedTupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef - __slots__ = [] - - def __repr__(self): - """ representation for debugging purposes """ - reprlist = [repr(item) for item in self._to_unwrapped_list()] - return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) - - #def tolist(self): --- inherited from W_AbstractTupleObject - # raise NotImplementedError - - def _to_unwrapped_list(self): - "NOT_RPYTHON" - raise NotImplementedError - - def length(self): - raise NotImplementedError - - def getitem(self, index): - raise NotImplementedError - - def hash(self, space): - raise NotImplementedError - - def eq(self, space, w_other): - raise NotImplementedError - - def setitem(self, index, w_item): - raise NotImplementedError - - def unwrap(self, space): - return tuple(self._to_unwrapped_list()) - - def delegating(self): - pass # for tests only - def make_specialised_class(typetuple): assert type(typetuple) == tuple - + nValues = len(typetuple) iter_n = unrolling_iterable(range(nValues)) - - class cls(W_SpecialisedTupleObject): + + class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space assert len(values_w) == nValues @@ -80,7 +40,7 @@ return nValues def tolist(self): - list_w = [None] * nValues + list_w = [None] * nValues for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -91,18 +51,7 @@ # same source code, but builds and returns a resizable list getitems_copy = func_with_new_name(tolist, 'getitems_copy') - def _to_unwrapped_list(self): - "NOT_RPYTHON" - list_w = [None] * nValues - for i in iter_n: - value = getattr(self, 'value%s' % i) - if typetuple[i] == object: - value = self.space.unwrap(value) - list_w[i] = value - return list_w - - def hash(self, space): - # XXX duplicate logic from tupleobject.py + def descr_hash(self, space): mult = 1000003 x = 0x345678 z = nValues @@ -123,50 +72,45 @@ x += 97531 return space.wrap(intmask(x)) - def _eq(self, w_other): + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented if not isinstance(w_other, cls): - # if we are not comparing same types, give up - raise FailedToImplement + if nValues != w_other.length(): + return space.w_False + for i in iter_n: + myval = getattr(self, 'value%s' % i) + otherval = w_other.getitem(space, i) + if typetuple[i] != object: + myval = space.wrap(myval) + if not space.eq_w(myval, otherval): + return space.w_False + return space.w_True + for i in iter_n: - myval = getattr(self, 'value%s' % i) + myval = getattr(self, 'value%s' % i) otherval = getattr(w_other, 'value%s' % i) if typetuple[i] == object: if not self.space.eq_w(myval, otherval): - return False + return space.w_False else: if myval != otherval: - return False - else: - return True + return space.w_False + return space.w_True - def eq(self, space, w_other): - return space.newbool(self._eq(w_other)) + descr_ne = negate(descr_eq) - def ne(self, space, w_other): - return space.newbool(not self._eq(w_other)) - -## def _compare(self, compare_op, w_other): -## if not isinstance(w_other, cls): -## raise FailedToImplement -## ncmp = min(self.length(), w_other.length()) -## for i in iter_n: -## if typetuple[i] == Any:#like space.eq on wrapped or two params? -## raise FailedToImplement -## if ncmp > i: -## l_val = getattr(self, 'value%s' % i) -## r_val = getattr(w_other, 'value%s' % i) -## if l_val != r_val: -## return compare_op(l_val, r_val) -## return compare_op(self.length(), w_other.length()) - - def getitem(self, index): + def getitem(self, space, index): + if index < 0: + index += nValues for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) if typetuple[i] != object: - value = self.space.wrap(value) + value = space.wrap(value) return value - raise IndexError + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) cls.__name__ = ('W_SpecialisedTupleObject_' + ''.join([t.__name__[0] for t in typetuple])) @@ -177,129 +121,21 @@ _specialisations = [] Cls_ii = make_specialised_class((int, int)) -#Cls_is = make_specialised_class((int, str)) -#Cls_io = make_specialised_class((int, object)) -#Cls_si = make_specialised_class((str, int)) -#Cls_ss = make_specialised_class((str, str)) -#Cls_so = make_specialised_class((str, object)) -#Cls_oi = make_specialised_class((object, int)) -#Cls_os = make_specialised_class((object, str)) Cls_oo = make_specialised_class((object, object)) Cls_ff = make_specialised_class((float, float)) -#Cls_ooo = make_specialised_class((object, object, object)) def makespecialisedtuple(space, list_w): if len(list_w) == 2: w_arg1, w_arg2 = list_w w_type1 = space.type(w_arg1) - #w_type2 = space.type(w_arg2) - # if w_type1 is space.w_int: w_type2 = space.type(w_arg2) if w_type2 is space.w_int: return Cls_ii(space, w_arg1, w_arg2) - #elif w_type2 is space.w_str: - # return Cls_is(space, w_arg1, w_arg2) - #else: - # return Cls_io(space, w_arg1, w_arg2) - # - #elif w_type1 is space.w_str: - # if w_type2 is space.w_int: - # return Cls_si(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_ss(space, w_arg1, w_arg2) - # else: - # return Cls_so(space, w_arg1, w_arg2) - # elif w_type1 is space.w_float: w_type2 = space.type(w_arg2) if w_type2 is space.w_float: return Cls_ff(space, w_arg1, w_arg2) - # - #else: - # if w_type2 is space.w_int: - # return Cls_oi(space, w_arg1, w_arg2) - # elif w_type2 is space.w_str: - # return Cls_os(space, w_arg1, w_arg2) - # else: return Cls_oo(space, w_arg1, w_arg2) - # - #elif len(list_w) == 3: - # return Cls_ooo(space, list_w[0], list_w[1], list_w[2]) else: raise NotSpecialised - -# ____________________________________________________________ - -registerimplementation(W_SpecialisedTupleObject) - -def delegate_SpecialisedTuple2Tuple(space, w_specialised): - w_specialised.delegating() - return W_TupleObject(w_specialised.tolist()) - -def len__SpecialisedTuple(space, w_tuple): - return space.wrap(w_tuple.length()) - -def getitem__SpecialisedTuple_ANY(space, w_tuple, w_index): - index = space.getindex_w(w_index, space.w_IndexError, "tuple index") - if index < 0: - index += w_tuple.length() - try: - return w_tuple.getitem(index) - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) - -def getitem__SpecialisedTuple_Slice(space, w_tuple, w_slice): - length = w_tuple.length() - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = w_tuple.getitem(start) - start += step - return space.newtuple(subitems) - -def mul_specialisedtuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.tolist() - return space.newtuple(items * times) - -def mul__SpecialisedTuple_ANY(space, w_tuple, w_times): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def mul__ANY_SpecialisedTuple(space, w_times, w_tuple): - return mul_specialisedtuple_times(space, w_tuple, w_times) - -def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.eq(space, w_tuple2) - -def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): - return w_tuple1.ne(space, w_tuple2) - -##from operator import lt, le, ge, gt - -##def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(lt, w_tuple2)) - -##def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(le, w_tuple2)) - -##def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(ge, w_tuple2)) - -##def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): -## return space.newbool(w_tuple1._compare(gt, w_tuple2)) - -def hash__SpecialisedTuple(space, w_tuple): - return w_tuple.hash(space) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -12,7 +12,6 @@ from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stringtype import ( joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) -from pypy.objspace.std.tupleobject import W_TupleObject from rpython.rlib import jit from rpython.rlib.objectmodel import ( compute_hash, compute_unique_id, specialize) @@ -684,7 +683,9 @@ w_end, True) return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) -def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): +def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): + if not space.isinstance_w(w_suffixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): @@ -702,7 +703,9 @@ w_end, True) return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) -def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): +def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): + if not space.isinstance_w(w_prefixes, space.w_tuple): + raise FailedToImplement (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py deleted file mode 100644 --- a/pypy/objspace/std/test/test_smalltupleobject.py +++ /dev/null @@ -1,84 +0,0 @@ -from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject -from pypy.interpreter.error import OperationError -from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject -from pypy.tool.pytest.objspace import gettestobjspace - -class AppTestW_SmallTupleObject(AppTestW_TupleObject): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def setup_class(cls): - cls.w_issmall = cls.space.appexec([], """(): - import __pypy__ - def issmall(obj): - assert "SmallTuple" in __pypy__.internal_repr(obj) - return issmall - """) - - def test_smalltuple(self): - self.issmall((1,2)) - self.issmall((1,2,3)) - - def test_slicing_to_small(self): - self.issmall((1, 2, 3)[0:2]) # SmallTuple2 - self.issmall((1, 2, 3)[0:2:1]) - - self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3 - self.issmall((1, 2, 3, 4)[0:3:1]) - - def test_adding_to_small(self): - self.issmall((1,)+(2,)) # SmallTuple2 - self.issmall((1,1)+(2,)) # SmallTuple3 - self.issmall((1,)+(2,3)) - - def test_multiply_to_small(self): - self.issmall((1,)*2) - self.issmall((1,)*3) - - def test_slicing_from_small(self): - assert (1,2)[0:1:1] == (1,) - assert (1,2,3)[0:2:1] == (1,2) - - def test_eq(self): - a = (1,2,3) - b = (1,2,3) - assert a == b - - c = (1,3,2) - assert a != c - - def test_hash(self): - a = (1,2,3) - b = (1,2,3) - assert hash(a) == hash(b) - - c = (1,3,2) - assert hash(a) != hash(c) - -class TestW_SmallTupleObject(): - spaceconfig = {"objspace.std.withsmalltuple": True} - - def test_issmalltupleobject(self): - w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - assert isinstance(w_tuple, W_SmallTupleObject) - - def test_hash_agains_normal_tuple(self): - normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) - w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) - w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) - - assert isinstance(w_smalltuple, W_SmallTupleObject) - assert isinstance(w_tuple, W_TupleObject) - assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) - assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) - - def test_setitem(self): - w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) - w_smalltuple.setitem(0, self.space.wrap(5)) - list_w = w_smalltuple.tolist() - assert len(list_w) == 2 - assert self.space.eq_w(list_w[0], self.space.wrap(5)) - assert self.space.eq_w(list_w[1], self.space.wrap(2)) diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -1,11 +1,7 @@ -import py, sys +from pypy.objspace.std.specialisedtupleobject import _specialisations +from pypy.objspace.std.test import test_tupleobject from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject -from pypy.objspace.std.specialisedtupleobject import _specialisations -from pypy.interpreter.error import OperationError from pypy.tool.pytest.objspace import gettestobjspace -from pypy.objspace.std.test import test_tupleobject -from pypy.interpreter import gateway for cls in _specialisations: @@ -18,62 +14,43 @@ def test_isspecialisedtupleobjectintint(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert isinstance(w_tuple, W_SpecialisedTupleObject_ii) - + def test_isnotspecialisedtupleobject(self): w_tuple = self.space.newtuple([self.space.wrap({})]) - assert not isinstance(w_tuple, W_SpecialisedTupleObject) - + assert not 'W_SpecialisedTupleObject' in type(w_tuple).__name__ + def test_specialisedtupleclassname(self): w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii' def test_hash_against_normal_tuple(self): - N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": False}) - S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) - def hash_test(values, must_be_specialized=True): - N_values_w = [N_space.wrap(value) for value in values] - S_values_w = [S_space.wrap(value) for value in values] - N_w_tuple = N_space.newtuple(N_values_w) - S_w_tuple = S_space.newtuple(S_values_w) + N_values_w = [self.space.wrap(value) for value in values] + S_values_w = [self.space.wrap(value) for value in values] + N_w_tuple = W_TupleObject(N_values_w) + S_w_tuple = self.space.newtuple(S_values_w) if must_be_specialized: - assert isinstance(S_w_tuple, W_SpecialisedTupleObject) - assert isinstance(N_w_tuple, W_TupleObject) - assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) - assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) + assert 'W_SpecialisedTupleObject' in type(S_w_tuple).__name__ + assert self.space.is_true(self.space.eq(N_w_tuple, S_w_tuple)) + assert self.space.is_true( + self.space.eq(self.space.hash(N_w_tuple), + self.space.hash(S_w_tuple))) - hash_test([1,2]) - hash_test([1.5,2.8]) - hash_test([1.0,2.0]) - hash_test(['arbitrary','strings']) - hash_test([1,(1,2,3,4)]) - hash_test([1,(1,2)]) - hash_test([1,('a',2)]) - hash_test([1,()]) - hash_test([1,2,3], must_be_specialized=False) + hash_test([1, 2]) + hash_test([1.5, 2.8]) + hash_test([1.0, 2.0]) + hash_test(['arbitrary', 'strings']) + hash_test([1, (1, 2, 3, 4)]) + hash_test([1, (1, 2)]) + hash_test([1, ('a', 2)]) + hash_test([1, ()]) + hash_test([1, 2, 3], must_be_specialized=False) class AppTestW_SpecialisedTupleObject: spaceconfig = {"objspace.std.withspecialisedtuple": True} - def setup_class(cls): - def forbid_delegation(space, w_tuple): - def delegation_forbidden(): - # haaaack - co = sys._getframe(2).f_code - if co.co_name.startswith('_mm_repr_tuple'): - return - raise OperationError(space.w_ReferenceError, w_tuple) - w_tuple.delegating = delegation_forbidden - return w_tuple - if cls.runappdirect: - cls.w_forbid_delegation = lambda self, x: x - cls.test_delegation = lambda self: skip("runappdirect") - else: - cls.w_forbid_delegation = cls.space.wrap( - gateway.interp2app(forbid_delegation)) - def w_isspecialised(self, obj, expected=''): import __pypy__ r = __pypy__.internal_repr(obj) @@ -101,16 +78,12 @@ obj = (1, 2, 3) assert self.isspecialised(obj, '_ooo') - def test_delegation(self): - t = self.forbid_delegation((42, 43)) - raises(ReferenceError, t.__getslice__, 0, 1) - def test_len(self): - t = self.forbid_delegation((42,43)) + t = (42, 43) assert len(t) == 2 def test_notspecialisedtuple(self): - assert not self.isspecialised((42,43,44,45)) + assert not self.isspecialised((42, 43, 44, 45)) assert not self.isspecialised((1.5,)) def test_slicing_to_specialised(self): @@ -133,79 +106,79 @@ def test_eq_no_delegation(self): t = (1,) - a = self.forbid_delegation(t + (2,)) + a = t + (2,) b = (1, 2) assert a == b c = (2, 1) assert not a == c - def test_eq_can_delegate(self): - a = (1,2) - b = (1,3,2) + def test_eq_can_delegate(self): + a = (1, 2) + b = (1, 3, 2) assert not a == b values = [2, 2L, 2.0, 1, 1L, 1.0] for x in values: for y in values: - assert ((1,2) == (x,y)) == (1 == x and 2 == y) + assert ((1, 2) == (x, y)) == (1 == x and 2 == y) def test_neq(self): - a = self.forbid_delegation((1,2)) + a = (1, 2) b = (1,) - b = b+(2,) + b = b + (2,) assert not a != b - - c = (1,3) + + c = (1, 3) assert a != c - + def test_ordering(self): - a = (1,2) #self.forbid_delegation((1,2)) --- code commented out - assert a < (2,2) - assert a < (1,3) - assert not a < (1,2) + a = (1, 2) + assert a < (2, 2) + assert a < (1, 3) + assert not a < (1, 2) - assert a <= (2,2) - assert a <= (1,2) - assert not a <= (1,1) - - assert a >= (0,2) - assert a >= (1,2) - assert not a >= (1,3) - - assert a > (0,2) - assert a > (1,1) - assert not a > (1,3) + assert a <= (2, 2) + assert a <= (1, 2) + assert not a <= (1, 1) - assert (2,2) > a - assert (1,3) > a - assert not (1,2) > a - - assert (2,2) >= a - assert (1,2) >= a - assert not (1,1) >= a - - assert (0,2) <= a - assert (1,2) <= a - assert not (1,3) <= a - - assert (0,2) < a - assert (1,1) < a - assert not (1,3) < a + assert a >= (0, 2) + assert a >= (1, 2) + assert not a >= (1, 3) + + assert a > (0, 2) + assert a > (1, 1) + assert not a > (1, 3) + + assert (2, 2) > a + assert (1, 3) > a + assert not (1, 2) > a + + assert (2, 2) >= a + assert (1, 2) >= a + assert not (1, 1) >= a + + assert (0, 2) <= a + assert (1, 2) <= a + assert not (1, 3) <= a + + assert (0, 2) < a + assert (1, 1) < a + assert not (1, 3) < a def test_hash(self): - a = (1,2) + a = (1, 2) b = (1,) - b += (2,) # else a and b refer to same constant + b += (2,) # else a and b refer to same constant assert hash(a) == hash(b) - c = (2,4) + c = (2, 4) assert hash(a) != hash(c) assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L)) def test_getitem(self): - t = self.forbid_delegation((5,3)) + t = (5, 3) assert (t)[0] == 5 assert (t)[1] == 3 assert (t)[-1] == 3 @@ -216,14 +189,14 @@ def test_three_tuples(self): if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - b = self.forbid_delegation((1, 2, 3)) + b = (1, 2, 3) c = (1,) d = c + (2, 3) assert self.isspecialised(d) assert b == d def test_mongrel(self): - a = self.forbid_delegation((2.2, '333')) + a = (2.2, '333') assert self.isspecialised(a) assert len(a) == 2 assert a[0] == 2.2 and a[1] == '333' @@ -233,7 +206,7 @@ # if not self.isspecialised((1, 2, 3)): skip("don't have specialization for 3-tuples") - a = self.forbid_delegation((1, 2.2, '333')) + a = (1, 2.2, '333') assert self.isspecialised(a) assert len(a) == 3 assert a[0] == 1 and a[1] == 2.2 and a[2] == '333' @@ -243,4 +216,4 @@ class AppTestAll(test_tupleobject.AppTestW_TupleObject): - pass + spaceconfig = {"objspace.std.withspecialisedtuple": True} diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -1,17 +1,16 @@ -#from __future__ import nested_scopes +from pypy.interpreter.error import OperationError from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.interpreter.error import OperationError + class TestW_TupleObject: - def test_is_true(self): w = self.space.wrap w_tuple = W_TupleObject([]) - assert self.space.is_true(w_tuple) == False + assert self.space.is_true(w_tuple) is False w_tuple = W_TupleObject([w(5)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True w_tuple = W_TupleObject([w(5), w(3)]) - assert self.space.is_true(w_tuple) == True + assert self.space.is_true(w_tuple) is True def test_len(self): w = self.space.wrap @@ -19,7 +18,7 @@ assert self.space.eq_w(self.space.len(w_tuple), w(0)) w_tuple = W_TupleObject([w(5)]) assert self.space.eq_w(self.space.len(w_tuple), w(1)) - w_tuple = W_TupleObject([w(5), w(3), w(99)]*111) + w_tuple = W_TupleObject([w(5), w(3), w(99)] * 111) assert self.space.eq_w(self.space.len(w_tuple), w(333)) def test_getitem(self): @@ -65,7 +64,7 @@ w_tuple2 = W_TupleObject([w(-7)] * 111) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple1), W_TupleObject([w(5), w(3), w(99), - w(5), w(3), w(99)])) + w(5), w(3), w(99)])) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple2), W_TupleObject([w(5), w(3), w(99)] + [w(-7)] * 111)) assert self.space.eq_w(self.space.add(w_tuple1, w_tuple0), w_tuple1) @@ -77,7 +76,7 @@ arg = w(2) n = 3 w_tup = W_TupleObject([arg]) - w_tup3 = W_TupleObject([arg]*n) + w_tup3 = W_TupleObject([arg] * n) w_res = self.space.mul(w_tup, w(n)) assert self.space.eq_w(w_tup3, w_res) # commute @@ -91,26 +90,26 @@ w = self.space.wrap def test1(testtuple, start, stop, step, expected): - w_slice = self.space.newslice(w(start), w(stop), w(step)) + w_slice = self.space.newslice(w(start), w(stop), w(step)) w_tuple = W_TupleObject([w(i) for i in testtuple]) w_result = self.space.getitem(w_tuple, w_slice) assert self.space.unwrap(w_result) == expected - - for testtuple in [(), (5,3,99), tuple(range(5,555,10))]: + + for testtuple in [(), (5, 3, 99), tuple(range(5, 555, 10))]: for start in [-2, -1, 0, 1, 10]: for end in [-1, 0, 2, 999]: test1(testtuple, start, end, 1, testtuple[start:end]) - test1((5,7,1,4), 3, 1, -2, (4,)) - test1((5,7,1,4), 3, 0, -2, (4, 7)) - test1((5,7,1,4), 3, -1, -2, ()) - test1((5,7,1,4), -2, 11, 2, (1,)) - test1((5,7,1,4), -3, 11, 2, (7, 4)) - test1((5,7,1,4), -5, 11, 2, (5, 1)) + test1((5, 7, 1, 4), 3, 1, -2, (4,)) + test1((5, 7, 1, 4), 3, 0, -2, (4, 7)) + test1((5, 7, 1, 4), 3, -1, -2, ()) + test1((5, 7, 1, 4), -2, 11, 2, (1,)) + test1((5, 7, 1, 4), -3, 11, 2, (7, 4)) + test1((5, 7, 1, 4), -5, 11, 2, (5, 1)) def test_eq(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -126,9 +125,10 @@ self.space.w_True) assert self.space.eq_w(self.space.eq(w_tuple2, w_tuple3), self.space.w_False) + def test_ne(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -144,9 +144,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ne(w_tuple2, w_tuple3), self.space.w_True) + def test_lt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -165,10 +166,10 @@ self.space.w_True) assert self.space.eq_w(self.space.lt(w_tuple4, w_tuple3), self.space.w_True) - + def test_ge(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -187,10 +188,10 @@ self.space.w_False) assert self.space.eq_w(self.space.ge(w_tuple4, w_tuple3), self.space.w_False) - + def test_gt(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -209,10 +210,10 @@ self.space.w_False) assert self.space.eq_w(self.space.gt(w_tuple4, w_tuple3), self.space.w_False) - + def test_le(self): w = self.space.wrap - + w_tuple0 = W_TupleObject([]) w_tuple1 = W_TupleObject([w(5), w(3), w(99)]) w_tuple2 = W_TupleObject([w(5), w(3), w(99)]) @@ -234,28 +235,27 @@ class AppTestW_TupleObject: - def test_is_true(self): assert not () assert (5,) - assert (5,3) + assert (5, 3) def test_len(self): assert len(()) == 0 assert len((5,)) == 1 - assert len((5,3,99,1,2,3,4,5,6)) == 9 + assert len((5, 3, 99, 1, 2, 3, 4, 5, 6)) == 9 def test_getitem(self): - assert (5,3)[0] == 5 - assert (5,3)[1] == 3 - assert (5,3)[-1] == 3 - assert (5,3)[-2] == 5 - raises(IndexError, "(5,3)[2]") + assert (5, 3)[0] == 5 + assert (5, 3)[1] == 3 + assert (5, 3)[-1] == 3 + assert (5, 3)[-2] == 5 + raises(IndexError, "(5, 3)[2]") raises(IndexError, "(5,)[1]") raises(IndexError, "()[0]") def test_iter(self): - t = (5,3,99) + t = (5, 3, 99) i = iter(t) assert i.next() == 5 assert i.next() == 3 @@ -263,7 +263,7 @@ raises(StopIteration, i.next) def test_contains(self): - t = (5,3,99) + t = (5, 3, 99) assert 5 in t assert 99 in t assert not 11 in t @@ -271,35 +271,35 @@ def test_add(self): t0 = () - t1 = (5,3,99) + t1 = (5, 3, 99) assert t0 + t0 == t0 assert t1 + t0 == t1 - assert t1 + t1 == (5,3,99,5,3,99) + assert t1 + t1 == (5, 3, 99, 5, 3, 99) def test_mul(self): assert () * 10 == () - assert (5,) * 3 == (5,5,5) - assert (5,2) * 2 == (5,2,5,2) + assert (5,) * 3 == (5, 5, 5) + assert (5, 2) * 2 == (5, 2, 5, 2) def test_mul_identity(self): - t = (1,2,3) + t = (1, 2, 3) assert (t * 1) is t def test_mul_subtype(self): class T(tuple): pass - t = T([1,2,3]) + t = T([1, 2, 3]) assert (t * 1) is not t assert (t * 1) == t def test_getslice_2(self): - assert (5,2,3)[1:2] == (2,) + assert (5, 2, 3)[1:2] == (2,) def test_eq(self): t0 = () - t1 = (5,3,99) - t2 = (5,3,99) - t3 = (5,3,99,-1) - t4 = (5,3,9,1) + t1 = (5, 3, 99) + t2 = (5, 3, 99) + t3 = (5, 3, 99, -1) + t4 = (5, 3, 9, 1) assert not t0 == t1 assert t0 != t1 assert t1 == t2 @@ -321,15 +321,15 @@ # check that hash behaves as in 2.4 for at least 31 bits assert hash(()) & 0x7fffffff == 0x35d373 assert hash((12,)) & 0x7fffffff == 0x1cca0557 - assert hash((12,34)) & 0x7fffffff == 0x153e2a41 + assert hash((12, 34)) & 0x7fffffff == 0x153e2a41 def test_getnewargs(self): - assert () .__getnewargs__() == ((),) + assert () .__getnewargs__() == ((),) def test_repr(self): assert repr((1,)) == '(1,)' assert repr(()) == '()' - assert repr((1,2,3)) == '(1, 2, 3)' + assert repr((1, 2, 3)) == '(1, 2, 3)' def test_getslice(self): assert ('a', 'b', 'c').__getslice__(-17, 2) == ('a', 'b') @@ -399,3 +399,11 @@ assert ((5,) != (N,)) is True assert ((5,) > (N,)) is False assert ((5,) >= (N,)) is False + + def test_eq_other_type(self): + assert (() == object()) is False + assert ((1,) == object()) is False + assert ((1, 2) == object()) is False + assert (() != object()) is True + assert ((1,) != object()) is True + assert ((1, 2) != object()) is True diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,212 +1,297 @@ +import sys +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate +from rpython.rlib import jit +from rpython.rlib.debug import make_sure_not_resized from rpython.rlib.rarithmetic import intmask -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from rpython.rlib.debug import make_sure_not_resized -from rpython.rlib import jit -from rpython.tool.sourcetools import func_with_new_name + UNROLL_CUTOFF = 10 -class W_AbstractTupleObject(W_Object): + +def _unroll_condition(self): + return jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) + + +def _unroll_condition_cmp(self, space, other): + return (jit.loop_unrolling_heuristic(self, self.length(), UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF)) + + +class W_AbstractTupleObject(W_Root): __slots__ = () + def __repr__(self): + """representation for debugging purposes""" + reprlist = [repr(w_item) for w_item in self.tolist()] + return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) + + def unwrap(self, space): + items = [space.unwrap(w_item) for w_item in self.tolist()] + return tuple(items) + def tolist(self): - "Returns the items, as a fixed-size list." + """Returns the items, as a fixed-size list.""" raise NotImplementedError def getitems_copy(self): - "Returns a copy of the items, as a resizable list." + """Returns a copy of the items, as a resizable list.""" raise NotImplementedError + def length(self): + raise NotImplementedError + + def getitem(self, space, item): + raise NotImplementedError + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + + def descr_iter(self, space): + from pypy.objspace.std import iterobject + return iterobject.W_FastTupleIterObject(self, self.tolist()) + + @staticmethod + def descr_new(space, w_tupletype, w_sequence=None): + if w_sequence is None: + tuple_w = [] + elif (space.is_w(w_tupletype, space.w_tuple) and + space.is_w(space.type(w_sequence), space.w_tuple)): + return w_sequence + else: + tuple_w = space.fixedview(w_sequence) + w_obj = space.allocate_instance(W_TupleObject, w_tupletype) + W_TupleObject.__init__(w_obj, tuple_w) + return w_obj + + def descr_repr(self, space): + items = self.tolist() + if len(items) == 1: + return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") + tmp = ", ".join([space.str_w(space.repr(item)) for item in items]) + return space.wrap("(" + tmp + ")") + + def descr_hash(self, space): + raise NotImplementedError + + def descr_eq(self, space, w_other): + raise NotImplementedError + + def descr_ne(self, space, w_other): + raise NotImplementedError + + def _make_tuple_comparison(name): + import operator + op = getattr(operator, name) + + def compare_tuples(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return _compare_tuples(self, space, w_other) + + @jit.look_inside_iff(_unroll_condition_cmp) + def _compare_tuples(self, space, w_other): + items1 = self.tolist() + items2 = w_other.tolist() + ncmp = min(len(items1), len(items2)) + # Search for the first index where items are different + for p in range(ncmp): + if not space.eq_w(items1[p], items2[p]): + return getattr(space, name)(items1[p], items2[p]) + # No more items to compare -- compare sizes + return space.newbool(op(len(items1), len(items2))) + + compare_tuples.__name__ = 'descr_' + name + return compare_tuples + + descr_lt = _make_tuple_comparison('lt') + descr_le = _make_tuple_comparison('le') + descr_gt = _make_tuple_comparison('gt') + descr_ge = _make_tuple_comparison('ge') + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_contains(self, space, w_obj): + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + return space.w_True + return space.w_False + + def descr_add(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + items1 = self.tolist() + items2 = w_other.tolist() + return space.newtuple(items1 + items2) + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + if times == 1 and space.type(self) == space.w_tuple: + return self + items = self.tolist() + return space.newtuple(items * times) + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + return self._getslice(space, w_index) + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") + return self.getitem(space, index) + + def _getslice(self, space, w_index): + items = self.tolist() + length = len(items) + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = items[start] + start += step + return space.newtuple(subitems) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + return space.newtuple(self.tolist()[start:stop]) + + def descr_getnewargs(self, space): + return space.newtuple([space.newtuple(self.tolist())]) + + @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self)) + def descr_count(self, space, w_obj): + """count(obj) -> number of times obj appears in the tuple""" + count = 0 + for w_item in self.tolist(): + if space.eq_w(w_item, w_obj): + count += 1 + return space.wrap(count) + + @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), + w_stop=gateway.WrappedDefault(sys.maxint)) + @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) + def descr_index(self, space, w_obj, w_start, w_stop): + """index(obj, [start, [stop]]) -> first index that obj appears in the + tuple + """ + length = self.length() + start, stop = slicetype.unwrap_start_stop(space, length, w_start, + w_stop) + for i in range(start, min(stop, length)): + w_item = self.tolist()[i] + if space.eq_w(w_item, w_obj): + return space.wrap(i) + raise OperationError(space.w_ValueError, + space.wrap("tuple.index(x): x not in tuple")) + +W_AbstractTupleObject.typedef = StdTypeDef( + "tuple", + __doc__ = '''tuple() -> an empty tuple +tuple(sequence) -> tuple initialized from sequence's items + +If the argument is a tuple, the return value is the same object.''', + __new__ = interp2app(W_AbstractTupleObject.descr_new), + __repr__ = interp2app(W_AbstractTupleObject.descr_repr), + __hash__ = interpindirect2app(W_AbstractTupleObject.descr_hash), + + __eq__ = interpindirect2app(W_AbstractTupleObject.descr_eq), + __ne__ = interpindirect2app(W_AbstractTupleObject.descr_ne), + __lt__ = interp2app(W_AbstractTupleObject.descr_lt), + __le__ = interp2app(W_AbstractTupleObject.descr_le), + __gt__ = interp2app(W_AbstractTupleObject.descr_gt), + __ge__ = interp2app(W_AbstractTupleObject.descr_ge), + + __len__ = interp2app(W_AbstractTupleObject.descr_len), + __iter__ = interp2app(W_AbstractTupleObject.descr_iter), + __contains__ = interp2app(W_AbstractTupleObject.descr_contains), + + __add__ = interp2app(W_AbstractTupleObject.descr_add), + __mul__ = interp2app(W_AbstractTupleObject.descr_mul), + __rmul__ = interp2app(W_AbstractTupleObject.descr_mul), + + __getitem__ = interp2app(W_AbstractTupleObject.descr_getitem), + __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice), + + __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs), + count = interp2app(W_AbstractTupleObject.descr_count), + index = interp2app(W_AbstractTupleObject.descr_index) +) + class W_TupleObject(W_AbstractTupleObject): - from pypy.objspace.std.tupletype import tuple_typedef as typedef _immutable_fields_ = ['wrappeditems[*]'] - def __init__(w_self, wrappeditems): + def __init__(self, wrappeditems): make_sure_not_resized(wrappeditems) - w_self.wrappeditems = wrappeditems # a list of wrapped values - - def __repr__(w_self): - """ representation for debugging purposes """ - reprlist = [repr(w_item) for w_item in w_self.wrappeditems] - return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist)) - - def unwrap(w_tuple, space): - items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] - return tuple(items) + self.wrappeditems = wrappeditems def tolist(self): return self.wrappeditems def getitems_copy(self): - return self.wrappeditems[:] # returns a resizable list + return self.wrappeditems[:] # returns a resizable list -registerimplementation(W_TupleObject) + def length(self): + return len(self.wrappeditems) + @jit.look_inside_iff(lambda self, _1: _unroll_condition(self)) + def descr_hash(self, space): + mult = 1000003 + x = 0x345678 + z = len(self.wrappeditems) + for w_item in self.wrappeditems: + y = space.hash_w(w_item) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) -def len__Tuple(space, w_tuple): - result = len(w_tuple.wrappeditems) - return wrapint(space, result) + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_AbstractTupleObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) -def getitem__Tuple_ANY(space, w_tuple, w_index): - # getindex_w should get a second argument space.w_IndexError, - # but that doesn't exist the first time this is called. - try: - w_IndexError = space.w_IndexError - except AttributeError: - w_IndexError = None - index = space.getindex_w(w_index, w_IndexError, "tuple index") - try: - return w_tuple.wrappeditems[index] - except IndexError: - raise OperationError(space.w_IndexError, - space.wrap("tuple index out of range")) + @jit.look_inside_iff(_unroll_condition_cmp) + def _descr_eq(self, space, w_other): + items1 = self.wrappeditems + items2 = w_other.tolist() + lgt1 = len(items1) + lgt2 = len(items2) + if lgt1 != lgt2: + return space.w_False + for i in range(lgt1): + item1 = items1[i] + item2 = items2[i] + if not space.eq_w(item1, item2): + return space.w_False + return space.w_True -def getitem__Tuple_Slice(space, w_tuple, w_slice): - items = w_tuple.wrappeditems - length = len(items) - start, stop, step, slicelength = w_slice.indices4(space, length) - assert slicelength >= 0 - subitems = [None] * slicelength - for i in range(slicelength): - subitems[i] = items[start] - start += step - return space.newtuple(subitems) + descr_ne = negate(descr_eq) -def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return space.newtuple(w_tuple.wrappeditems[start:stop]) + def getitem(self, space, index): + try: + return self.wrappeditems[index] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) - at jit.look_inside_iff(lambda space, w_tuple, w_obj: - jit.loop_unrolling_heuristic(w_tuple, len(w_tuple.wrappeditems), UNROLL_CUTOFF)) -def contains__Tuple_ANY(space, w_tuple, w_obj): - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - return space.w_True - return space.w_False -def iter__Tuple(space, w_tuple): - from pypy.objspace.std import iterobject - return iterobject.W_FastTupleIterObject(w_tuple, w_tuple.wrappeditems) - -def add__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - return space.newtuple(items1 + items2) - -def mul_tuple_times(space, w_tuple, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times == 1 and space.type(w_tuple) == space.w_tuple: - return w_tuple - items = w_tuple.wrappeditems - return space.newtuple(items * times) - -def mul__Tuple_ANY(space, w_tuple, w_times): - return mul_tuple_times(space, w_tuple, w_times) - -def mul__ANY_Tuple(space, w_times, w_tuple): - return mul_tuple_times(space, w_tuple, w_times) - -def tuple_unroll_condition(space, w_tuple1, w_tuple2): - return jit.loop_unrolling_heuristic(w_tuple1, len(w_tuple1.wrappeditems), UNROLL_CUTOFF) or \ - jit.loop_unrolling_heuristic(w_tuple2, len(w_tuple2.wrappeditems), UNROLL_CUTOFF) - - at jit.look_inside_iff(tuple_unroll_condition) -def eq__Tuple_Tuple(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - lgt1 = len(items1) - lgt2 = len(items2) - if lgt1 != lgt2: - return space.w_False - for i in range(lgt1): - item1 = items1[i] - item2 = items2[i] - if not space.eq_w(item1, item2): - return space.w_False - return space.w_True - -def _make_tuple_comparison(name): - import operator - op = getattr(operator, name) - - @jit.look_inside_iff(tuple_unroll_condition) - def compare_tuples(space, w_tuple1, w_tuple2): - items1 = w_tuple1.wrappeditems - items2 = w_tuple2.wrappeditems - ncmp = min(len(items1), len(items2)) - # Search for the first index where items are different - for p in range(ncmp): - if not space.eq_w(items1[p], items2[p]): - return getattr(space, name)(items1[p], items2[p]) - # No more items to compare -- compare sizes - return space.newbool(op(len(items1), len(items2))) - return func_with_new_name(compare_tuples, name + '__Tuple_Tuple') - -lt__Tuple_Tuple = _make_tuple_comparison('lt') -le__Tuple_Tuple = _make_tuple_comparison('le') -gt__Tuple_Tuple = _make_tuple_comparison('gt') -ge__Tuple_Tuple = _make_tuple_comparison('ge') - -def repr__Tuple(space, w_tuple): - items = w_tuple.wrappeditems - # XXX this is quite innefficient, still better than calling - # it via applevel - if len(items) == 1: - return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") - return space.wrap("(" + - (", ".join([space.str_w(space.repr(item)) for item in items])) - + ")") - -def hash__Tuple(space, w_tuple): - return space.wrap(hash_tuple(space, w_tuple.wrappeditems)) - - at jit.look_inside_iff(lambda space, wrappeditems: - jit.loop_unrolling_heuristic(wrappeditems, len(wrappeditems), UNROLL_CUTOFF)) -def hash_tuple(space, wrappeditems): - # this is the CPython 2.4 algorithm (changed from 2.3) - mult = 1000003 - x = 0x345678 - z = len(wrappeditems) - for w_item in wrappeditems: - y = space.hash_w(w_item) - x = (x ^ y) * mult - z -= 1 - mult += 82520 + z + z - x += 97531 - return intmask(x) - -def getnewargs__Tuple(space, w_tuple): - return space.newtuple([space.newtuple(w_tuple.wrappeditems)]) - -def tuple_count__Tuple_ANY(space, w_tuple, w_obj): - count = 0 - for w_item in w_tuple.wrappeditems: - if space.eq_w(w_item, w_obj): - count += 1 - return space.wrap(count) - -def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - length = len(w_tuple.wrappeditems) - start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) - for i in range(start, min(stop, length)): - w_item = w_tuple.wrappeditems[i] - if space.eq_w(w_item, w_obj): - return space.wrap(i) - raise OperationError(space.w_ValueError, - space.wrap("tuple.index(x): x not in tuple")) - -from pypy.objspace.std import tupletype -register_all(vars(), tupletype) +def wraptuple(space, list_w): + if space.config.objspace.std.withspecialisedtuple: + from specialisedtupleobject import makespecialisedtuple, NotSpecialised + try: + return makespecialisedtuple(space, list_w) + except NotSpecialised: + pass + return W_TupleObject(list_w) diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py deleted file mode 100644 --- a/pypy/objspace/std/tupletype.py +++ /dev/null @@ -1,70 +0,0 @@ -import sys -from pypy.interpreter import gateway -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -def wraptuple(space, list_w): - from pypy.objspace.std.tupleobject import W_TupleObject - - if space.config.objspace.std.withspecialisedtuple: - from specialisedtupleobject import makespecialisedtuple, NotSpecialised - try: - return makespecialisedtuple(space, list_w) - except NotSpecialised: - pass - - if space.config.objspace.std.withsmalltuple: - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 - from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 - if len(list_w) == 2: - return W_SmallTupleObject2(list_w) - if len(list_w) == 3: - return W_SmallTupleObject3(list_w) - if len(list_w) == 4: - return W_SmallTupleObject4(list_w) - if len(list_w) == 5: - return W_SmallTupleObject5(list_w) - if len(list_w) == 6: - return W_SmallTupleObject6(list_w) - if len(list_w) == 7: - return W_SmallTupleObject7(list_w) - if len(list_w) == 8: - return W_SmallTupleObject8(list_w) - return W_TupleObject(list_w) - -tuple_count = SMM("count", 2, - doc="count(obj) -> number of times obj appears in the tuple") - -tuple_index = SMM("index", 4, defaults=(0, sys.maxint), - doc="index(obj, [start, [stop]]) -> first index that obj " - "appears in the tuple") - - -def descr__new__(space, w_tupletype, w_sequence=None): - from pypy.objspace.std.tupleobject import W_TupleObject - if w_sequence is None: - tuple_w = [] - elif (space.is_w(w_tupletype, space.w_tuple) and - space.is_w(space.type(w_sequence), space.w_tuple)): - return w_sequence - else: - tuple_w = space.fixedview(w_sequence) - w_obj = space.allocate_instance(W_TupleObject, w_tupletype) - W_TupleObject.__init__(w_obj, tuple_w) - return w_obj - -# ____________________________________________________________ - -tuple_typedef = StdTypeDef("tuple", - __doc__ = '''tuple() -> an empty tuple -tuple(sequence) -> tuple initialized from sequence's items - -If the argument is a tuple, the return value is the same object.''', - __new__ = gateway.interp2app(descr__new__), - ) -tuple_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -12,7 +12,6 @@ W_StringObject, make_rsplit_with_delim) from pypy.objspace.std.stringtype import stringendswith, stringstartswith From noreply at buildbot.pypy.org Wed May 22 22:16:04 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 22:16:04 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Unskip test_fastpath_isinstance() again. Message-ID: <20130522201604.1DFD11C331D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64479:3adc7b42e56a Date: 2013-05-22 22:01 +0200 http://bitbucket.org/pypy/pypy/changeset/3adc7b42e56a/ Log: Unskip test_fastpath_isinstance() again. diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -19,6 +19,7 @@ from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.iterobject import W_AbstractSeqIterObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.longobject import W_LongObject, newlong from pypy.objspace.std.noneobject import W_NoneObject @@ -668,6 +669,8 @@ self._interplevel_classes[self.w_list] = W_ListObject self._interplevel_classes[self.w_set] = W_SetObject self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + self._interplevel_classes[self.w_sequenceiterator] = \ + W_AbstractSeqIterObject @specialize.memo() def _get_interplevel_cls(self, w_type): diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py --- a/pypy/objspace/std/test/test_stdobjspace.py +++ b/pypy/objspace/std/test/test_stdobjspace.py @@ -37,7 +37,6 @@ assert space.sliceindices(w_obj, w(3)) == (1,2,3) def test_fastpath_isinstance(self): - py.test.skip("skipped until SMMs are removed") from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.iterobject import W_AbstractSeqIterObject From noreply at buildbot.pypy.org Wed May 22 22:16:06 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 22:16:06 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Remove commented out code. Message-ID: <20130522201606.016651C331E@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64480:cc3baea7040d Date: 2013-05-22 22:07 +0200 http://bitbucket.org/pypy/pypy/changeset/cc3baea7040d/ Log: Remove commented out code. diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -33,11 +33,6 @@ XXX to do: remove this __reduce__ method and do a registration with copy_reg, instead. """ - - # cpython does not support pickling iterators but stackless python do - #msg = 'Pickling for iterators dissabled as cpython does not support it' - #raise OperationError(space.w_TypeError, space.wrap(msg)) - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject assert isinstance(self, W_AbstractSeqIterObject) from pypy.interpreter.mixedmodule import MixedModule From noreply at buildbot.pypy.org Wed May 22 22:16:02 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 22:16:02 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: hg merge default Message-ID: <20130522201602.A0E2C1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64478:b1e0c5ec2b32 Date: 2013-05-22 21:56 +0200 http://bitbucket.org/pypy/pypy/changeset/b1e0c5ec2b32/ Log: hg merge default 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 @@ -7,7 +7,7 @@ appleveldefs = { } interpleveldefs = { - '__version__': 'space.wrap("0.6")', + '__version__': 'space.wrap("0.7")', 'load_library': 'libraryobj.load_library', @@ -30,6 +30,8 @@ 'typeoffsetof': 'func.typeoffsetof', 'rawaddressof': 'func.rawaddressof', 'getcname': 'func.getcname', + 'newp_handle': 'handle.newp_handle', + 'from_handle': 'handle.from_handle', '_get_types': 'func._get_types', 'string': 'func.string', diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -394,6 +394,19 @@ return self.length +class W_CDataHandle(W_CData): + _attrs_ = ['w_keepalive'] + _immutable_fields_ = ['w_keepalive'] + + def __init__(self, space, cdata, ctype, w_keepalive): + W_CData.__init__(self, space, cdata, ctype) + self.w_keepalive = w_keepalive + + def _repr_extra(self): + w_repr = self.space.repr(self.w_keepalive) + return "handle to %s" % (self.space.str_w(w_repr),) + + W_CData.typedef = TypeDef( 'CData', __module__ = '_cffi_backend', 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 @@ -172,8 +172,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = ['is_file', 'cache_array_type'] - _immutable_fields_ = ['is_file', 'cache_array_type?'] + _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr'] + _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr'] kind = "pointer" cache_array_type = None @@ -186,6 +186,7 @@ extra = " *" self.is_file = (ctitem.name == "struct _IO_FILE" or ctitem.name == "struct $FILE") + self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid) W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/handle.py @@ -0,0 +1,93 @@ +import weakref +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import unwrap_spec +from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj +from pypy.module._weakref.interp__weakref import dead_ref +from rpython.rtyper.lltypesystem import lltype, rffi + + +def reduced_value(s): + while True: + divide = s & 1 + s >>= 1 + if not divide: + return s + +# ____________________________________________________________ + + +class CffiHandles: + def __init__(self, space): + self.handles = [] + self.look_distance = 0 + + def reserve_next_handle_index(self): + # The reservation ordering done here is tweaked for pypy's + # memory allocator. We look from index 'look_distance'. + # Look_distance increases from 0. But we also look at + # "look_distance/2" or "/4" or "/8", etc. If we find that one + # of these secondary locations is free, we assume it's because + # there was recently a minor collection; so we reset + # look_distance to 0 and start again from the lowest locations. + length = len(self.handles) + for d in range(self.look_distance, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + s = reduced_value(d) + if self.handles[s]() is None: + break + # restart from the beginning + for d in range(0, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + # full! extend, but don't use '!=' here + self.handles = self.handles + [dead_ref] * (length // 3 + 5) + self.look_distance = length + 1 + return length + + def store_handle(self, index, content): + self.handles[index] = weakref.ref(content) + + def fetch_handle(self, index): + if 0 <= index < len(self.handles): + return self.handles[index]() + return None + +def get(space): + return space.fromcache(CffiHandles) + +# ____________________________________________________________ + + at unwrap_spec(w_ctype=ctypeobj.W_CType) +def newp_handle(space, w_ctype, w_x): + if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or + not w_ctype.is_void_ptr): + raise operationerrfmt(space.w_TypeError, + "needs 'void *', got '%s'", w_ctype.name) + index = get(space).reserve_next_handle_index() + _cdata = rffi.cast(rffi.CCHARP, index + 1) + new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x) + get(space).store_handle(index, new_cdataobj) + return new_cdataobj + + at 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): + raise operationerrfmt(space.w_TypeError, + "expected a 'cdata' object with a 'void *' out " + "of new_handle(), got '%s'", ctype.name) + index = rffi.cast(lltype.Signed, w_cdata._cdata) + original_cdataobj = get(space).fetch_handle(index - 1) + # + if isinstance(original_cdataobj, cdataobj.W_CDataHandle): + return original_cdataobj.w_keepalive + else: + if index == 0: + msg = "cannot use from_handle() on NULL pointer" + else: + msg = "'void *' value does not correspond to any object" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) 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 @@ -2732,6 +2732,32 @@ assert x != cast(BIntP, 12344) assert hash(x) == hash(cast(BIntP, 12345)) +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + + def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.6" + assert __version__ == "0.7" diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/test/test_handle.py @@ -0,0 +1,59 @@ +import random +from pypy.module._cffi_backend.handle import CffiHandles, reduced_value + + +def test_reduced_value(): + assert reduced_value(0) == 0 + assert reduced_value(1) == 0 + assert reduced_value(2) == 1 + assert reduced_value(3) == 0 + assert reduced_value(4) == 2 + assert reduced_value(5) == 1 + assert reduced_value(6) == 3 + assert reduced_value(7) == 0 + assert reduced_value(8) == 4 + assert reduced_value(9) == 2 + assert reduced_value(10) == 5 + assert reduced_value(11) == 1 + + +class PseudoWeakRef(object): + _content = 42 + + def __call__(self): + return self._content + + +def test_cffi_handles_1(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + assert len(ch.handles) < 13500 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr + +def test_cffi_handles_2(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + # + if len(expected_content) > 20: + r = random.choice(list(expected_content)) + pwr = expected_content.pop(r) + pwr._content = None + # + assert len(ch.handles) < 100 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -70,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: @@ -324,6 +324,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): @@ -356,13 +357,13 @@ self.strides = strides self.backstrides = backstrides self.shape = shape + if dtype is None: + dtype = parent.dtype if isinstance(parent, SliceArray): parent = parent.parent # one level only self.parent = parent self.storage = parent.storage self.order = parent.order - if dtype is None: - dtype = parent.dtype self.dtype = dtype self.size = support.product(shape) * self.dtype.itemtype.get_element_size() self.start = start diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,14 +268,30 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) @@ -373,7 +389,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,12 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -78,7 +84,8 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) @@ -111,8 +118,15 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -279,15 +293,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -333,10 +354,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +390,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +428,8 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,7 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) @@ -726,7 +726,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -781,6 +781,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -793,6 +794,27 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2699,6 +2701,56 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array, zeros + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) + + def test_multidim_subarray(self): + from numpypy import dtype, array + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1684,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1696,10 +1699,68 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + items_w = space.fixedview(w_items) + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if space.len_w(shape) <= 1: + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + for w_item in items_w: + self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) + ofs += size + return arr + + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + # TODO: Make sure the shape and the array match + items_w = space.fixedview(w_items) + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if len(shape) <= 1: + for i in range(len(items_w)): + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + for w_item in items_w: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + self._coerce(space, arr, ofs, dtype, w_item, shape[1:]) + ofs += size + + def coerce(self, space, dtype, w_items): + arr = VoidBoxStorage(self.size, dtype) + self._coerce(space, arr, 0, dtype, w_items, dtype.shape) + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + + def readarray(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, + dtype.shape, arr, W_NDimArray(arr), dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1733,7 +1794,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -74,7 +74,7 @@ def descr_eq(self, space, w_other): if not isinstance(w_other, W_AbstractTupleObject): - return space.w_NotImplementedError + return space.w_NotImplemented if not isinstance(w_other, cls): if nValues != w_other.length(): return space.w_False diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -216,4 +216,4 @@ class AppTestAll(test_tupleobject.AppTestW_TupleObject): - pass + spaceconfig = {"objspace.std.withspecialisedtuple": True} diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -399,3 +399,11 @@ assert ((5,) != (N,)) is True assert ((5,) > (N,)) is False assert ((5,) >= (N,)) is False + + def test_eq_other_type(self): + assert (() == object()) is False + assert ((1,) == object()) is False + assert ((1, 2) == object()) is False + assert (() != object()) is True + assert ((1,) != object()) is True + assert ((1, 2) != object()) is True diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -621,7 +621,8 @@ tobox = self.metainterp.heapcache.getfield(box, fielddescr) if tobox is valuebox: return - self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) + if tobox is not None or not self.metainterp.heapcache.is_unescaped(box) or not isinstance(valuebox, Const) or valuebox.nonnull(): + self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox) self.metainterp.heapcache.setfield(box, valuebox, fielddescr) opimpl_setfield_gc_i = _opimpl_setfield_gc_any opimpl_setfield_gc_r = _opimpl_setfield_gc_any diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -645,3 +645,20 @@ res = self.interp_operations(fn, [1]) assert res == -1 self.check_operations_history(guard_class=0) + + def test_dont_record_setfield_gc_zeros(self): + class A(object): + pass + + def make_a(): + return A() + make_a._dont_inline_ = True + + def fn(n): + a = make_a() + a.x = jit.promote(n) + return a.x + + res = self.interp_operations(fn, [0]) + assert res == 0 + self.check_operations_history(setfield_gc=0) From noreply at buildbot.pypy.org Wed May 22 22:16:07 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 22:16:07 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: style fixes Message-ID: <20130522201607.3B3871C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64481:83395d86dbc0 Date: 2013-05-22 22:10 +0200 http://bitbucket.org/pypy/pypy/changeset/83395d86dbc0/ Log: style fixes diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -36,10 +36,10 @@ from pypy.objspace.std.iterobject import W_AbstractSeqIterObject assert isinstance(self, W_AbstractSeqIterObject) from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('seqiter_new') - tup = [self.w_seq, space.wrap(self.index)] + tup = [self.w_seq, space.wrap(self.index)] return space.newtuple([new_inst, space.newtuple(tup)]) def descr_length_hint(self, space): @@ -47,7 +47,8 @@ assert isinstance(self, W_AbstractSeqIterObject) return self.getlength(space) -W_AbstractSeqIterObject.typedef = StdTypeDef("sequenceiterator", +W_AbstractSeqIterObject.typedef = StdTypeDef( + "sequenceiterator", __doc__ = '''iter(collection) -> iterator iter(callable, sentinel) -> iterator @@ -58,8 +59,9 @@ __iter__ = gateway.interp2app(W_AbstractSeqIterObject.descr_iter), next = gateway.interpindirect2app(W_AbstractSeqIterObject.descr_next), __reduce__ = gateway.interp2app(W_AbstractSeqIterObject.descr_reduce), - __length_hint__ = gateway.interp2app(W_AbstractSeqIterObject.descr_length_hint), - ) + __length_hint__ = gateway.interp2app( + W_AbstractSeqIterObject.descr_length_hint), +) W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False @@ -80,7 +82,7 @@ return w_item -class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed +class W_FastListIterObject(W_AbstractSeqIterObject): """Sequence iterator specialized for lists.""" def descr_next(self, space): @@ -135,10 +137,10 @@ from pypy.objspace.std.iterobject import W_ReverseSeqIterObject assert isinstance(self, W_ReverseSeqIterObject) from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('reverseseqiter_new') - tup = [self.w_seq, space.wrap(self.index)] + tup = [self.w_seq, space.wrap(self.index)] return space.newtuple([new_inst, space.newtuple(tup)]) def descr_length_hint(self, space): @@ -174,10 +176,12 @@ raise OperationError(space.w_StopIteration, space.w_None) return w_item -W_ReverseSeqIterObject.typedef = StdTypeDef("reversesequenceiterator", +W_ReverseSeqIterObject.typedef = StdTypeDef( + "reversesequenceiterator", __iter__ = gateway.interp2app(W_ReverseSeqIterObject.descr_iter), next = gateway.interp2app(W_ReverseSeqIterObject.descr_next), __reduce__ = gateway.interp2app(W_ReverseSeqIterObject.descr_reduce), - __length_hint__ = gateway.interp2app(W_ReverseSeqIterObject.descr_length_hint), + __length_hint__ = gateway.interp2app( + W_ReverseSeqIterObject.descr_length_hint), ) W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False From noreply at buildbot.pypy.org Wed May 22 22:16:08 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 22:16:08 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Document branch. Message-ID: <20130522201608.931ED1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64482:647ed5e89f36 Date: 2013-05-22 22:12 +0200 http://bitbucket.org/pypy/pypy/changeset/647ed5e89f36/ Log: Document branch. 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 @@ -31,3 +31,6 @@ .. branch: remove-tuple-smm Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators From noreply at buildbot.pypy.org Wed May 22 22:16:09 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 22:16:09 +0200 (CEST) Subject: [pypy-commit] pypy remove-iter-smm: Close to-be-merged branch. Message-ID: <20130522201609.E4C8E1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-iter-smm Changeset: r64483:6d6e010445c4 Date: 2013-05-22 22:12 +0200 http://bitbucket.org/pypy/pypy/changeset/6d6e010445c4/ Log: Close to-be-merged branch. From noreply at buildbot.pypy.org Wed May 22 22:16:11 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Wed, 22 May 2013 22:16:11 +0200 (CEST) Subject: [pypy-commit] pypy default: hg merge remove-iter-smm Message-ID: <20130522201611.442BA1C331C@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: Changeset: r64484:df1447de24d7 Date: 2013-05-22 22:13 +0200 http://bitbucket.org/pypy/pypy/changeset/df1447de24d7/ Log: hg merge remove-iter-smm 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 @@ -31,3 +31,6 @@ .. branch: remove-tuple-smm Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,15 +1,11 @@ """Generic iterator implementations""" +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.stdtypedef import StdTypeDef -class W_AbstractIterObject(W_Object): - __slots__ = () - -class W_AbstractSeqIterObject(W_AbstractIterObject): - from pypy.objspace.std.itertype import iter_typedef as typedef - +class W_AbstractSeqIterObject(W_Root): def __init__(w_self, w_seq, index=0): if index < 0: index = 0 @@ -26,12 +22,84 @@ w_len = space.wrap(0) return w_len + def descr_iter(self, space): + return self + + def descr_next(self, space): + raise NotImplementedError + + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.objspace.std.iterobject import W_AbstractSeqIterObject + assert isinstance(self, W_AbstractSeqIterObject) + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('seqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) + + def descr_length_hint(self, space): + from pypy.objspace.std.iterobject import W_AbstractSeqIterObject + assert isinstance(self, W_AbstractSeqIterObject) + return self.getlength(space) + +W_AbstractSeqIterObject.typedef = StdTypeDef( + "sequenceiterator", + __doc__ = '''iter(collection) -> iterator +iter(callable, sentinel) -> iterator + +Get an iterator from an object. In the first form, the argument must +supply its own iterator, or be a sequence. +In the second form, the callable is called until it returns the sentinel.''', + + __iter__ = gateway.interp2app(W_AbstractSeqIterObject.descr_iter), + next = gateway.interpindirect2app(W_AbstractSeqIterObject.descr_next), + __reduce__ = gateway.interp2app(W_AbstractSeqIterObject.descr_reduce), + __length_hint__ = gateway.interp2app( + W_AbstractSeqIterObject.descr_length_hint), +) +W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False + + class W_SeqIterObject(W_AbstractSeqIterObject): """Sequence iterator implementation for general sequences.""" -class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed - """Sequence iterator specialized for lists. - """ + def descr_next(self, space): + if self.w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + self.index += 1 + return w_item + + +class W_FastListIterObject(W_AbstractSeqIterObject): + """Sequence iterator specialized for lists.""" + + def descr_next(self, space): + from pypy.objspace.std.listobject import W_ListObject + w_seq = self.w_seq + if w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + assert isinstance(w_seq, W_ListObject) + index = self.index + try: + w_item = w_seq.getitem(index) + except IndexError: + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + class W_FastTupleIterObject(W_AbstractSeqIterObject): """Sequence iterator specialized for tuples, accessing directly @@ -41,87 +109,79 @@ W_AbstractSeqIterObject.__init__(w_self, w_seq) w_self.tupleitems = wrappeditems -class W_ReverseSeqIterObject(W_Object): - from pypy.objspace.std.itertype import reverse_iter_typedef as typedef + def descr_next(self, space): + if self.tupleitems is None: + raise OperationError(space.w_StopIteration, space.w_None) + index = self.index + try: + w_item = self.tupleitems[index] + except IndexError: + self.tupleitems = None + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + +class W_ReverseSeqIterObject(W_Root): def __init__(w_self, space, w_seq, index=-1): w_self.w_seq = w_seq w_self.w_len = space.len(w_seq) w_self.index = space.int_w(w_self.w_len) + index + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.objspace.std.iterobject import W_ReverseSeqIterObject + assert isinstance(self, W_ReverseSeqIterObject) + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('reverseseqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) -registerimplementation(W_SeqIterObject) -registerimplementation(W_FastListIterObject) -registerimplementation(W_FastTupleIterObject) -registerimplementation(W_ReverseSeqIterObject) + def descr_length_hint(self, space): + from pypy.objspace.std.iterobject import W_ReverseSeqIterObject + assert isinstance(self, W_ReverseSeqIterObject) + if self.w_seq is None: + return space.wrap(0) + index = self.index + 1 + w_length = space.len(self.w_seq) + # if length of sequence is less than index :exhaust iterator + if space.is_true(space.gt(space.wrap(self.index), w_length)): + w_len = space.wrap(0) + self.w_seq = None + else: + w_len = space.wrap(index) + if space.is_true(space.lt(w_len, space.wrap(0))): + w_len = space.wrap(0) + return w_len -def iter__SeqIter(space, w_seqiter): - return w_seqiter + def descr_iter(self, space): + return self -def next__SeqIter(space, w_seqiter): - if w_seqiter.w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index += 1 - return w_item + def descr_next(self, space): + if self.w_seq is None or self.index < 0: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + self.index -= 1 + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + return w_item - -def iter__FastTupleIter(space, w_seqiter): - return w_seqiter - -def next__FastTupleIter(space, w_seqiter): - if w_seqiter.tupleitems is None: - raise OperationError(space.w_StopIteration, space.w_None) - index = w_seqiter.index - try: - w_item = w_seqiter.tupleitems[index] - except IndexError: - w_seqiter.tupleitems = None - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__FastListIter(space, w_seqiter): - return w_seqiter - -def next__FastListIter(space, w_seqiter): - from pypy.objspace.std.listobject import W_ListObject - w_seq = w_seqiter.w_seq - if w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - assert isinstance(w_seq, W_ListObject) - index = w_seqiter.index - try: - w_item = w_seq.getitem(index) - except IndexError: - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__ReverseSeqIter(space, w_seqiter): - return w_seqiter - -def next__ReverseSeqIter(space, w_seqiter): - if w_seqiter.w_seq is None or w_seqiter.index < 0: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - w_seqiter.index -= 1 - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - return w_item - -register_all(vars()) +W_ReverseSeqIterObject.typedef = StdTypeDef( + "reversesequenceiterator", + __iter__ = gateway.interp2app(W_ReverseSeqIterObject.descr_iter), + next = gateway.interp2app(W_ReverseSeqIterObject.descr_next), + __reduce__ = gateway.interp2app(W_ReverseSeqIterObject.descr_reduce), + __length_hint__ = gateway.interp2app( + W_ReverseSeqIterObject.descr_length_hint), +) +W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/itertype.py b/pypy/objspace/std/itertype.py deleted file mode 100644 --- a/pypy/objspace/std/itertype.py +++ /dev/null @@ -1,85 +0,0 @@ -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.interpreter.error import OperationError - -# ____________________________________________________________ - -def descr_seqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - - # cpython does not support pickling iterators but stackless python do - #msg = 'Pickling for iterators dissabled as cpython does not support it' - #raise OperationError(space.w_TypeError, space.wrap(msg)) - - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('seqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_seqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - return w_self.getlength(space) - -# ____________________________________________________________ - -def descr_reverseseqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('reverseseqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_reverseseqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - if w_self.w_seq is None: - return space.wrap(0) - index = w_self.index + 1 - w_length = space.len(w_self.w_seq) - # if length of sequence is less than index :exhaust iterator - if space.is_true(space.gt(space.wrap(w_self.index), w_length)): - w_len = space.wrap(0) - w_self.w_seq = None - else: - w_len = space.wrap(index) - if space.is_true(space.lt(w_len, space.wrap(0))): - w_len = space.wrap(0) - return w_len - -# ____________________________________________________________ -iter_typedef = StdTypeDef("sequenceiterator", - __doc__ = '''iter(collection) -> iterator -iter(callable, sentinel) -> iterator - -Get an iterator from an object. In the first form, the argument must -supply its own iterator, or be a sequence. -In the second form, the callable is called until it returns the sentinel.''', - - __reduce__ = gateway.interp2app(descr_seqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_seqiter__length_hint__), - ) -iter_typedef.acceptable_as_base_class = False - -reverse_iter_typedef = StdTypeDef("reversesequenceiterator", - - __reduce__ = gateway.interp2app(descr_reverseseqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_reverseseqiter__length_hint__), - ) -reverse_iter_typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -44,7 +44,6 @@ from pypy.objspace.std.longtype import long_typedef from pypy.objspace.std.unicodetype import unicode_typedef from pypy.objspace.std.nonetype import none_typedef - from pypy.objspace.std.itertype import iter_typedef self.pythontypes = [value for key, value in result.__dict__.items() if not key.startswith('_')] # don't look @@ -81,6 +80,7 @@ self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) + self.pythontypes.append(iterobject.W_AbstractSeqIterObject.typedef) # the set of implementation types self.typeorder = { @@ -95,10 +95,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - iterobject.W_SeqIterObject: [], - iterobject.W_FastListIterObject: [], - iterobject.W_FastTupleIterObject: [], - iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -19,6 +19,7 @@ from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.iterobject import W_AbstractSeqIterObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.longobject import W_LongObject, newlong from pypy.objspace.std.noneobject import W_NoneObject @@ -668,6 +669,8 @@ self._interplevel_classes[self.w_list] = W_ListObject self._interplevel_classes[self.w_set] = W_SetObject self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + self._interplevel_classes[self.w_sequenceiterator] = \ + W_AbstractSeqIterObject @specialize.memo() def _get_interplevel_cls(self, w_type): diff --git a/pypy/objspace/std/test/test_lengthhint.py b/pypy/objspace/std/test/test_lengthhint.py --- a/pypy/objspace/std/test/test_lengthhint.py +++ b/pypy/objspace/std/test/test_lengthhint.py @@ -74,7 +74,7 @@ self._test_length_hint(self.space.wrap(u'Y' * self.SIZE)) def test_tuple(self): - self._test_length_hint(self.space.newtuple(self.ITEMS)) + self._test_length_hint(self.space.wrap(tuple(self.ITEMS))) def test_reversed(self): # test the generic reversed iterator (w_foo lacks __reversed__) From noreply at buildbot.pypy.org Wed May 22 23:43:42 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 22 May 2013 23:43:42 +0200 (CEST) Subject: [pypy-commit] pypy default: Move these tes methods to be on the base class. Message-ID: <20130522214342.5E2551C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64485:da61460b435a Date: 2013-05-22 14:43 -0700 http://bitbucket.org/pypy/pypy/changeset/da61460b435a/ Log: Move these tes methods to be on the base class. diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py --- a/rpython/jit/metainterp/test/test_string.py +++ b/rpython/jit/metainterp/test/test_string.py @@ -1,16 +1,14 @@ import py -from rpython.jit.codewriter.policy import StopAtXPolicy -from rpython.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from rpython.jit.metainterp.test.support import LLJitMixin from rpython.rlib.debug import debug_print -from rpython.rlib.jit import JitDriver, dont_look_inside, we_are_jitted,\ - promote_string -from rpython.rlib.rstring import StringBuilder -from rpython.rtyper.ootypesystem import ootype +from rpython.rlib.jit import (JitDriver, dont_look_inside, we_are_jitted, + promote_string) +from rpython.rlib.rstring import StringBuilder, UnicodeBuilder class StringTests: - _str, _chr = str, chr + _str, _chr, _StringBuilder = str, chr, StringBuilder def test_eq_residual(self): _str = self._str @@ -358,7 +356,7 @@ s1 = self.meta_interp(f, []) s2 = f() for c1, c2 in zip(s1.chars, s2): - assert c1==c2 + assert c1 == c2 def test_virtual_strings_boxed(self): _str = self._str @@ -516,6 +514,75 @@ self.meta_interp(f, [0]) self.check_resops(call=7) + def test_join_chars(self): + jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) + _str = self._str + + def f(a, b, c): + i = 0 + while i < 10: + jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) + x = [] + if a: + x.append(_str("a")) + if b: + x.append(_str("b")) + if c: + x.append(_str("c")) + i += len(_str("").join(x)) + return i + res = self.meta_interp(f, [1, 1, 1]) + assert res == f(True, True, True) + # The "".join should be unrolled, since the length of x is known since + # it is virtual, ensure there are no calls to ll_join_chars, or + # allocations. + self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, + 'int_add': 2, 'int_is_true': 3}) + + def test_virtual_copystringcontent(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord(b.build()[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_virtual_copystringcontent2(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord((b.build() + _str("xyz"))[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_bytearray(self): + py.test.skip("implement it") + + def f(i): + b = bytearray("abc") + b[1] = i + return b[1] + + res = self.interp_operations(f, [13]) + assert res == 13 + + #class TestOOtype(StringTests, OOJitMixin): # CALL = "oosend" # CALL_PURE = "oosend_pure" @@ -524,8 +591,9 @@ CALL = "call" CALL_PURE = "call_pure" + class TestLLtypeUnicode(TestLLtype): - _str, _chr = unicode, unichr + _str, _chr, _StringBuilder = unicode, unichr, UnicodeBuilder def test_str2unicode(self): _str = self._str @@ -569,64 +637,3 @@ self.check_resops(call_pure=0, unicodesetitem=0, call=2, newunicode=0, unicodegetitem=0, copyunicodecontent=0) - - def test_join_chars(self): - jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) - def f(a, b, c): - i = 0 - while i < 10: - jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) - x = [] - if a: - x.append("a") - if b: - x.append("b") - if c: - x.append("c") - i += len("".join(x)) - return i - res = self.meta_interp(f, [1, 1, 1]) - assert res == f(True, True, True) - # The "".join should be unrolled, since the length of x is known since - # it is virtual, ensure there are no calls to ll_join_chars, or - # allocations. - self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, - 'int_add': 2, 'int_is_true': 3}) - - def test_virtual_copystringcontent(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord(b.build()[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_virtual_copystringcontent2(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord((b.build() + "xyz")[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_bytearray(self): - py.test.skip("implement it") - def f(i): - b = bytearray("abc") - b[1] = i - return b[1] - - res = self.interp_operations(f, [13]) - assert res == 13 From noreply at buildbot.pypy.org Thu May 23 00:29:27 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 00:29:27 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130522222927.AD12D1C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64486:fbb53a72fa8d Date: 2013-05-22 14:41 -0700 http://bitbucket.org/pypy/pypy/changeset/fbb53a72fa8d/ Log: merge default diff too long, truncating to 2000 out of 6754 lines diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -214,10 +214,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), @@ -355,6 +351,7 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0.1`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0.1`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,46 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -22,3 +22,12 @@ .. branch: remove-dict-smm Remove multi-methods on dict + +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -128,12 +128,14 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - os_thread.setup_threads(space) - rffi.aroundstate.before() + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - rthread.gc_thread_start() + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), 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 @@ -7,7 +7,7 @@ appleveldefs = { } interpleveldefs = { - '__version__': 'space.wrap("0.6")', + '__version__': 'space.wrap("0.7")', 'load_library': 'libraryobj.load_library', @@ -30,6 +30,8 @@ 'typeoffsetof': 'func.typeoffsetof', 'rawaddressof': 'func.rawaddressof', 'getcname': 'func.getcname', + 'newp_handle': 'handle.newp_handle', + 'from_handle': 'handle.from_handle', '_get_types': 'func._get_types', 'string': 'func.string', diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -394,6 +394,19 @@ return self.length +class W_CDataHandle(W_CData): + _attrs_ = ['w_keepalive'] + _immutable_fields_ = ['w_keepalive'] + + def __init__(self, space, cdata, ctype, w_keepalive): + W_CData.__init__(self, space, cdata, ctype) + self.w_keepalive = w_keepalive + + def _repr_extra(self): + w_repr = self.space.repr(self.w_keepalive) + return "handle to %s" % (self.space.str_w(w_repr),) + + W_CData.typedef = TypeDef( 'CData', __module__ = '_cffi_backend', 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 @@ -174,8 +174,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = ['is_file', 'cache_array_type'] - _immutable_fields_ = ['is_file', 'cache_array_type?'] + _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr'] + _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr'] kind = "pointer" cache_array_type = None @@ -188,6 +188,7 @@ extra = " *" self.is_file = (ctitem.name == "struct _IO_FILE" or ctitem.name == "struct $FILE") + self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid) W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/handle.py @@ -0,0 +1,93 @@ +import weakref +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import unwrap_spec +from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj +from pypy.module._weakref.interp__weakref import dead_ref +from rpython.rtyper.lltypesystem import lltype, rffi + + +def reduced_value(s): + while True: + divide = s & 1 + s >>= 1 + if not divide: + return s + +# ____________________________________________________________ + + +class CffiHandles: + def __init__(self, space): + self.handles = [] + self.look_distance = 0 + + def reserve_next_handle_index(self): + # The reservation ordering done here is tweaked for pypy's + # memory allocator. We look from index 'look_distance'. + # Look_distance increases from 0. But we also look at + # "look_distance/2" or "/4" or "/8", etc. If we find that one + # of these secondary locations is free, we assume it's because + # there was recently a minor collection; so we reset + # look_distance to 0 and start again from the lowest locations. + length = len(self.handles) + for d in range(self.look_distance, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + s = reduced_value(d) + if self.handles[s]() is None: + break + # restart from the beginning + for d in range(0, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + # full! extend, but don't use '!=' here + self.handles = self.handles + [dead_ref] * (length // 3 + 5) + self.look_distance = length + 1 + return length + + def store_handle(self, index, content): + self.handles[index] = weakref.ref(content) + + def fetch_handle(self, index): + if 0 <= index < len(self.handles): + return self.handles[index]() + return None + +def get(space): + return space.fromcache(CffiHandles) + +# ____________________________________________________________ + + at unwrap_spec(w_ctype=ctypeobj.W_CType) +def newp_handle(space, w_ctype, w_x): + if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or + not w_ctype.is_void_ptr): + raise operationerrfmt(space.w_TypeError, + "needs 'void *', got '%s'", w_ctype.name) + index = get(space).reserve_next_handle_index() + _cdata = rffi.cast(rffi.CCHARP, index + 1) + new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x) + get(space).store_handle(index, new_cdataobj) + return new_cdataobj + + at 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): + raise operationerrfmt(space.w_TypeError, + "expected a 'cdata' object with a 'void *' out " + "of new_handle(), got '%s'", ctype.name) + index = rffi.cast(lltype.Signed, w_cdata._cdata) + original_cdataobj = get(space).fetch_handle(index - 1) + # + if isinstance(original_cdataobj, cdataobj.W_CDataHandle): + return original_cdataobj.w_keepalive + else: + if index == 0: + msg = "cannot use from_handle() on NULL pointer" + else: + msg = "'void *' value does not correspond to any object" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) 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 @@ -2732,6 +2732,32 @@ assert x != cast(BIntP, 12344) assert hash(x) == hash(cast(BIntP, 12345)) +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + + def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.6" + assert __version__ == "0.7" diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/test/test_handle.py @@ -0,0 +1,59 @@ +import random +from pypy.module._cffi_backend.handle import CffiHandles, reduced_value + + +def test_reduced_value(): + assert reduced_value(0) == 0 + assert reduced_value(1) == 0 + assert reduced_value(2) == 1 + assert reduced_value(3) == 0 + assert reduced_value(4) == 2 + assert reduced_value(5) == 1 + assert reduced_value(6) == 3 + assert reduced_value(7) == 0 + assert reduced_value(8) == 4 + assert reduced_value(9) == 2 + assert reduced_value(10) == 5 + assert reduced_value(11) == 1 + + +class PseudoWeakRef(object): + _content = 42 + + def __call__(self): + return self._content + + +def test_cffi_handles_1(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + assert len(ch.handles) < 13500 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr + +def test_cffi_handles_2(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + # + if len(expected_content) > 20: + r = random.choice(list(expected_content)) + pwr = expected_content.pop(r) + pwr._content = None + # + assert len(ch.handles) < 100 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") 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 @@ -344,7 +344,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1, external=False) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -70,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: @@ -324,6 +324,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): @@ -356,13 +357,13 @@ self.strides = strides self.backstrides = backstrides self.shape = shape + if dtype is None: + dtype = parent.dtype if isinstance(parent, SliceArray): parent = parent.parent # one level only self.parent = parent self.storage = parent.storage self.order = parent.order - if dtype is None: - dtype = parent.dtype self.dtype = dtype self.size = support.product(shape) * self.dtype.itemtype.get_element_size() self.start = start diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,14 +268,30 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) @@ -373,7 +389,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,12 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -78,7 +84,8 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) @@ -111,8 +118,15 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -279,15 +293,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -333,10 +354,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +390,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +428,8 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -274,7 +274,7 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) @@ -725,7 +725,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -780,6 +780,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -792,6 +793,27 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.__func__(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2700,6 +2702,56 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array, zeros + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) + + def test_multidim_subarray(self): + from numpypy import dtype, array + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1684,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1696,10 +1699,68 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + items_w = space.fixedview(w_items) + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if space.len_w(shape) <= 1: + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + for w_item in items_w: + self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) + ofs += size + return arr + + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + # TODO: Make sure the shape and the array match + items_w = space.fixedview(w_items) + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if len(shape) <= 1: + for i in range(len(items_w)): + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + for w_item in items_w: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + self._coerce(space, arr, ofs, dtype, w_item, shape[1:]) + ofs += size + + def coerce(self, space, dtype, w_items): + arr = VoidBoxStorage(self.size, dtype) + self._coerce(space, arr, 0, dtype, w_items, dtype.shape) + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + + def readarray(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, + dtype.shape, arr, W_NDimArray(arr), dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1733,7 +1794,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -190,12 +193,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -487,6 +487,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -586,7 +587,6 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=<.*>) i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -44,6 +44,7 @@ # gc_id call is hoisted out of the loop, the id of a value obviously # can't change ;) assert loop.match_by_id("getitem", """ + ... i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...) ... p33 = getinteriorfield_gc(p31, i26, descr=>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -36,7 +36,7 @@ assert loop0.match(expected) # XXX: The retracing fails to form a loop since j # becomes constant 0 after the bridge and constant 1 at the end of the - # loop. A bridge back to the peramble is produced instead. + # loop. A bridge back to the peramble is produced instead. #assert loop1.match(expected) def test_factorial(self): @@ -242,6 +242,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) + guard_not_invalidated(descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -9,8 +9,8 @@ # ____________________________________________________________ - at unwrap_spec(w_depth = WrappedDefault(0)) -def _getframe(space, w_depth): + at unwrap_spec(depth=int) +def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default @@ -18,7 +18,6 @@ This function should be used for internal and specialized purposes only.""" - depth = space.int_w(w_depth) if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -5,7 +5,6 @@ from pypy.objspace.std import stringobject from pypy.objspace.std.bytearraytype import new_bytearray from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.listobject import get_list_index, get_positive_index from pypy.objspace.std.longobject import W_LongObject from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement @@ -14,7 +13,7 @@ from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.stringtype import getbytevalue, makebytesdata_w -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -263,31 +262,30 @@ raise operationerrfmt(space.w_TypeError, msg, funcname, typename) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): + if space.isinstance_w(w_prefix, space.w_tuple): + w_str = _to_bytes(space, w_bytearray) + w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_prefix)]) + return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + w_start, w_stop) + w_prefix = space.wrapbytes(_suffix_to_str(space, w_prefix, 'startswith')) w_str = _to_bytes(space, w_bytearray) return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) -def str_startswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - w_str = _to_bytes(space, w_bytearray) - w_prefix = space.newtuple([space.wrapbytes(space.bufferstr_new_w(w_entry)) - for w_entry in space.unpackiterable(w_prefix)]) - return stringobject.str_startswith__String_Tuple_ANY_ANY(space, w_str, w_prefix, - w_start, w_stop) - def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): + if space.isinstance_w(w_suffix, space.w_tuple): + w_str = _to_bytes(space, w_bytearray) + w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_suffix)]) + return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + w_start, w_stop) w_suffix = space.wrapbytes(_suffix_to_str(space, w_suffix, 'endswith')) w_str = _to_bytes(space, w_bytearray) return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) -def str_endswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): - w_str = _to_bytes(space, w_bytearray) - w_suffix = space.newtuple([space.wrapbytes(space.bufferstr_new_w(w_entry)) - for w_entry in space.unpackiterable(w_suffix)]) - return stringobject.str_endswith__String_Tuple_ANY_ANY(space, w_str, w_suffix, - w_start, w_stop) - def str_join__Bytearray_ANY(space, w_self, w_list): list_w = space.listview(w_list) if not list_w: @@ -538,7 +536,7 @@ _setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00') def delitem__Bytearray_ANY(space, w_bytearray, w_idx): - idx = get_list_index(space, w_idx) + idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray index") try: del w_bytearray.data[idx] except IndexError: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -5,6 +5,7 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null @@ -41,19 +42,6 @@ w_dct.length() <= UNROLL_CUTOFF) -def negate(f): - def _negator(self, space, w_other): - # no need to use space.is_ / space.not_ - tmp = f(self, space, w_other) - if tmp is space.w_NotImplemented: - return space.w_NotImplemented - elif tmp is space.w_False: - return space.w_True - else: - return space.w_False - _negator.func_name = 'negate-%s' % f.func_name - return _negator - class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,27 +1,35 @@ -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.multimethod import FailedToImplement +import operator +from sys import maxint + +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import (WrappedDefault, unwrap_spec, applevel, + interp2app) from pypy.interpreter.generator import GeneratorIterator +from pypy.interpreter.signature import Signature +from pypy.objspace.std import slicetype +from pypy.objspace.std.floatobject import W_FloatObject +from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.iterobject import (W_FastListIterObject, + W_ReverseSeqIterObject) from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std import slicetype -from pypy.interpreter.gateway import WrappedDefault, unwrap_spec, applevel,\ - interp2app -from pypy.interpreter import baseobjspace -from pypy.interpreter.signature import Signature +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject +from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.util import negate, get_positive_index +from rpython.rlib import rerased, jit, debug +from rpython.rlib.listsort import make_timsort_class from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) -from rpython.rlib.listsort import make_timsort_class -from rpython.rlib import rerased, jit, debug + resizelist_hint) from rpython.tool.sourcetools import func_with_new_name -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from sys import maxint + +__all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] + UNROLL_CUTOFF = 5 -class W_AbstractListObject(W_Object): - __slots__ = () def make_range_list(space, start, step, length): if length <= 0: @@ -32,16 +40,19 @@ storage = strategy.erase((start, step, length)) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list(space): strategy = space.fromcache(EmptyListStrategy) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + def make_empty_list_with_size(space, hint): strategy = SizeListStrategy(space, hint) storage = strategy.erase(None) return W_ListObject.from_storage_and_strategy(space, storage, strategy) + @jit.look_inside_iff(lambda space, list_w, sizehint: jit.loop_unrolling_heuristic(list_w, len(list_w), UNROLL_CUTOFF)) def get_strategy_from_list_objects(space, list_w, sizehint): @@ -52,7 +63,7 @@ # check for ints for w_obj in list_w: - if not is_W_IntObject(w_obj): + if not type(w_obj) is W_IntObject: break else: return space.fromcache(IntegerListStrategy) @@ -61,7 +72,7 @@ # XXX: StringListStrategy is currently broken """ for w_obj in list_w: - if not is_W_StringObject(w_obj): + if not type(w_obj) is W_StringObject: break else: return space.fromcache(StringListStrategy) @@ -69,24 +80,26 @@ # check for unicode for w_obj in list_w: - if not is_W_UnicodeObject(w_obj): + if not type(w_obj) is W_UnicodeObject: break else: return space.fromcache(UnicodeListStrategy) # check for floats for w_obj in list_w: - if not is_W_FloatObject(w_obj): + if not type(w_obj) is W_FloatObject: break else: return space.fromcache(FloatListStrategy) return space.fromcache(ObjectListStrategy) + def _get_printable_location(w_type): return ('list__do_extend_from_iterable [w_type=%s]' % w_type.getname(w_type.space)) + _do_extend_jitdriver = jit.JitDriver( name='list__do_extend_from_iterable', greens=['w_type'], @@ -111,23 +124,15 @@ i += 1 return i -def is_W_IntObject(w_object): - from pypy.objspace.std.intobject import W_IntObject - return type(w_object) is W_IntObject -def is_W_StringObject(w_object): - from pypy.objspace.std.stringobject import W_StringObject - return type(w_object) is W_StringObject +def list_unroll_condition(w_list1, space, w_list2): + return (jit.loop_unrolling_heuristic(w_list1, w_list1.length(), + UNROLL_CUTOFF) or + jit.loop_unrolling_heuristic(w_list2, w_list2.length(), + UNROLL_CUTOFF)) -def is_W_UnicodeObject(w_object): - from pypy.objspace.std.unicodeobject import W_UnicodeObject - return type(w_object) is W_UnicodeObject -def is_W_FloatObject(w_object): - from pypy.objspace.std.floatobject import W_FloatObject - return type(w_object) is W_FloatObject - -class W_ListObject(W_AbstractListObject): +class W_ListObject(W_Root): def __init__(w_self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) w_self.space = space @@ -159,7 +164,8 @@ def __repr__(w_self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, w_self.lstorage._x) + return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, + w_self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -178,7 +184,8 @@ list_w = self.getitems() strategy = self.space.fromcache(ObjectListStrategy) storage = strategy.erase(list_w) - w_objectlist = W_ListObject.from_storage_and_strategy(self.space, storage, strategy) + w_objectlist = W_ListObject.from_storage_and_strategy( + self.space, storage, strategy) return w_objectlist # ___________________________________________________ @@ -214,13 +221,12 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) def append(self, w_item): - 'L.append(object) -- append object to end' + """L.append(object) -- append object to end""" self.strategy.append(self, w_item) def length(self): @@ -233,8 +239,8 @@ return self.strategy.getitem(self, index) def getslice(self, start, stop, step, length): - """Returns a slice of the list defined by the arguments. Arguments must be - normalized (i.e. using normalize_simple_slice or W_Slice.indices4). + """Returns a slice of the list defined by the arguments. Arguments must + be normalized (i.e. using normalize_simple_slice or W_Slice.indices4). May raise IndexError.""" return self.strategy.getslice(self, start, stop, step, length) @@ -251,7 +257,7 @@ def getitems_unroll(self): """Returns a fixed-size list of all items after wrapping them. The JIT - will fully unroll this function. """ + will fully unroll this function.""" l = self.strategy.getitems_unroll(self) debug.make_sure_not_resized(l) return l @@ -262,22 +268,21 @@ return self.strategy.getitems_copy(self) def getitems_str(self): - """ Return the items in the list as unwrapped strings. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped strings. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_str(self) def getitems_unicode(self): - """ Return the items in the list as unwrapped unicodes. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped unicodes. If the list does + not use the list strategy, return None.""" return self.strategy.getitems_unicode(self) def getitems_int(self): - """ Return the items in the list as unwrapped ints. If the list does - not use the list strategy, return None. """ + """Return the items in the list as unwrapped ints. If the list does not + use the list strategy, return None.""" return self.strategy.getitems_int(self) # ___________________________________________________ - def mul(self, times): """Returns a copy of the list, multiplied by times. Argument must be unwrapped.""" @@ -331,15 +336,222 @@ argument reverse. Argument must be unwrapped.""" self.strategy.sort(self, reverse) + # exposed to app-level + + @staticmethod + def descr_new(space, w_listtype, __args__): + w_obj = space.allocate_instance(W_ListObject, w_listtype) + w_obj.clear(space) + return w_obj + + def descr_init(self, space, __args__): + # this is on the silly side + w_iterable, = __args__.parse_obj( + None, 'list', init_signature, init_defaults) + self.clear(space) + if w_iterable is not None: + self.extend(w_iterable) + + def descr_repr(self, space): + if self.length() == 0: + return space.wrap('[]') + ec = space.getexecutioncontext() + w_currently_in_repr = ec._py_repr + if w_currently_in_repr is None: + w_currently_in_repr = ec._py_repr = space.newdict() + return listrepr(space, w_currently_in_repr, self) + + def descr_eq(self, space, w_other): + if not isinstance(w_other, W_ListObject): + return space.w_NotImplemented + return self._descr_eq(space, w_other) + + @jit.look_inside_iff(list_unroll_condition) + def _descr_eq(self, space, w_other): + # needs to be safe against eq_w() mutating the w_lists behind our back + if self.length() != w_other.length(): + return space.w_False + + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now + i = 0 + while i < self.length() and i < w_other.length(): + if not space.eq_w(self.getitem(i), w_other.getitem(i)): + return space.w_False + i += 1 + return space.w_True + + descr_ne = negate(descr_eq) + + def _make_list_comparison(name): + op = getattr(operator, name) + + def compare_unwrappeditems(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented + return _compare_unwrappeditems(self, space, w_list2) + + @jit.look_inside_iff(list_unroll_condition) + def _compare_unwrappeditems(self, space, w_list2): + # needs to be safe against eq_w() mutating the w_lists behind our + # back + # Search for the first index where items are different + i = 0 + # XXX in theory, this can be implemented more efficiently as well. + # let's not care for now + while i < self.length() and i < w_list2.length(): + w_item1 = self.getitem(i) + w_item2 = w_list2.getitem(i) + if not space.eq_w(w_item1, w_item2): + return getattr(space, name)(w_item1, w_item2) + i += 1 + # No more items to compare -- compare sizes + return space.newbool(op(self.length(), w_list2.length())) + + return func_with_new_name(compare_unwrappeditems, name + '__List_List') + + descr_lt = _make_list_comparison('lt') + descr_le = _make_list_comparison('le') + descr_gt = _make_list_comparison('gt') + descr_ge = _make_list_comparison('ge') + + def descr_len(self, space): + result = self.length() + return wrapint(space, result) + + def descr_iter(self, space): + return W_FastListIterObject(self) + + def descr_contains(self, space, w_obj): + try: + self.find(w_obj) + return space.w_True + except ValueError: + return space.w_False + + def descr_add(self, space, w_list2): + if not isinstance(w_list2, W_ListObject): + return space.w_NotImplemented + w_clone = self.clone() + w_clone.extend(w_list2) + return w_clone + + def descr_inplace_add(self, space, w_iterable): + if isinstance(w_iterable, W_ListObject): + self.extend(w_iterable) + return self + + try: + self.extend(w_iterable) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + return self.mul(times) + + def descr_inplace_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + raise + self.inplace_mul(times) + return self + + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + # XXX consider to extend rlist's functionality? + length = self.length() + start, stop, step, slicelength = w_index.indices4(space, length) + assert slicelength >= 0 + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, step, slicelength) + + try: + index = space.getindex_w(w_index, space.w_IndexError, "list index") + return self.getitem(index) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("list index out of range")) + + def descr_getslice(self, space, w_start, w_stop): + length = self.length() + start, stop = normalize_simple_slice(space, length, w_start, w_stop) + + slicelength = stop - start + if slicelength == 0: + return make_empty_list(space) + return self.getslice(start, stop, 1, stop - start) + From noreply at buildbot.pypy.org Thu May 23 00:29:29 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 00:29:29 +0200 (CEST) Subject: [pypy-commit] pypy py3k: forbid_delegation was killed Message-ID: <20130522222929.5F6DC1C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64487:ef760aff9941 Date: 2013-05-22 15:14 -0700 http://bitbucket.org/pypy/pypy/changeset/ef760aff9941/ Log: forbid_delegation was killed diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py --- a/pypy/objspace/std/test/test_specialisedtupleobject.py +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -78,10 +78,6 @@ obj = (1, 2, 3) assert self.isspecialised(obj, '_ooo') - def test_delegation(self): - t = self.forbid_delegation((42, 43)) - raises(ReferenceError, t.__contains__, 0) - def test_len(self): t = (42, 43) assert len(t) == 2 From noreply at buildbot.pypy.org Thu May 23 00:29:30 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 00:29:30 +0200 (CEST) Subject: [pypy-commit] pypy py3k: reapply py3k mods Message-ID: <20130522222930.C42441C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64488:3484e4c671d1 Date: 2013-05-22 15:15 -0700 http://bitbucket.org/pypy/pypy/changeset/3484e4c671d1/ Log: reapply py3k mods diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -75,9 +75,11 @@ def descr_repr(self, space): items = self.tolist() if len(items) == 1: - return space.wrap("(" + space.str_w(space.repr(items[0])) + ",)") - tmp = ", ".join([space.str_w(space.repr(item)) for item in items]) - return space.wrap("(" + tmp + ")") + return space.wrap(u"(" + space.unicode_w(space.repr(items[0])) + + u",)") + tmp = u", ".join([space.unicode_w(space.repr(item)) + for item in items]) + return space.wrap(u"(" + tmp + u")") def descr_hash(self, space): raise NotImplementedError @@ -160,11 +162,6 @@ start += step return space.newtuple(subitems) - def descr_getslice(self, space, w_start, w_stop): - length = self.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return space.newtuple(self.tolist()[start:stop]) - def descr_getnewargs(self, space): return space.newtuple([space.newtuple(self.tolist())]) @@ -220,7 +217,6 @@ __rmul__ = interp2app(W_AbstractTupleObject.descr_mul), __getitem__ = interp2app(W_AbstractTupleObject.descr_getitem), - __getslice__ = interp2app(W_AbstractTupleObject.descr_getslice), __getnewargs__ = interp2app(W_AbstractTupleObject.descr_getnewargs), count = interp2app(W_AbstractTupleObject.descr_count), From noreply at buildbot.pypy.org Thu May 23 00:29:32 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 00:29:32 +0200 (CEST) Subject: [pypy-commit] pypy py3k: reapply py3k's wrapbytes Message-ID: <20130522222932.4A4E21C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64489:1ea11f8296ab Date: 2013-05-22 15:16 -0700 http://bitbucket.org/pypy/pypy/changeset/1ea11f8296ab/ Log: reapply py3k's wrapbytes diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -264,7 +264,7 @@ def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): if space.isinstance_w(w_prefix, space.w_tuple): w_str = _to_bytes(space, w_bytearray) - w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + w_prefix = space.newtuple([space.wrapbytes(space.bufferstr_new_w(w_entry)) for w_entry in space.fixedview(w_prefix)]) return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) @@ -277,7 +277,7 @@ def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): if space.isinstance_w(w_suffix, space.w_tuple): w_str = _to_bytes(space, w_bytearray) - w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + w_suffix = space.newtuple([space.wrapbytes(space.bufferstr_new_w(w_entry)) for w_entry in space.fixedview(w_suffix)]) return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) From noreply at buildbot.pypy.org Thu May 23 00:29:33 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 00:29:33 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix tuple handling Message-ID: <20130522222933.B61641C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64490:f093a2c55499 Date: 2013-05-22 15:16 -0700 http://bitbucket.org/pypy/pypy/changeset/f093a2c55499/ Log: fix tuple handling diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -725,35 +725,33 @@ w_end, True) return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) -def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): - if not space.isinstance_w(w_suffixes, space.w_tuple): - raise FailedToImplement - (u_self, start, end) = _convert_idx_params(space, w_self, w_start, - w_end, True) - for w_suffix in space.fixedview(w_suffixes): - suffix = space.bufferstr_w(w_suffix) +def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffix, w_start, w_end): + u_self, start, end = _convert_idx_params(space, w_self, w_start, w_end, + True) + if not space.isinstance_w(w_suffix, space.w_tuple): + suffix = _suffix_to_str(space, w_suffix, 'endswith') + return space.newbool(stringendswith(u_self, suffix, start, end)) + + for w_item in space.fixedview(w_suffix): + suffix = space.bufferstr_w(w_item) if stringendswith(u_self, suffix, start, end): return space.w_True return space.w_False -def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefix, w_start, w_end): - (u_self, start, end) = _convert_idx_params(space, w_self, w_start, - w_end, True) - return space.newbool(stringstartswith( - u_self, _suffix_to_str(space, w_prefix, 'startswith'), start, end)) - def str_startswith__String_String_ANY_ANY(space, w_self, w_prefix, w_start, w_end): (u_self, start, end) = _convert_idx_params(space, w_self, w_start, w_end, True) return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) -def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): - if not space.isinstance_w(w_prefixes, space.w_tuple): - raise FailedToImplement - (u_self, start, end) = _convert_idx_params(space, w_self, - w_start, w_end, True) - for w_prefix in space.fixedview(w_prefixes): - prefix = space.bufferstr_w(w_prefix) +def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefix, w_start, w_end): + u_self, start, end = _convert_idx_params(space, w_self, w_start, w_end, + True) + if not space.isinstance_w(w_prefix, space.w_tuple): + prefix = _suffix_to_str(space, w_prefix, 'startswith') + return space.newbool(stringstartswith(u_self, prefix, start, end)) + + for w_item in space.fixedview(w_prefix): + prefix = space.bufferstr_w(w_item) if stringstartswith(u_self, prefix, start, end): return space.w_True return space.w_False diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -453,22 +453,11 @@ space, len(self), w_start, w_end, upper_bound) return (self, start, end) -def unicode_endswith__Unicode_ANY_ANY_ANY(space, w_self, w_substr, w_start, w_end): - typename = space.type(w_substr).getname(space) - msg = "endswith first arg must be str or a tuple of str, not %s" % typename - raise OperationError(space.w_TypeError, space.wrap(msg)) - def unicode_endswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): self, start, end = _convert_idx_params(space, w_self, w_start, w_end, True) return space.newbool(stringendswith(self, w_substr._value, start, end)) -def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_self, w_substr, w_start, w_end): - typename = space.type(w_substr).getname(space) - msg = ("startswith first arg must be str or a tuple of str, not %s" % - typename) - raise OperationError(space.w_TypeError, space.wrap(msg)) - def unicode_startswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): self, start, end = _convert_idx_params(space, w_self, w_start, w_end, True) # XXX this stuff can be waaay better for ootypebased backends if @@ -479,7 +468,11 @@ def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_prefixes, w_start, w_end): if not space.isinstance_w(w_prefixes, space.w_tuple): - raise FailedToImplement + typename = space.type(w_prefixes).getname(space) + msg = ("startswith first arg must be str or a tuple of str, not %s" % + typename) + raise OperationError(space.w_TypeError, space.wrap(msg)) + unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): @@ -491,7 +484,10 @@ def unicode_endswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_suffixes, w_start, w_end): if not space.isinstance_w(w_suffixes, space.w_tuple): - raise FailedToImplement + typename = space.type(w_suffixes).getname(space) + msg = "endswith first arg must be str or a tuple of str, not %s" % typename + raise OperationError(space.w_TypeError, space.wrap(msg)) + unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): From noreply at buildbot.pypy.org Thu May 23 00:39:15 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 23 May 2013 00:39:15 +0200 (CEST) Subject: [pypy-commit] pypy default: Mark this function as threadsafe=True so it doesn't release the GIL, it's very fast. Message-ID: <20130522223915.06B3F1C331B@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64491:3e52ecf916b2 Date: 2013-05-22 15:38 -0700 http://bitbucket.org/pypy/pypy/changeset/3e52ecf916b2/ Log: Mark this function as threadsafe=True so it doesn't release the GIL, it's very fast. diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py --- a/rpython/rtyper/module/ll_os.py +++ b/rpython/rtyper/module/ll_os.py @@ -682,7 +682,7 @@ @registering_if(os, 'getpid') def register_os_getpid(self): - return self.extdef_for_os_function_returning_int('getpid') + return self.extdef_for_os_function_returning_int('getpid', threadsafe=False) @registering_if(os, 'getgid') def register_os_getgid(self): From noreply at buildbot.pypy.org Thu May 23 00:40:43 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 00:40:43 +0200 (CEST) Subject: [pypy-commit] pypy py3k: kill kill kill Message-ID: <20130522224043.0D2DE1C331B@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64492:fe4e379eaafb Date: 2013-05-22 15:39 -0700 http://bitbucket.org/pypy/pypy/changeset/fe4e379eaafb/ Log: kill kill kill diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -13,7 +13,7 @@ from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.iterobject import (W_FastListIterObject, W_ReverseSeqIterObject) -from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std.stdtypedef import StdTypeDef from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject @@ -485,15 +485,6 @@ raise OperationError(space.w_IndexError, space.wrap("list index out of range")) - def descr_getslice(self, space, w_start, w_stop): - length = self.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - - slicelength = stop - start - if slicelength == 0: - return make_empty_list(space) - return self.getslice(start, stop, 1, stop - start) - def descr_setitem(self, space, w_index, w_any): if isinstance(w_index, W_SliceObject): oldsize = self.length() @@ -513,17 +504,6 @@ raise OperationError(space.w_IndexError, space.wrap("list index out of range")) - def descr_setslice(self, space, w_start, w_stop, w_iterable): - length = self.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - - if isinstance(w_iterable, W_ListObject): - self.setslice(start, 1, stop - start, w_iterable) - else: - sequence_w = space.listview(w_iterable) - w_other = W_ListObject(space, sequence_w) - self.setslice(start, 1, stop - start, w_other) - def descr_delitem(self, space, w_idx): if isinstance(w_idx, W_SliceObject): start, stop, step, slicelength = w_idx.indices4( @@ -540,11 +520,6 @@ raise OperationError(space.w_IndexError, space.wrap("list index out of range")) - def descr_delslice(self, space, w_start, w_stop): - length = self.length() - start, stop = normalize_simple_slice(space, length, w_start, w_stop) - self.deleteslice(start, 1, stop - start) - def descr_reversed(self, space): 'L.__reversed__() -- return a reverse iterator over the list' return W_ReverseSeqIterObject(space, self, -1) @@ -1713,11 +1688,8 @@ __imul__ = interp2app(W_ListObject.descr_inplace_mul), __getitem__ = interp2app(W_ListObject.descr_getitem), - __getslice__ = interp2app(W_ListObject.descr_getslice), __setitem__ = interp2app(W_ListObject.descr_setitem), - __setslice__ = interp2app(W_ListObject.descr_setslice), __delitem__ = interp2app(W_ListObject.descr_delitem), - __delslice__ = interp2app(W_ListObject.descr_delslice), sort = interp2app(W_ListObject.descr_sort), index = interp2app(W_ListObject.descr_index), From noreply at buildbot.pypy.org Thu May 23 00:50:05 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 23 May 2013 00:50:05 +0200 (CEST) Subject: [pypy-commit] pypy default: When ll_shrink_array is called a constant string allow that to be propogated. Message-ID: <20130522225005.CCF041C331D@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64493:f6e4e1ccc876 Date: 2013-05-22 15:49 -0700 http://bitbucket.org/pypy/pypy/changeset/f6e4e1ccc876/ Log: When ll_shrink_array is called a constant string allow that to be propogated. diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -21,6 +21,7 @@ OS_NONE = 0 # normal case, no oopspec OS_ARRAYCOPY = 1 # "list.ll_arraycopy" OS_STR2UNICODE = 2 # "str.str2unicode" + OS_SHRINK_ARRAY = 3 # rgc.ll_shrink_array # OS_STR_CONCAT = 22 # "stroruni.concat" OS_STR_SLICE = 23 # "stroruni.slice" @@ -82,8 +83,10 @@ OS_JIT_FORCE_VIRTUAL = 120 # for debugging: - _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, - OS_RAW_MALLOC_VARSIZE_CHAR, OS_JIT_FORCE_VIRTUAL]) + _OS_CANRAISE = set([ + OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, OS_RAW_MALLOC_VARSIZE_CHAR, + OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY, + ]) def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -398,6 +398,8 @@ prepare = self._handle_libffi_call elif oopspec_name.startswith('math.sqrt'): prepare = self._handle_math_sqrt_call + elif oopspec_name.startswith('rgc.'): + prepare = self._handle_rgc_call else: prepare = self.prepare_builtin_call try: @@ -1779,6 +1781,12 @@ return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, EffectInfo.EF_ELIDABLE_CANNOT_RAISE) + def _handle_rgc_call(self, op, oopspec_name, args): + if oopspec_name == 'rgc.ll_shrink_array': + return self._handle_oopspec_call(op, args, EffectInfo.OS_SHRINK_ARRAY, EffectInfo.EF_CAN_RAISE) + else: + raise NotImplementedError(oopspec_name) + def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args descr1 = self.cpu.fielddescrof(v_inst.concretetype.TO, diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -136,6 +136,9 @@ assert size <= MAX_CONST_LEN self._chars = [None] * size + def shrink(self, length): + del self._chars[length:] + def setup_slice(self, longerlist, start, stop): assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] @@ -554,6 +557,9 @@ if oopspecindex == EffectInfo.OS_STR2UNICODE: if self.opt_call_str_STR2UNICODE(op): return + if oopspecindex == EffectInfo.OS_SHRINK_ARRAY: + if self.opt_call_SHRINK_ARRAY(op): + return self.emit_operation(op) optimize_CALL_PURE = optimize_CALL @@ -721,6 +727,19 @@ return True return False + def opt_call_SHRINK_ARRAY(self, op): + v1 = self.getvalue(op.getarg(1)) + v2 = self.getvalue(op.getarg(2)) + # If the index is constant, if the argument is virtual (we only support + # VStringPlainValue for now) we can optimize away the call. + if v2.is_constant() and v1.is_virtual() and isinstance(v1, VStringPlainValue): + length = v2.box.getint() + v1.shrink(length) + self.last_emitted_operation = REMOVED + self.make_equal_to(op.result, v1) + return True + return False + def generate_modified_call(self, oopspecindex, args, result, mode): oopspecindex += mode.OS_offset cic = self.optimizer.metainterp_sd.callinfocollection diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py --- a/rpython/jit/metainterp/test/test_string.py +++ b/rpython/jit/metainterp/test/test_string.py @@ -582,6 +582,26 @@ res = self.interp_operations(f, [13]) assert res == 13 + def test_shrink_array(self): + jitdriver = JitDriver(reds=['result', 'n'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def f(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(20) + b.append(_str("Testing!")) + result += len(b.build()) + n -= 1 + return result + + res = self.meta_interp(f, [9]) + assert res == f(9) + self.check_resops({ + 'jump': 1, 'guard_true': 2, 'int_ge': 2, 'int_add': 2, 'int_sub': 2 + }) + #class TestOOtype(StringTests, OOJitMixin): # CALL = "oosend" diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py --- a/rpython/rlib/rgc.py +++ b/rpython/rlib/rgc.py @@ -183,6 +183,7 @@ return True return False + @jit.oopspec('list.ll_arraycopy(source, dest, source_start, dest_start, length)') @enforceargs(None, None, int, int, int) @specialize.ll() @@ -229,6 +230,9 @@ keepalive_until_here(source) keepalive_until_here(dest) + + at jit.oopspec('rgc.ll_shrink_array(p, smallerlength)') + at specialize.ll() def ll_shrink_array(p, smallerlength): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import keepalive_until_here @@ -249,16 +253,15 @@ ARRAY = getattr(TP, TP._arrayfld) offset = (llmemory.offsetof(TP, TP._arrayfld) + llmemory.itemoffsetof(ARRAY, 0)) - source_addr = llmemory.cast_ptr_to_adr(p) + offset - dest_addr = llmemory.cast_ptr_to_adr(newp) + offset + source_addr = llmemory.cast_ptr_to_adr(p) + offset + dest_addr = llmemory.cast_ptr_to_adr(newp) + offset llmemory.raw_memcopy(source_addr, dest_addr, llmemory.sizeof(ARRAY.OF) * smallerlength) keepalive_until_here(p) keepalive_until_here(newp) return newp -ll_shrink_array._annspecialcase_ = 'specialize:ll' -ll_shrink_array._jit_look_inside_ = False + def no_collect(func): func._dont_inline_ = True From noreply at buildbot.pypy.org Thu May 23 00:50:53 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 23 May 2013 00:50:53 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged default in Message-ID: <20130522225053.C897D1C331D@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64494:be8a71a17b62 Date: 2013-05-22 15:50 -0700 http://bitbucket.org/pypy/pypy/changeset/be8a71a17b62/ Log: merged default in 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 @@ -31,3 +31,6 @@ .. branch: remove-tuple-smm Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators 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 @@ -7,7 +7,7 @@ appleveldefs = { } interpleveldefs = { - '__version__': 'space.wrap("0.6")', + '__version__': 'space.wrap("0.7")', 'load_library': 'libraryobj.load_library', @@ -30,6 +30,8 @@ 'typeoffsetof': 'func.typeoffsetof', 'rawaddressof': 'func.rawaddressof', 'getcname': 'func.getcname', + 'newp_handle': 'handle.newp_handle', + 'from_handle': 'handle.from_handle', '_get_types': 'func._get_types', 'string': 'func.string', diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -394,6 +394,19 @@ return self.length +class W_CDataHandle(W_CData): + _attrs_ = ['w_keepalive'] + _immutable_fields_ = ['w_keepalive'] + + def __init__(self, space, cdata, ctype, w_keepalive): + W_CData.__init__(self, space, cdata, ctype) + self.w_keepalive = w_keepalive + + def _repr_extra(self): + w_repr = self.space.repr(self.w_keepalive) + return "handle to %s" % (self.space.str_w(w_repr),) + + W_CData.typedef = TypeDef( 'CData', __module__ = '_cffi_backend', 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 @@ -172,8 +172,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = ['is_file', 'cache_array_type'] - _immutable_fields_ = ['is_file', 'cache_array_type?'] + _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr'] + _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr'] kind = "pointer" cache_array_type = None @@ -186,6 +186,7 @@ extra = " *" self.is_file = (ctitem.name == "struct _IO_FILE" or ctitem.name == "struct $FILE") + self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid) W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/handle.py @@ -0,0 +1,93 @@ +import weakref +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import unwrap_spec +from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj +from pypy.module._weakref.interp__weakref import dead_ref +from rpython.rtyper.lltypesystem import lltype, rffi + + +def reduced_value(s): + while True: + divide = s & 1 + s >>= 1 + if not divide: + return s + +# ____________________________________________________________ + + +class CffiHandles: + def __init__(self, space): + self.handles = [] + self.look_distance = 0 + + def reserve_next_handle_index(self): + # The reservation ordering done here is tweaked for pypy's + # memory allocator. We look from index 'look_distance'. + # Look_distance increases from 0. But we also look at + # "look_distance/2" or "/4" or "/8", etc. If we find that one + # of these secondary locations is free, we assume it's because + # there was recently a minor collection; so we reset + # look_distance to 0 and start again from the lowest locations. + length = len(self.handles) + for d in range(self.look_distance, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + s = reduced_value(d) + if self.handles[s]() is None: + break + # restart from the beginning + for d in range(0, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + # full! extend, but don't use '!=' here + self.handles = self.handles + [dead_ref] * (length // 3 + 5) + self.look_distance = length + 1 + return length + + def store_handle(self, index, content): + self.handles[index] = weakref.ref(content) + + def fetch_handle(self, index): + if 0 <= index < len(self.handles): + return self.handles[index]() + return None + +def get(space): + return space.fromcache(CffiHandles) + +# ____________________________________________________________ + + at unwrap_spec(w_ctype=ctypeobj.W_CType) +def newp_handle(space, w_ctype, w_x): + if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or + not w_ctype.is_void_ptr): + raise operationerrfmt(space.w_TypeError, + "needs 'void *', got '%s'", w_ctype.name) + index = get(space).reserve_next_handle_index() + _cdata = rffi.cast(rffi.CCHARP, index + 1) + new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x) + get(space).store_handle(index, new_cdataobj) + return new_cdataobj + + at 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): + raise operationerrfmt(space.w_TypeError, + "expected a 'cdata' object with a 'void *' out " + "of new_handle(), got '%s'", ctype.name) + index = rffi.cast(lltype.Signed, w_cdata._cdata) + original_cdataobj = get(space).fetch_handle(index - 1) + # + if isinstance(original_cdataobj, cdataobj.W_CDataHandle): + return original_cdataobj.w_keepalive + else: + if index == 0: + msg = "cannot use from_handle() on NULL pointer" + else: + msg = "'void *' value does not correspond to any object" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) 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 @@ -2732,6 +2732,32 @@ assert x != cast(BIntP, 12344) assert hash(x) == hash(cast(BIntP, 12345)) +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + + def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.6" + assert __version__ == "0.7" diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/test/test_handle.py @@ -0,0 +1,59 @@ +import random +from pypy.module._cffi_backend.handle import CffiHandles, reduced_value + + +def test_reduced_value(): + assert reduced_value(0) == 0 + assert reduced_value(1) == 0 + assert reduced_value(2) == 1 + assert reduced_value(3) == 0 + assert reduced_value(4) == 2 + assert reduced_value(5) == 1 + assert reduced_value(6) == 3 + assert reduced_value(7) == 0 + assert reduced_value(8) == 4 + assert reduced_value(9) == 2 + assert reduced_value(10) == 5 + assert reduced_value(11) == 1 + + +class PseudoWeakRef(object): + _content = 42 + + def __call__(self): + return self._content + + +def test_cffi_handles_1(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + assert len(ch.handles) < 13500 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr + +def test_cffi_handles_2(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + # + if len(expected_content) > 20: + r = random.choice(list(expected_content)) + pwr = expected_content.pop(r) + pwr._content = None + # + assert len(ch.handles) < 100 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -70,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: @@ -324,6 +324,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): @@ -356,13 +357,13 @@ self.strides = strides self.backstrides = backstrides self.shape = shape + if dtype is None: + dtype = parent.dtype if isinstance(parent, SliceArray): parent = parent.parent # one level only self.parent = parent self.storage = parent.storage self.order = parent.order - if dtype is None: - dtype = parent.dtype self.dtype = dtype self.size = support.product(shape) * self.dtype.itemtype.get_element_size() self.start = start diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,14 +268,30 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) @@ -373,7 +389,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,12 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -78,7 +84,8 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) @@ -111,8 +118,15 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -279,15 +293,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -333,10 +354,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +390,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +428,8 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,7 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) @@ -726,7 +726,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -781,6 +781,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -793,6 +794,27 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2699,6 +2701,56 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array, zeros + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) + + def test_multidim_subarray(self): + from numpypy import dtype, array + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1684,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1696,10 +1699,68 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + items_w = space.fixedview(w_items) + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if space.len_w(shape) <= 1: + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + for w_item in items_w: + self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) + ofs += size + return arr + + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + # TODO: Make sure the shape and the array match + items_w = space.fixedview(w_items) + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if len(shape) <= 1: + for i in range(len(items_w)): + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + for w_item in items_w: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + self._coerce(space, arr, ofs, dtype, w_item, shape[1:]) + ofs += size + + def coerce(self, space, dtype, w_items): + arr = VoidBoxStorage(self.size, dtype) + self._coerce(space, arr, 0, dtype, w_items, dtype.shape) + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + + def readarray(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, + dtype.shape, arr, W_NDimArray(arr), dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1733,7 +1794,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,15 +1,11 @@ """Generic iterator implementations""" +from pypy.interpreter import gateway +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.stdtypedef import StdTypeDef -class W_AbstractIterObject(W_Object): - __slots__ = () - -class W_AbstractSeqIterObject(W_AbstractIterObject): - from pypy.objspace.std.itertype import iter_typedef as typedef - +class W_AbstractSeqIterObject(W_Root): def __init__(w_self, w_seq, index=0): if index < 0: index = 0 @@ -26,12 +22,84 @@ w_len = space.wrap(0) return w_len + def descr_iter(self, space): + return self + + def descr_next(self, space): + raise NotImplementedError + + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.objspace.std.iterobject import W_AbstractSeqIterObject + assert isinstance(self, W_AbstractSeqIterObject) + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('seqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) + + def descr_length_hint(self, space): + from pypy.objspace.std.iterobject import W_AbstractSeqIterObject + assert isinstance(self, W_AbstractSeqIterObject) + return self.getlength(space) + +W_AbstractSeqIterObject.typedef = StdTypeDef( + "sequenceiterator", + __doc__ = '''iter(collection) -> iterator +iter(callable, sentinel) -> iterator + +Get an iterator from an object. In the first form, the argument must +supply its own iterator, or be a sequence. +In the second form, the callable is called until it returns the sentinel.''', + + __iter__ = gateway.interp2app(W_AbstractSeqIterObject.descr_iter), + next = gateway.interpindirect2app(W_AbstractSeqIterObject.descr_next), + __reduce__ = gateway.interp2app(W_AbstractSeqIterObject.descr_reduce), + __length_hint__ = gateway.interp2app( + W_AbstractSeqIterObject.descr_length_hint), +) +W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False + + class W_SeqIterObject(W_AbstractSeqIterObject): """Sequence iterator implementation for general sequences.""" -class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed - """Sequence iterator specialized for lists. - """ + def descr_next(self, space): + if self.w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + self.index += 1 + return w_item + + +class W_FastListIterObject(W_AbstractSeqIterObject): + """Sequence iterator specialized for lists.""" + + def descr_next(self, space): + from pypy.objspace.std.listobject import W_ListObject + w_seq = self.w_seq + if w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + assert isinstance(w_seq, W_ListObject) + index = self.index + try: + w_item = w_seq.getitem(index) + except IndexError: + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + class W_FastTupleIterObject(W_AbstractSeqIterObject): """Sequence iterator specialized for tuples, accessing directly @@ -41,87 +109,79 @@ W_AbstractSeqIterObject.__init__(w_self, w_seq) w_self.tupleitems = wrappeditems -class W_ReverseSeqIterObject(W_Object): - from pypy.objspace.std.itertype import reverse_iter_typedef as typedef + def descr_next(self, space): + if self.tupleitems is None: + raise OperationError(space.w_StopIteration, space.w_None) + index = self.index + try: + w_item = self.tupleitems[index] + except IndexError: + self.tupleitems = None + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + +class W_ReverseSeqIterObject(W_Root): def __init__(w_self, space, w_seq, index=-1): w_self.w_seq = w_seq w_self.w_len = space.len(w_seq) w_self.index = space.int_w(w_self.w_len) + index + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.objspace.std.iterobject import W_ReverseSeqIterObject + assert isinstance(self, W_ReverseSeqIterObject) + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('reverseseqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) -registerimplementation(W_SeqIterObject) -registerimplementation(W_FastListIterObject) -registerimplementation(W_FastTupleIterObject) -registerimplementation(W_ReverseSeqIterObject) + def descr_length_hint(self, space): + from pypy.objspace.std.iterobject import W_ReverseSeqIterObject + assert isinstance(self, W_ReverseSeqIterObject) + if self.w_seq is None: + return space.wrap(0) + index = self.index + 1 + w_length = space.len(self.w_seq) + # if length of sequence is less than index :exhaust iterator + if space.is_true(space.gt(space.wrap(self.index), w_length)): + w_len = space.wrap(0) + self.w_seq = None + else: + w_len = space.wrap(index) + if space.is_true(space.lt(w_len, space.wrap(0))): + w_len = space.wrap(0) + return w_len -def iter__SeqIter(space, w_seqiter): - return w_seqiter + def descr_iter(self, space): + return self -def next__SeqIter(space, w_seqiter): - if w_seqiter.w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index += 1 - return w_item + def descr_next(self, space): + if self.w_seq is None or self.index < 0: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + self.index -= 1 + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + return w_item - -def iter__FastTupleIter(space, w_seqiter): - return w_seqiter - -def next__FastTupleIter(space, w_seqiter): - if w_seqiter.tupleitems is None: - raise OperationError(space.w_StopIteration, space.w_None) - index = w_seqiter.index - try: - w_item = w_seqiter.tupleitems[index] - except IndexError: - w_seqiter.tupleitems = None - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__FastListIter(space, w_seqiter): - return w_seqiter - -def next__FastListIter(space, w_seqiter): - from pypy.objspace.std.listobject import W_ListObject - w_seq = w_seqiter.w_seq - if w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - assert isinstance(w_seq, W_ListObject) - index = w_seqiter.index - try: - w_item = w_seq.getitem(index) - except IndexError: - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__ReverseSeqIter(space, w_seqiter): - return w_seqiter - -def next__ReverseSeqIter(space, w_seqiter): - if w_seqiter.w_seq is None or w_seqiter.index < 0: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - w_seqiter.index -= 1 - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - return w_item - -register_all(vars()) +W_ReverseSeqIterObject.typedef = StdTypeDef( + "reversesequenceiterator", + __iter__ = gateway.interp2app(W_ReverseSeqIterObject.descr_iter), + next = gateway.interp2app(W_ReverseSeqIterObject.descr_next), + __reduce__ = gateway.interp2app(W_ReverseSeqIterObject.descr_reduce), + __length_hint__ = gateway.interp2app( + W_ReverseSeqIterObject.descr_length_hint), +) +W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/itertype.py b/pypy/objspace/std/itertype.py deleted file mode 100644 --- a/pypy/objspace/std/itertype.py +++ /dev/null @@ -1,85 +0,0 @@ -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.interpreter.error import OperationError - -# ____________________________________________________________ - -def descr_seqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - - # cpython does not support pickling iterators but stackless python do - #msg = 'Pickling for iterators dissabled as cpython does not support it' - #raise OperationError(space.w_TypeError, space.wrap(msg)) - - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('seqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_seqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - return w_self.getlength(space) - -# ____________________________________________________________ - -def descr_reverseseqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('reverseseqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_reverseseqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - if w_self.w_seq is None: - return space.wrap(0) - index = w_self.index + 1 - w_length = space.len(w_self.w_seq) - # if length of sequence is less than index :exhaust iterator - if space.is_true(space.gt(space.wrap(w_self.index), w_length)): - w_len = space.wrap(0) - w_self.w_seq = None - else: - w_len = space.wrap(index) - if space.is_true(space.lt(w_len, space.wrap(0))): - w_len = space.wrap(0) - return w_len - -# ____________________________________________________________ -iter_typedef = StdTypeDef("sequenceiterator", - __doc__ = '''iter(collection) -> iterator -iter(callable, sentinel) -> iterator - -Get an iterator from an object. In the first form, the argument must -supply its own iterator, or be a sequence. -In the second form, the callable is called until it returns the sentinel.''', - - __reduce__ = gateway.interp2app(descr_seqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_seqiter__length_hint__), - ) -iter_typedef.acceptable_as_base_class = False - -reverse_iter_typedef = StdTypeDef("reversesequenceiterator", - - __reduce__ = gateway.interp2app(descr_reverseseqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_reverseseqiter__length_hint__), - ) -reverse_iter_typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -44,7 +44,6 @@ from pypy.objspace.std.longtype import long_typedef from pypy.objspace.std.unicodetype import unicode_typedef from pypy.objspace.std.nonetype import none_typedef - from pypy.objspace.std.itertype import iter_typedef self.pythontypes = [value for key, value in result.__dict__.items() if not key.startswith('_')] # don't look @@ -81,6 +80,7 @@ self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) + self.pythontypes.append(iterobject.W_AbstractSeqIterObject.typedef) # the set of implementation types self.typeorder = { @@ -95,10 +95,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - iterobject.W_SeqIterObject: [], - iterobject.W_FastListIterObject: [], - iterobject.W_FastTupleIterObject: [], - iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -19,6 +19,7 @@ from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.iterobject import W_AbstractSeqIterObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.longobject import W_LongObject, newlong from pypy.objspace.std.noneobject import W_NoneObject @@ -668,6 +669,8 @@ self._interplevel_classes[self.w_list] = W_ListObject self._interplevel_classes[self.w_set] = W_SetObject self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + self._interplevel_classes[self.w_sequenceiterator] = \ + W_AbstractSeqIterObject @specialize.memo() def _get_interplevel_cls(self, w_type): diff --git a/pypy/objspace/std/test/test_lengthhint.py b/pypy/objspace/std/test/test_lengthhint.py --- a/pypy/objspace/std/test/test_lengthhint.py +++ b/pypy/objspace/std/test/test_lengthhint.py @@ -74,7 +74,7 @@ self._test_length_hint(self.space.wrap(u'Y' * self.SIZE)) def test_tuple(self): - self._test_length_hint(self.space.newtuple(self.ITEMS)) + self._test_length_hint(self.space.wrap(tuple(self.ITEMS))) def test_reversed(self): # test the generic reversed iterator (w_foo lacks __reversed__) diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -21,6 +21,7 @@ OS_NONE = 0 # normal case, no oopspec OS_ARRAYCOPY = 1 # "list.ll_arraycopy" OS_STR2UNICODE = 2 # "str.str2unicode" + OS_SHRINK_ARRAY = 3 # rgc.ll_shrink_array # OS_STR_CONCAT = 22 # "stroruni.concat" OS_STR_SLICE = 23 # "stroruni.slice" @@ -82,8 +83,10 @@ OS_JIT_FORCE_VIRTUAL = 120 # for debugging: - _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, - OS_RAW_MALLOC_VARSIZE_CHAR, OS_JIT_FORCE_VIRTUAL]) + _OS_CANRAISE = set([ + OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, OS_RAW_MALLOC_VARSIZE_CHAR, + OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY, + ]) def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -398,6 +398,8 @@ prepare = self._handle_libffi_call elif oopspec_name.startswith('math.sqrt'): prepare = self._handle_math_sqrt_call + elif oopspec_name.startswith('rgc.'): + prepare = self._handle_rgc_call else: prepare = self.prepare_builtin_call try: @@ -1779,6 +1781,12 @@ return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, EffectInfo.EF_ELIDABLE_CANNOT_RAISE) + def _handle_rgc_call(self, op, oopspec_name, args): + if oopspec_name == 'rgc.ll_shrink_array': + return self._handle_oopspec_call(op, args, EffectInfo.OS_SHRINK_ARRAY, EffectInfo.EF_CAN_RAISE) + else: + raise NotImplementedError(oopspec_name) + def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args descr1 = self.cpu.fielddescrof(v_inst.concretetype.TO, diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -136,6 +136,9 @@ assert size <= MAX_CONST_LEN self._chars = [None] * size + def shrink(self, length): + del self._chars[length:] + def setup_slice(self, longerlist, start, stop): assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] @@ -554,6 +557,9 @@ if oopspecindex == EffectInfo.OS_STR2UNICODE: if self.opt_call_str_STR2UNICODE(op): return + if oopspecindex == EffectInfo.OS_SHRINK_ARRAY: + if self.opt_call_SHRINK_ARRAY(op): + return self.emit_operation(op) optimize_CALL_PURE = optimize_CALL @@ -721,6 +727,19 @@ return True return False + def opt_call_SHRINK_ARRAY(self, op): + v1 = self.getvalue(op.getarg(1)) + v2 = self.getvalue(op.getarg(2)) + # If the index is constant, if the argument is virtual (we only support + # VStringPlainValue for now) we can optimize away the call. + if v2.is_constant() and v1.is_virtual() and isinstance(v1, VStringPlainValue): + length = v2.box.getint() + v1.shrink(length) + self.last_emitted_operation = REMOVED + self.make_equal_to(op.result, v1) + return True + return False + def generate_modified_call(self, oopspecindex, args, result, mode): oopspecindex += mode.OS_offset cic = self.optimizer.metainterp_sd.callinfocollection diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py --- a/rpython/jit/metainterp/test/test_string.py +++ b/rpython/jit/metainterp/test/test_string.py @@ -1,16 +1,14 @@ import py -from rpython.jit.codewriter.policy import StopAtXPolicy -from rpython.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from rpython.jit.metainterp.test.support import LLJitMixin from rpython.rlib.debug import debug_print -from rpython.rlib.jit import JitDriver, dont_look_inside, we_are_jitted,\ - promote_string -from rpython.rlib.rstring import StringBuilder -from rpython.rtyper.ootypesystem import ootype +from rpython.rlib.jit import (JitDriver, dont_look_inside, we_are_jitted, + promote_string) +from rpython.rlib.rstring import StringBuilder, UnicodeBuilder class StringTests: - _str, _chr = str, chr + _str, _chr, _StringBuilder = str, chr, StringBuilder def test_eq_residual(self): _str = self._str @@ -358,7 +356,7 @@ s1 = self.meta_interp(f, []) s2 = f() for c1, c2 in zip(s1.chars, s2): - assert c1==c2 + assert c1 == c2 def test_virtual_strings_boxed(self): _str = self._str @@ -516,6 +514,95 @@ self.meta_interp(f, [0]) self.check_resops(call=7) + def test_join_chars(self): + jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) + _str = self._str + + def f(a, b, c): + i = 0 + while i < 10: + jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) + x = [] + if a: + x.append(_str("a")) + if b: + x.append(_str("b")) + if c: + x.append(_str("c")) + i += len(_str("").join(x)) + return i + res = self.meta_interp(f, [1, 1, 1]) + assert res == f(True, True, True) + # The "".join should be unrolled, since the length of x is known since + # it is virtual, ensure there are no calls to ll_join_chars, or + # allocations. + self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, + 'int_add': 2, 'int_is_true': 3}) + + def test_virtual_copystringcontent(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord(b.build()[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_virtual_copystringcontent2(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord((b.build() + _str("xyz"))[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_bytearray(self): + py.test.skip("implement it") + + def f(i): + b = bytearray("abc") + b[1] = i + return b[1] + + res = self.interp_operations(f, [13]) + assert res == 13 + + def test_shrink_array(self): + jitdriver = JitDriver(reds=['result', 'n'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def f(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(20) + b.append(_str("Testing!")) + result += len(b.build()) + n -= 1 + return result + + res = self.meta_interp(f, [9]) + assert res == f(9) + self.check_resops({ + 'jump': 1, 'guard_true': 2, 'int_ge': 2, 'int_add': 2, 'int_sub': 2 + }) + + #class TestOOtype(StringTests, OOJitMixin): # CALL = "oosend" # CALL_PURE = "oosend_pure" @@ -524,8 +611,9 @@ CALL = "call" CALL_PURE = "call_pure" + class TestLLtypeUnicode(TestLLtype): - _str, _chr = unicode, unichr + _str, _chr, _StringBuilder = unicode, unichr, UnicodeBuilder def test_str2unicode(self): _str = self._str @@ -569,64 +657,3 @@ self.check_resops(call_pure=0, unicodesetitem=0, call=2, newunicode=0, unicodegetitem=0, copyunicodecontent=0) - - def test_join_chars(self): - jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) - def f(a, b, c): - i = 0 - while i < 10: - jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) - x = [] - if a: - x.append("a") - if b: - x.append("b") - if c: - x.append("c") - i += len("".join(x)) - return i - res = self.meta_interp(f, [1, 1, 1]) - assert res == f(True, True, True) - # The "".join should be unrolled, since the length of x is known since - # it is virtual, ensure there are no calls to ll_join_chars, or - # allocations. - self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, - 'int_add': 2, 'int_is_true': 3}) - - def test_virtual_copystringcontent(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord(b.build()[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_virtual_copystringcontent2(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord((b.build() + "xyz")[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_bytearray(self): - py.test.skip("implement it") - def f(i): - b = bytearray("abc") - b[1] = i - return b[1] - - res = self.interp_operations(f, [13]) - assert res == 13 diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py --- a/rpython/rlib/rgc.py +++ b/rpython/rlib/rgc.py @@ -183,6 +183,7 @@ return True return False + @jit.oopspec('list.ll_arraycopy(source, dest, source_start, dest_start, length)') @enforceargs(None, None, int, int, int) @specialize.ll() @@ -229,6 +230,9 @@ keepalive_until_here(source) keepalive_until_here(dest) + + at jit.oopspec('rgc.ll_shrink_array(p, smallerlength)') + at specialize.ll() def ll_shrink_array(p, smallerlength): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import keepalive_until_here @@ -249,16 +253,15 @@ ARRAY = getattr(TP, TP._arrayfld) offset = (llmemory.offsetof(TP, TP._arrayfld) + llmemory.itemoffsetof(ARRAY, 0)) - source_addr = llmemory.cast_ptr_to_adr(p) + offset - dest_addr = llmemory.cast_ptr_to_adr(newp) + offset + source_addr = llmemory.cast_ptr_to_adr(p) + offset + dest_addr = llmemory.cast_ptr_to_adr(newp) + offset llmemory.raw_memcopy(source_addr, dest_addr, llmemory.sizeof(ARRAY.OF) * smallerlength) keepalive_until_here(p) keepalive_until_here(newp) return newp -ll_shrink_array._annspecialcase_ = 'specialize:ll' -ll_shrink_array._jit_look_inside_ = False + def no_collect(func): func._dont_inline_ = True diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py --- a/rpython/rtyper/module/ll_os.py +++ b/rpython/rtyper/module/ll_os.py @@ -682,7 +682,7 @@ @registering_if(os, 'getpid') def register_os_getpid(self): - return self.extdef_for_os_function_returning_int('getpid') + return self.extdef_for_os_function_returning_int('getpid', threadsafe=False) @registering_if(os, 'getgid') def register_os_getgid(self): From noreply at buildbot.pypy.org Thu May 23 01:05:33 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 23 May 2013 01:05:33 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix translation. Message-ID: <20130522230533.6F0AD1C331D@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64495:416ab73a45e1 Date: 2013-05-22 16:04 -0700 http://bitbucket.org/pypy/pypy/changeset/416ab73a45e1/ Log: Fix translation. diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -137,6 +137,7 @@ self._chars = [None] * size def shrink(self, length): + assert length >= 0 del self._chars[length:] def setup_slice(self, longerlist, start, stop): From noreply at buildbot.pypy.org Thu May 23 01:06:27 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 23 May 2013 01:06:27 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged default in Message-ID: <20130522230627.8A3411C331D@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64496:6b35bfdd3fbd Date: 2013-05-22 16:05 -0700 http://bitbucket.org/pypy/pypy/changeset/6b35bfdd3fbd/ Log: merged default in diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -137,6 +137,7 @@ self._chars = [None] * size def shrink(self, length): + assert length >= 0 del self._chars[length:] def setup_slice(self, longerlist, start, stop): From noreply at buildbot.pypy.org Thu May 23 01:41:44 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 01:41:44 +0200 (CEST) Subject: [pypy-commit] pypy default: kill no longer needed asserts, minor cleanup Message-ID: <20130522234144.330611C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64497:e34aedb316d0 Date: 2013-05-22 16:31 -0700 http://bitbucket.org/pypy/pypy/changeset/e34aedb316d0/ Log: kill no longer needed asserts, minor cleanup diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,16 +1,17 @@ """Generic iterator implementations""" -from pypy.interpreter import gateway + from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.gateway import interp2app, interpindirect2app from pypy.interpreter.error import OperationError from pypy.objspace.std.stdtypedef import StdTypeDef class W_AbstractSeqIterObject(W_Root): - def __init__(w_self, w_seq, index=0): + def __init__(self, w_seq, index=0): if index < 0: index = 0 - w_self.w_seq = w_seq - w_self.index = index + self.w_seq = w_seq + self.index = index def getlength(self, space): if self.w_seq is None: @@ -33,8 +34,6 @@ XXX to do: remove this __reduce__ method and do a registration with copy_reg, instead. """ - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(self, W_AbstractSeqIterObject) from pypy.interpreter.mixedmodule import MixedModule w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) @@ -43,8 +42,6 @@ return space.newtuple([new_inst, space.newtuple(tup)]) def descr_length_hint(self, space): - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(self, W_AbstractSeqIterObject) return self.getlength(space) W_AbstractSeqIterObject.typedef = StdTypeDef( @@ -55,12 +52,10 @@ Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.''', - - __iter__ = gateway.interp2app(W_AbstractSeqIterObject.descr_iter), - next = gateway.interpindirect2app(W_AbstractSeqIterObject.descr_next), - __reduce__ = gateway.interp2app(W_AbstractSeqIterObject.descr_reduce), - __length_hint__ = gateway.interp2app( - W_AbstractSeqIterObject.descr_length_hint), + __iter__ = interp2app(W_AbstractSeqIterObject.descr_iter), + next = interpindirect2app(W_AbstractSeqIterObject.descr_next), + __reduce__ = interp2app(W_AbstractSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_AbstractSeqIterObject.descr_length_hint), ) W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False @@ -105,9 +100,9 @@ """Sequence iterator specialized for tuples, accessing directly their RPython-level list of wrapped objects. """ - def __init__(w_self, w_seq, wrappeditems): - W_AbstractSeqIterObject.__init__(w_self, w_seq) - w_self.tupleitems = wrappeditems + def __init__(self, w_seq, wrappeditems): + W_AbstractSeqIterObject.__init__(self, w_seq) + self.tupleitems = wrappeditems def descr_next(self, space): if self.tupleitems is None: @@ -124,18 +119,16 @@ class W_ReverseSeqIterObject(W_Root): - def __init__(w_self, space, w_seq, index=-1): - w_self.w_seq = w_seq - w_self.w_len = space.len(w_seq) - w_self.index = space.int_w(w_self.w_len) + index + def __init__(self, space, w_seq, index=-1): + self.w_seq = w_seq + self.w_len = space.len(w_seq) + self.index = space.int_w(self.w_len) + index def descr_reduce(self, space): """ XXX to do: remove this __reduce__ method and do a registration with copy_reg, instead. """ - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(self, W_ReverseSeqIterObject) from pypy.interpreter.mixedmodule import MixedModule w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) @@ -144,8 +137,6 @@ return space.newtuple([new_inst, space.newtuple(tup)]) def descr_length_hint(self, space): - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(self, W_ReverseSeqIterObject) if self.w_seq is None: return space.wrap(0) index = self.index + 1 @@ -178,10 +169,9 @@ W_ReverseSeqIterObject.typedef = StdTypeDef( "reversesequenceiterator", - __iter__ = gateway.interp2app(W_ReverseSeqIterObject.descr_iter), - next = gateway.interp2app(W_ReverseSeqIterObject.descr_next), - __reduce__ = gateway.interp2app(W_ReverseSeqIterObject.descr_reduce), - __length_hint__ = gateway.interp2app( - W_ReverseSeqIterObject.descr_length_hint), + __iter__ = interp2app(W_ReverseSeqIterObject.descr_iter), + next = interp2app(W_ReverseSeqIterObject.descr_next), + __reduce__ = interp2app(W_ReverseSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_ReverseSeqIterObject.descr_length_hint), ) W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False From noreply at buildbot.pypy.org Thu May 23 01:41:45 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 01:41:45 +0200 (CEST) Subject: [pypy-commit] pypy default: minor cleanup Message-ID: <20130522234145.87DCA1C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64498:91b978e64619 Date: 2013-05-22 16:40 -0700 http://bitbucket.org/pypy/pypy/changeset/91b978e64619/ Log: minor cleanup diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,5 +1,14 @@ +"""The builtin list implementation + +Lists optimize their storage by holding certain primitive datatypes in +unwrapped form. For more information: + +http://morepypy.blogspot.com/2011/10/more-compact-lists-with-list-strategies.html + +""" + import operator -from sys import maxint +import sys from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt @@ -18,11 +27,11 @@ from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject -from pypy.objspace.std.util import negate, get_positive_index -from rpython.rlib import rerased, jit, debug +from pypy.objspace.std.util import get_positive_index, negate +from rpython.rlib import debug, jit, rerased from rpython.rlib.listsort import make_timsort_class -from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) +from rpython.rlib.objectmodel import ( + instantiate, newlist_hint, resizelist_hint, specialize) from rpython.tool.sourcetools import func_with_new_name __all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] @@ -130,26 +139,26 @@ class W_ListObject(W_Root): - def __init__(w_self, space, wrappeditems, sizehint=-1): + + def __init__(self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) - w_self.space = space + self.space = space if space.config.objspace.std.withliststrategies: - w_self.strategy = get_strategy_from_list_objects(space, - wrappeditems, - sizehint) + self.strategy = get_strategy_from_list_objects(space, wrappeditems, + sizehint) else: - w_self.strategy = space.fromcache(ObjectListStrategy) - w_self.init_from_list_w(wrappeditems) + self.strategy = space.fromcache(ObjectListStrategy) + self.init_from_list_w(wrappeditems) @staticmethod def from_storage_and_strategy(space, storage, strategy): - w_self = instantiate(W_ListObject) - w_self.space = space - w_self.strategy = strategy - w_self.lstorage = storage + self = instantiate(W_ListObject) + self.space = space + self.strategy = strategy + self.lstorage = storage if not space.config.objspace.std.withliststrategies: - w_self.switch_to_object_strategy() - return w_self + self.switch_to_object_strategy() + return self @staticmethod def newlist_str(space, list_s): @@ -157,10 +166,10 @@ storage = strategy.erase(list_s) return W_ListObject.from_storage_and_strategy(space, storage, strategy) - def __repr__(w_self): + def __repr__(self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, - w_self.lstorage._x) + return "%s(%s, %s)" % (self.__class__.__name__, self.strategy, + self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -216,7 +225,7 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): + def find(self, w_item, start=0, end=sys.maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) @@ -590,14 +599,14 @@ 'L.remove(value) -- remove first occurrence of value' # needs to be safe against eq_w() mutating the w_list behind our back try: - i = self.find(w_value, 0, maxint) + i = self.find(w_value, 0, sys.maxint) except ValueError: raise OperationError(space.w_ValueError, space.wrap("list.remove(x): x not in list")) if i < self.length(): # otherwise list was mutated self.pop(i) - @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) def descr_index(self, space, w_value, w_start, w_stop): '''L.index(value, [start, [stop]]) -> integer -- return first index of value''' diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -18,18 +18,18 @@ class W_BaseSetObject(W_Root): typedef = None - def __init__(w_self, space, w_iterable=None): + def __init__(self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" - w_self.space = space - set_strategy_and_setdata(space, w_self, w_iterable) + self.space = space + set_strategy_and_setdata(space, self, w_iterable) - def __repr__(w_self): + def __repr__(self): """representation for debugging purposes""" - reprlist = [repr(w_item) for w_item in w_self.getkeys()] - return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist)) + reprlist = [repr(w_item) for w_item in self.getkeys()] + return "<%s(%s)>" % (self.__class__.__name__, ', '.join(reprlist)) - def from_storage_and_strategy(w_self, storage, strategy): - obj = w_self._newobj(w_self.space, None) + def from_storage_and_strategy(self, storage, strategy): + obj = self._newobj(self.space, None) assert isinstance(obj, W_BaseSetObject) obj.strategy = strategy obj.sstorage = storage @@ -501,11 +501,11 @@ class W_SetObject(W_BaseSetObject): - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" - if type(w_self) is W_SetObject: + if type(self) is W_SetObject: return W_SetObject(space, w_iterable) - w_type = space.type(w_self) + w_type = space.type(self) w_obj = space.allocate_instance(W_SetObject, w_type) W_SetObject.__init__(w_obj, space, w_iterable) return w_obj @@ -577,11 +577,11 @@ class W_FrozensetObject(W_BaseSetObject): hash = 0 - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new frozenset by taking ownership of 'w_iterable'.""" - if type(w_self) is W_FrozensetObject: + if type(self) is W_FrozensetObject: return W_FrozensetObject(space, w_iterable) - w_type = space.type(w_self) + w_type = space.type(self) w_obj = space.allocate_instance(W_FrozensetObject, w_type) W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj @@ -1439,9 +1439,9 @@ class W_SetIterObject(W_Root): - def __init__(w_self, space, iterimplementation): - w_self.space = space - w_self.iterimplementation = iterimplementation + def __init__(self, space, iterimplementation): + self.space = space + self.iterimplementation = iterimplementation def descr_length_hint(self, space): return space.wrap(self.iterimplementation.length()) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -14,13 +14,13 @@ def make_specialised_class(typetuple): assert type(typetuple) == tuple - nValues = len(typetuple) - iter_n = unrolling_iterable(range(nValues)) + typelen = len(typetuple) + iter_n = unrolling_iterable(range(typelen)) class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space - assert len(values_w) == nValues + assert len(values_w) == typelen for i in iter_n: w_obj = values_w[i] val_type = typetuple[i] @@ -37,10 +37,10 @@ setattr(self, 'value%s' % i, unwrapped) def length(self): - return nValues + return typelen def tolist(self): - list_w = [None] * nValues + list_w = [None] * typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -54,7 +54,7 @@ def descr_hash(self, space): mult = 1000003 x = 0x345678 - z = nValues + z = typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] == object: @@ -76,7 +76,7 @@ if not isinstance(w_other, W_AbstractTupleObject): return space.w_NotImplemented if not isinstance(w_other, cls): - if nValues != w_other.length(): + if typelen != w_other.length(): return space.w_False for i in iter_n: myval = getattr(self, 'value%s' % i) @@ -102,7 +102,7 @@ def getitem(self, space, index): if index < 0: - index += nValues + index += typelen for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,8 +1,11 @@ +"""The builtin tuple implementation""" + import sys -from pypy.interpreter import gateway + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice @@ -177,8 +180,7 @@ count += 1 return space.wrap(count) - @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), - w_stop=gateway.WrappedDefault(sys.maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) def descr_index(self, space, w_obj, w_start, w_stop): """index(obj, [start, [stop]]) -> first index that obj appears in the From noreply at buildbot.pypy.org Thu May 23 02:09:24 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 02:09:24 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130523000924.3AA981C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64499:34adaf2e34d5 Date: 2013-05-22 16:57 -0700 http://bitbucket.org/pypy/pypy/changeset/34adaf2e34d5/ Log: merge default 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 @@ -31,3 +31,6 @@ .. branch: remove-tuple-smm Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,20 +1,17 @@ """Generic iterator implementations""" + +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.gateway import interp2app, interpindirect2app from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.stdtypedef import StdTypeDef -class W_AbstractIterObject(W_Object): - __slots__ = () - -class W_AbstractSeqIterObject(W_AbstractIterObject): - from pypy.objspace.std.itertype import iter_typedef as typedef - - def __init__(w_self, w_seq, index=0): +class W_AbstractSeqIterObject(W_Root): + def __init__(self, w_seq, index=0): if index < 0: index = 0 - w_self.w_seq = w_seq - w_self.index = index + self.w_seq = w_seq + self.index = index def getlength(self, space): if self.w_seq is None: @@ -26,102 +23,155 @@ w_len = space.wrap(0) return w_len + def descr_iter(self, space): + return self + + def descr_next(self, space): + raise NotImplementedError + + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('seqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) + + def descr_length_hint(self, space): + return self.getlength(space) + +W_AbstractSeqIterObject.typedef = StdTypeDef( + "sequenceiterator", + __doc__ = '''iter(collection) -> iterator +iter(callable, sentinel) -> iterator + +Get an iterator from an object. In the first form, the argument must +supply its own iterator, or be a sequence. +In the second form, the callable is called until it returns the sentinel.''', + __iter__ = interp2app(W_AbstractSeqIterObject.descr_iter), + next = interpindirect2app(W_AbstractSeqIterObject.descr_next), + __reduce__ = interp2app(W_AbstractSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_AbstractSeqIterObject.descr_length_hint), +) +W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False + + class W_SeqIterObject(W_AbstractSeqIterObject): """Sequence iterator implementation for general sequences.""" -class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed - """Sequence iterator specialized for lists. - """ + def descr_next(self, space): + if self.w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + self.index += 1 + return w_item + + +class W_FastListIterObject(W_AbstractSeqIterObject): + """Sequence iterator specialized for lists.""" + + def descr_next(self, space): + from pypy.objspace.std.listobject import W_ListObject + w_seq = self.w_seq + if w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + assert isinstance(w_seq, W_ListObject) + index = self.index + try: + w_item = w_seq.getitem(index) + except IndexError: + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + class W_FastTupleIterObject(W_AbstractSeqIterObject): """Sequence iterator specialized for tuples, accessing directly their RPython-level list of wrapped objects. """ - def __init__(w_self, w_seq, wrappeditems): - W_AbstractSeqIterObject.__init__(w_self, w_seq) - w_self.tupleitems = wrappeditems + def __init__(self, w_seq, wrappeditems): + W_AbstractSeqIterObject.__init__(self, w_seq) + self.tupleitems = wrappeditems -class W_ReverseSeqIterObject(W_Object): - from pypy.objspace.std.itertype import reverse_iter_typedef as typedef + def descr_next(self, space): + if self.tupleitems is None: + raise OperationError(space.w_StopIteration, space.w_None) + index = self.index + try: + w_item = self.tupleitems[index] + except IndexError: + self.tupleitems = None + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item - def __init__(w_self, space, w_seq, index=-1): - w_self.w_seq = w_seq - w_self.w_len = space.len(w_seq) - w_self.index = space.int_w(w_self.w_len) + index +class W_ReverseSeqIterObject(W_Root): + def __init__(self, space, w_seq, index=-1): + self.w_seq = w_seq + self.w_len = space.len(w_seq) + self.index = space.int_w(self.w_len) + index -registerimplementation(W_SeqIterObject) -registerimplementation(W_FastListIterObject) -registerimplementation(W_FastTupleIterObject) -registerimplementation(W_ReverseSeqIterObject) + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('reverseseqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) -def iter__SeqIter(space, w_seqiter): - return w_seqiter + def descr_length_hint(self, space): + if self.w_seq is None: + return space.wrap(0) + index = self.index + 1 + w_length = space.len(self.w_seq) + # if length of sequence is less than index :exhaust iterator + if space.is_true(space.gt(space.wrap(self.index), w_length)): + w_len = space.wrap(0) + self.w_seq = None + else: + w_len = space.wrap(index) + if space.is_true(space.lt(w_len, space.wrap(0))): + w_len = space.wrap(0) + return w_len -def next__SeqIter(space, w_seqiter): - if w_seqiter.w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index += 1 - return w_item + def descr_iter(self, space): + return self + def descr_next(self, space): + if self.w_seq is None or self.index < 0: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + self.index -= 1 + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + return w_item -def iter__FastTupleIter(space, w_seqiter): - return w_seqiter - -def next__FastTupleIter(space, w_seqiter): - if w_seqiter.tupleitems is None: - raise OperationError(space.w_StopIteration, space.w_None) - index = w_seqiter.index - try: - w_item = w_seqiter.tupleitems[index] - except IndexError: - w_seqiter.tupleitems = None - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__FastListIter(space, w_seqiter): - return w_seqiter - -def next__FastListIter(space, w_seqiter): - from pypy.objspace.std.listobject import W_ListObject - w_seq = w_seqiter.w_seq - if w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - assert isinstance(w_seq, W_ListObject) - index = w_seqiter.index - try: - w_item = w_seq.getitem(index) - except IndexError: - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__ReverseSeqIter(space, w_seqiter): - return w_seqiter - -def next__ReverseSeqIter(space, w_seqiter): - if w_seqiter.w_seq is None or w_seqiter.index < 0: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - w_seqiter.index -= 1 - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - return w_item - -register_all(vars()) +W_ReverseSeqIterObject.typedef = StdTypeDef( + "reversesequenceiterator", + __iter__ = interp2app(W_ReverseSeqIterObject.descr_iter), + next = interp2app(W_ReverseSeqIterObject.descr_next), + __reduce__ = interp2app(W_ReverseSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_ReverseSeqIterObject.descr_length_hint), +) +W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/itertype.py b/pypy/objspace/std/itertype.py deleted file mode 100644 --- a/pypy/objspace/std/itertype.py +++ /dev/null @@ -1,85 +0,0 @@ -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.interpreter.error import OperationError - -# ____________________________________________________________ - -def descr_seqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copyreg, instead. - """ - - # cpython does not support pickling iterators but stackless python do - #msg = 'Pickling for iterators dissabled as cpython does not support it' - #raise OperationError(space.w_TypeError, space.wrap(msg)) - - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('seqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_seqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - return w_self.getlength(space) - -# ____________________________________________________________ - -def descr_reverseseqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copyreg, instead. - """ - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('reverseseqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_reverseseqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - if w_self.w_seq is None: - return space.wrap(0) - index = w_self.index + 1 - w_length = space.len(w_self.w_seq) - # if length of sequence is less than index :exhaust iterator - if space.is_true(space.gt(space.wrap(w_self.index), w_length)): - w_len = space.wrap(0) - w_self.w_seq = None - else: - w_len = space.wrap(index) - if space.is_true(space.lt(w_len, space.wrap(0))): - w_len = space.wrap(0) - return w_len - -# ____________________________________________________________ -iter_typedef = StdTypeDef("sequenceiterator", - __doc__ = '''iter(collection) -> iterator -iter(callable, sentinel) -> iterator - -Get an iterator from an object. In the first form, the argument must -supply its own iterator, or be a sequence. -In the second form, the callable is called until it returns the sentinel.''', - - __reduce__ = gateway.interp2app(descr_seqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_seqiter__length_hint__), - ) -iter_typedef.acceptable_as_base_class = False - -reverse_iter_typedef = StdTypeDef("reversesequenceiterator", - - __reduce__ = gateway.interp2app(descr_reverseseqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_reverseseqiter__length_hint__), - ) -reverse_iter_typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,5 +1,14 @@ +"""The builtin list implementation + +Lists optimize their storage by holding certain primitive datatypes in +unwrapped form. For more information: + +http://morepypy.blogspot.com/2011/10/more-compact-lists-with-list-strategies.html + +""" + import operator -from sys import maxint +import sys from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt @@ -18,11 +27,11 @@ from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject -from pypy.objspace.std.util import negate, get_positive_index -from rpython.rlib import rerased, jit, debug +from pypy.objspace.std.util import get_positive_index, negate +from rpython.rlib import debug, jit, rerased from rpython.rlib.listsort import make_timsort_class -from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) +from rpython.rlib.objectmodel import ( + instantiate, newlist_hint, resizelist_hint, specialize) from rpython.tool.sourcetools import func_with_new_name __all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] @@ -133,26 +142,26 @@ class W_ListObject(W_Root): - def __init__(w_self, space, wrappeditems, sizehint=-1): + + def __init__(self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) - w_self.space = space + self.space = space if space.config.objspace.std.withliststrategies: - w_self.strategy = get_strategy_from_list_objects(space, - wrappeditems, - sizehint) + self.strategy = get_strategy_from_list_objects(space, wrappeditems, + sizehint) else: - w_self.strategy = space.fromcache(ObjectListStrategy) - w_self.init_from_list_w(wrappeditems) + self.strategy = space.fromcache(ObjectListStrategy) + self.init_from_list_w(wrappeditems) @staticmethod def from_storage_and_strategy(space, storage, strategy): - w_self = instantiate(W_ListObject) - w_self.space = space - w_self.strategy = strategy - w_self.lstorage = storage + self = instantiate(W_ListObject) + self.space = space + self.strategy = strategy + self.lstorage = storage if not space.config.objspace.std.withliststrategies: - w_self.switch_to_object_strategy() - return w_self + self.switch_to_object_strategy() + return self @staticmethod def newlist_str(space, list_s): @@ -162,10 +171,10 @@ storage = strategy.erase(list_s) return W_ListObject.from_storage_and_strategy(space, storage, strategy) - def __repr__(w_self): + def __repr__(self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, - w_self.lstorage._x) + return "%s(%s, %s)" % (self.__class__.__name__, self.strategy, + self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -221,7 +230,7 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): + def find(self, w_item, start=0, end=sys.maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) @@ -570,14 +579,14 @@ 'L.remove(value) -- remove first occurrence of value' # needs to be safe against eq_w() mutating the w_list behind our back try: - i = self.find(w_value, 0, maxint) + i = self.find(w_value, 0, sys.maxint) except ValueError: raise OperationError(space.w_ValueError, space.wrap("list.remove(x): x not in list")) if i < self.length(): # otherwise list was mutated self.pop(i) - @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) def descr_index(self, space, w_value, w_start, w_stop): '''L.index(value, [start, [stop]]) -> integer -- return first index of value''' diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -43,7 +43,6 @@ from pypy.objspace.std.longtype import long_typedef from pypy.objspace.std.unicodetype import unicode_typedef from pypy.objspace.std.nonetype import none_typedef - from pypy.objspace.std.itertype import iter_typedef self.pythontypes = [value for key, value in result.__dict__.items() if not key.startswith('_')] # don't look @@ -80,6 +79,7 @@ self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) + self.pythontypes.append(iterobject.W_AbstractSeqIterObject.typedef) # the set of implementation types self.typeorder = { @@ -94,10 +94,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - iterobject.W_SeqIterObject: [], - iterobject.W_FastListIterObject: [], - iterobject.W_FastTupleIterObject: [], - iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -20,6 +20,7 @@ from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.iterobject import W_AbstractSeqIterObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.longobject import W_LongObject, newlong from pypy.objspace.std.noneobject import W_NoneObject @@ -698,6 +699,8 @@ self._interplevel_classes[self.w_list] = W_ListObject self._interplevel_classes[self.w_set] = W_SetObject self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + self._interplevel_classes[self.w_sequenceiterator] = \ + W_AbstractSeqIterObject @specialize.memo() def _get_interplevel_cls(self, w_type): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -18,18 +18,18 @@ class W_BaseSetObject(W_Root): typedef = None - def __init__(w_self, space, w_iterable=None): + def __init__(self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" - w_self.space = space - set_strategy_and_setdata(space, w_self, w_iterable) + self.space = space + set_strategy_and_setdata(space, self, w_iterable) - def __repr__(w_self): + def __repr__(self): """representation for debugging purposes""" - reprlist = [repr(w_item) for w_item in w_self.getkeys()] - return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist)) + reprlist = [repr(w_item) for w_item in self.getkeys()] + return "<%s(%s)>" % (self.__class__.__name__, ', '.join(reprlist)) - def from_storage_and_strategy(w_self, storage, strategy): - obj = w_self._newobj(w_self.space, None) + def from_storage_and_strategy(self, storage, strategy): + obj = self._newobj(self.space, None) assert isinstance(obj, W_BaseSetObject) obj.strategy = strategy obj.sstorage = storage @@ -492,7 +492,7 @@ class W_SetObject(W_BaseSetObject): - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" return W_SetObject(space, w_iterable) @@ -562,7 +562,7 @@ class W_FrozensetObject(W_BaseSetObject): hash = 0 - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new frozenset by taking ownership of 'w_iterable'.""" return W_FrozensetObject(space, w_iterable) @@ -1418,9 +1418,9 @@ class W_SetIterObject(W_Root): - def __init__(w_self, space, iterimplementation): - w_self.space = space - w_self.iterimplementation = iterimplementation + def __init__(self, space, iterimplementation): + self.space = space + self.iterimplementation = iterimplementation def descr_length_hint(self, space): return space.wrap(self.iterimplementation.length()) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -14,13 +14,13 @@ def make_specialised_class(typetuple): assert type(typetuple) == tuple - nValues = len(typetuple) - iter_n = unrolling_iterable(range(nValues)) + typelen = len(typetuple) + iter_n = unrolling_iterable(range(typelen)) class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space - assert len(values_w) == nValues + assert len(values_w) == typelen for i in iter_n: w_obj = values_w[i] val_type = typetuple[i] @@ -37,10 +37,10 @@ setattr(self, 'value%s' % i, unwrapped) def length(self): - return nValues + return typelen def tolist(self): - list_w = [None] * nValues + list_w = [None] * typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -54,7 +54,7 @@ def descr_hash(self, space): mult = 1000003 x = 0x345678 - z = nValues + z = typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] == object: @@ -76,7 +76,7 @@ if not isinstance(w_other, W_AbstractTupleObject): return space.w_NotImplemented if not isinstance(w_other, cls): - if nValues != w_other.length(): + if typelen != w_other.length(): return space.w_False for i in iter_n: myval = getattr(self, 'value%s' % i) @@ -102,7 +102,7 @@ def getitem(self, space, index): if index < 0: - index += nValues + index += typelen for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) diff --git a/pypy/objspace/std/test/test_lengthhint.py b/pypy/objspace/std/test/test_lengthhint.py --- a/pypy/objspace/std/test/test_lengthhint.py +++ b/pypy/objspace/std/test/test_lengthhint.py @@ -80,7 +80,7 @@ self._test_length_hint(self.space.wrap('P' * self.SIZE)) def test_tuple(self): - self._test_length_hint(self.space.newtuple(self.ITEMS)) + self._test_length_hint(self.space.wrap(tuple(self.ITEMS))) def test_reversed(self): # test the generic reversed iterator (w_foo lacks __reversed__) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,8 +1,11 @@ +"""The builtin tuple implementation""" + import sys -from pypy.interpreter import gateway + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice @@ -174,8 +177,7 @@ count += 1 return space.wrap(count) - @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), - w_stop=gateway.WrappedDefault(sys.maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) def descr_index(self, space, w_obj, w_start, w_stop): """index(obj, [start, [stop]]) -> first index that obj appears in the diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -21,6 +21,7 @@ OS_NONE = 0 # normal case, no oopspec OS_ARRAYCOPY = 1 # "list.ll_arraycopy" OS_STR2UNICODE = 2 # "str.str2unicode" + OS_SHRINK_ARRAY = 3 # rgc.ll_shrink_array # OS_STR_CONCAT = 22 # "stroruni.concat" OS_STR_SLICE = 23 # "stroruni.slice" @@ -82,8 +83,10 @@ OS_JIT_FORCE_VIRTUAL = 120 # for debugging: - _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, - OS_RAW_MALLOC_VARSIZE_CHAR, OS_JIT_FORCE_VIRTUAL]) + _OS_CANRAISE = set([ + OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, OS_RAW_MALLOC_VARSIZE_CHAR, + OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY, + ]) def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -398,6 +398,8 @@ prepare = self._handle_libffi_call elif oopspec_name.startswith('math.sqrt'): prepare = self._handle_math_sqrt_call + elif oopspec_name.startswith('rgc.'): + prepare = self._handle_rgc_call else: prepare = self.prepare_builtin_call try: @@ -1779,6 +1781,12 @@ return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, EffectInfo.EF_ELIDABLE_CANNOT_RAISE) + def _handle_rgc_call(self, op, oopspec_name, args): + if oopspec_name == 'rgc.ll_shrink_array': + return self._handle_oopspec_call(op, args, EffectInfo.OS_SHRINK_ARRAY, EffectInfo.EF_CAN_RAISE) + else: + raise NotImplementedError(oopspec_name) + def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args descr1 = self.cpu.fielddescrof(v_inst.concretetype.TO, diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -136,6 +136,10 @@ assert size <= MAX_CONST_LEN self._chars = [None] * size + def shrink(self, length): + assert length >= 0 + del self._chars[length:] + def setup_slice(self, longerlist, start, stop): assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] @@ -554,6 +558,9 @@ if oopspecindex == EffectInfo.OS_STR2UNICODE: if self.opt_call_str_STR2UNICODE(op): return + if oopspecindex == EffectInfo.OS_SHRINK_ARRAY: + if self.opt_call_SHRINK_ARRAY(op): + return self.emit_operation(op) optimize_CALL_PURE = optimize_CALL @@ -721,6 +728,19 @@ return True return False + def opt_call_SHRINK_ARRAY(self, op): + v1 = self.getvalue(op.getarg(1)) + v2 = self.getvalue(op.getarg(2)) + # If the index is constant, if the argument is virtual (we only support + # VStringPlainValue for now) we can optimize away the call. + if v2.is_constant() and v1.is_virtual() and isinstance(v1, VStringPlainValue): + length = v2.box.getint() + v1.shrink(length) + self.last_emitted_operation = REMOVED + self.make_equal_to(op.result, v1) + return True + return False + def generate_modified_call(self, oopspecindex, args, result, mode): oopspecindex += mode.OS_offset cic = self.optimizer.metainterp_sd.callinfocollection diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py --- a/rpython/jit/metainterp/test/test_string.py +++ b/rpython/jit/metainterp/test/test_string.py @@ -1,16 +1,14 @@ import py -from rpython.jit.codewriter.policy import StopAtXPolicy -from rpython.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from rpython.jit.metainterp.test.support import LLJitMixin from rpython.rlib.debug import debug_print -from rpython.rlib.jit import JitDriver, dont_look_inside, we_are_jitted,\ - promote_string -from rpython.rlib.rstring import StringBuilder -from rpython.rtyper.ootypesystem import ootype +from rpython.rlib.jit import (JitDriver, dont_look_inside, we_are_jitted, + promote_string) +from rpython.rlib.rstring import StringBuilder, UnicodeBuilder class StringTests: - _str, _chr = str, chr + _str, _chr, _StringBuilder = str, chr, StringBuilder def test_eq_residual(self): _str = self._str @@ -358,7 +356,7 @@ s1 = self.meta_interp(f, []) s2 = f() for c1, c2 in zip(s1.chars, s2): - assert c1==c2 + assert c1 == c2 def test_virtual_strings_boxed(self): _str = self._str @@ -516,6 +514,95 @@ self.meta_interp(f, [0]) self.check_resops(call=7) + def test_join_chars(self): + jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) + _str = self._str + + def f(a, b, c): + i = 0 + while i < 10: + jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) + x = [] + if a: + x.append(_str("a")) + if b: + x.append(_str("b")) + if c: + x.append(_str("c")) + i += len(_str("").join(x)) + return i + res = self.meta_interp(f, [1, 1, 1]) + assert res == f(True, True, True) + # The "".join should be unrolled, since the length of x is known since + # it is virtual, ensure there are no calls to ll_join_chars, or + # allocations. + self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, + 'int_add': 2, 'int_is_true': 3}) + + def test_virtual_copystringcontent(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord(b.build()[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_virtual_copystringcontent2(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord((b.build() + _str("xyz"))[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_bytearray(self): + py.test.skip("implement it") + + def f(i): + b = bytearray("abc") + b[1] = i + return b[1] + + res = self.interp_operations(f, [13]) + assert res == 13 + + def test_shrink_array(self): + jitdriver = JitDriver(reds=['result', 'n'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def f(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(20) + b.append(_str("Testing!")) + result += len(b.build()) + n -= 1 + return result + + res = self.meta_interp(f, [9]) + assert res == f(9) + self.check_resops({ + 'jump': 1, 'guard_true': 2, 'int_ge': 2, 'int_add': 2, 'int_sub': 2 + }) + + #class TestOOtype(StringTests, OOJitMixin): # CALL = "oosend" # CALL_PURE = "oosend_pure" @@ -524,8 +611,9 @@ CALL = "call" CALL_PURE = "call_pure" + class TestLLtypeUnicode(TestLLtype): - _str, _chr = unicode, unichr + _str, _chr, _StringBuilder = unicode, unichr, UnicodeBuilder def test_str2unicode(self): _str = self._str @@ -569,64 +657,3 @@ self.check_resops(call_pure=0, unicodesetitem=0, call=2, newunicode=0, unicodegetitem=0, copyunicodecontent=0) - - def test_join_chars(self): - jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) - def f(a, b, c): - i = 0 - while i < 10: - jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) - x = [] - if a: - x.append("a") - if b: - x.append("b") - if c: - x.append("c") - i += len("".join(x)) - return i - res = self.meta_interp(f, [1, 1, 1]) - assert res == f(True, True, True) - # The "".join should be unrolled, since the length of x is known since - # it is virtual, ensure there are no calls to ll_join_chars, or - # allocations. - self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, - 'int_add': 2, 'int_is_true': 3}) - - def test_virtual_copystringcontent(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord(b.build()[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_virtual_copystringcontent2(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord((b.build() + "xyz")[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_bytearray(self): - py.test.skip("implement it") - def f(i): - b = bytearray("abc") - b[1] = i - return b[1] - - res = self.interp_operations(f, [13]) - assert res == 13 diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py --- a/rpython/rlib/rgc.py +++ b/rpython/rlib/rgc.py @@ -183,6 +183,7 @@ return True return False + @jit.oopspec('list.ll_arraycopy(source, dest, source_start, dest_start, length)') @enforceargs(None, None, int, int, int) @specialize.ll() @@ -229,6 +230,9 @@ keepalive_until_here(source) keepalive_until_here(dest) + + at jit.oopspec('rgc.ll_shrink_array(p, smallerlength)') + at specialize.ll() def ll_shrink_array(p, smallerlength): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import keepalive_until_here @@ -249,16 +253,15 @@ ARRAY = getattr(TP, TP._arrayfld) offset = (llmemory.offsetof(TP, TP._arrayfld) + llmemory.itemoffsetof(ARRAY, 0)) - source_addr = llmemory.cast_ptr_to_adr(p) + offset - dest_addr = llmemory.cast_ptr_to_adr(newp) + offset + source_addr = llmemory.cast_ptr_to_adr(p) + offset + dest_addr = llmemory.cast_ptr_to_adr(newp) + offset llmemory.raw_memcopy(source_addr, dest_addr, llmemory.sizeof(ARRAY.OF) * smallerlength) keepalive_until_here(p) keepalive_until_here(newp) return newp -ll_shrink_array._annspecialcase_ = 'specialize:ll' -ll_shrink_array._jit_look_inside_ = False + def no_collect(func): func._dont_inline_ = True diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py --- a/rpython/rtyper/module/ll_os.py +++ b/rpython/rtyper/module/ll_os.py @@ -682,7 +682,7 @@ @registering_if(os, 'getpid') def register_os_getpid(self): - return self.extdef_for_os_function_returning_int('getpid') + return self.extdef_for_os_function_returning_int('getpid', threadsafe=False) @registering_if(os, 'getgid') def register_os_getgid(self): From noreply at buildbot.pypy.org Thu May 23 02:09:26 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 02:09:26 +0200 (CEST) Subject: [pypy-commit] pypy py3k: next -> __next__ Message-ID: <20130523000926.9C7C01C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64500:86c5e0dd59e9 Date: 2013-05-22 17:03 -0700 http://bitbucket.org/pypy/pypy/changeset/86c5e0dd59e9/ Log: next -> __next__ diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -53,7 +53,7 @@ supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.''', __iter__ = interp2app(W_AbstractSeqIterObject.descr_iter), - next = interpindirect2app(W_AbstractSeqIterObject.descr_next), + __next__ = interpindirect2app(W_AbstractSeqIterObject.descr_next), __reduce__ = interp2app(W_AbstractSeqIterObject.descr_reduce), __length_hint__ = interp2app(W_AbstractSeqIterObject.descr_length_hint), ) @@ -170,7 +170,7 @@ W_ReverseSeqIterObject.typedef = StdTypeDef( "reversesequenceiterator", __iter__ = interp2app(W_ReverseSeqIterObject.descr_iter), - next = interp2app(W_ReverseSeqIterObject.descr_next), + __next__ = interp2app(W_ReverseSeqIterObject.descr_next), __reduce__ = interp2app(W_ReverseSeqIterObject.descr_reduce), __length_hint__ = interp2app(W_ReverseSeqIterObject.descr_length_hint), ) From noreply at buildbot.pypy.org Thu May 23 02:09:28 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 02:09:28 +0200 (CEST) Subject: [pypy-commit] pypy py3k: 2to3 Message-ID: <20130523000928.298191C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64501:1d61aefe7ef0 Date: 2013-05-22 17:03 -0700 http://bitbucket.org/pypy/pypy/changeset/1d61aefe7ef0/ Log: 2to3 diff --git a/lib-python/3/distutils/unixccompiler.py b/lib-python/3/distutils/unixccompiler.py --- a/lib-python/3/distutils/unixccompiler.py +++ b/lib-python/3/distutils/unixccompiler.py @@ -134,7 +134,7 @@ executables['ranlib'] = ["ranlib"] executables['linker_so'] += ['-undefined', 'dynamic_lookup'] - for k, v in executables.iteritems(): + for k, v in executables.items(): if v and v[0] == 'cc': v += ['-arch', arch] From noreply at buildbot.pypy.org Thu May 23 02:09:29 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 02:09:29 +0200 (CEST) Subject: [pypy-commit] pypy py3k: skip when _testcapi ImportErrors Message-ID: <20130523000929.934CF1C0328@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64502:17f84dc7e269 Date: 2013-05-22 17:06 -0700 http://bitbucket.org/pypy/pypy/changeset/17f84dc7e269/ Log: skip when _testcapi ImportErrors diff --git a/lib-python/3/importlib/test/extension/test_case_sensitivity.py b/lib-python/3/importlib/test/extension/test_case_sensitivity.py --- a/lib-python/3/importlib/test/extension/test_case_sensitivity.py +++ b/lib-python/3/importlib/test/extension/test_case_sensitivity.py @@ -9,6 +9,7 @@ @util.case_insensitive_tests class ExtensionModuleCaseSensitivityTest(unittest.TestCase): + @ext_util.skip_unless__testcapi def find_module(self): good_name = ext_util.NAME bad_name = good_name.upper() From noreply at buildbot.pypy.org Thu May 23 02:30:16 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Thu, 23 May 2013 02:30:16 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: Don't construct a long object just to throw it away (this is a backpor tof a change in python3) Message-ID: <20130523003016.A2EF61C0328@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64503:9ab42b7860b2 Date: 2013-05-22 17:01 -0700 http://bitbucket.org/pypy/pypy/changeset/9ab42b7860b2/ Log: Don't construct a long object just to throw it away (this is a backpor tof a change in python3) diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py --- a/lib-python/2.7/logging/__init__.py +++ b/lib-python/2.7/logging/__init__.py @@ -277,7 +277,7 @@ self.lineno = lineno self.funcName = func self.created = ct - self.msecs = (ct - long(ct)) * 1000 + self.msecs = (ct - int(ct)) * 1000 self.relativeCreated = (self.created - _startTime) * 1000 if logThreads and thread: self.thread = thread.get_ident() From noreply at buildbot.pypy.org Thu May 23 03:15:10 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 23 May 2013 03:15:10 +0200 (CEST) Subject: [pypy-commit] pypy remove-string-smm: Remove unnecessary import that broke tests. Message-ID: <20130523011510.262421C331D@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-string-smm Changeset: r64505:ceaa6984b4aa Date: 2013-05-22 22:31 +0200 http://bitbucket.org/pypy/pypy/changeset/ceaa6984b4aa/ Log: Remove unnecessary import that broke tests. diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -6,7 +6,6 @@ from pypy.objspace.std.contiguousstring import StringMethods from pypy.objspace.std.formatting import mod_format from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.model import registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject From noreply at buildbot.pypy.org Thu May 23 03:15:08 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 23 May 2013 03:15:08 +0200 (CEST) Subject: [pypy-commit] pypy remove-string-smm: hg merge default Message-ID: <20130523011508.9D7B71C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-string-smm Changeset: r64504:2cf31bc28ed5 Date: 2013-05-22 22:28 +0200 http://bitbucket.org/pypy/pypy/changeset/2cf31bc28ed5/ Log: hg merge default diff too long, truncating to 2000 out of 8576 lines diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -7,7 +7,8 @@ import subprocess from copy import copy, deepcopy -from test.test_support import run_unittest, TESTFN, unlink, get_attribute +from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, + import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -236,7 +237,10 @@ def test_get_config_h_filename(self): config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -121,12 +121,10 @@ __import__(name) except (ImportError, CompilationError, py.test.skip.Exception), e: errcls = e.__class__.__name__ - config.add_warning( + raise Exception( "The module %r is disabled\n" % (modname,) + "because importing %s raised %s\n" % (name, errcls) + str(e)) - raise ConflictConfigError("--withmod-%s: %s" % (modname, - errcls)) return validator else: return None @@ -217,10 +215,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), @@ -365,6 +359,7 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0.1`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0.1`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,46 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -22,3 +22,15 @@ .. branch: remove-dict-smm Remove multi-methods on dict + +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -10,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -120,6 +122,17 @@ source = rffi.charp2str(ll_source) return _pypy_execute_source(source) + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() + w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), space.builtin_modules['__builtin__']) @@ -137,6 +150,8 @@ return 0 return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, 'pypy_setup_home': pypy_setup_home} def call_finish(space): diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -853,9 +853,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -864,6 +865,37 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists/sets of constants in the context of "in"/"not in". + + lists are folded into tuples, sets into frozensets, otherwise + returns False + """ + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -973,3 +973,30 @@ counts = self.count_instructions(source3) assert counts[ops.BUILD_LIST] == 1 assert ops.BUILD_LIST_FROM_ARG not in counts + + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts 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 @@ -903,24 +903,35 @@ expected_path = [str(prefix.join(subdir).ensure(dir=1)) for subdir in ('lib_pypy', 'lib-python/%s' % cpy_ver)] + # an empty directory from where we can't find the stdlib + tmp_dir = str(udir.join('tmp').ensure(dir=1)) self.w_goal_dir = self.space.wrap(goal_dir) self.w_fake_exe = self.space.wrap(str(fake_exe)) self.w_expected_path = self.space.wrap(expected_path) self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir)) + self.w_tmp_dir = self.space.wrap(tmp_dir) + foo_py = prefix.join('foo.py').write("pass") self.w_foo_py = self.space.wrap(str(foo_py)) def test_setup_bootstrap_path(self): - import sys + # Check how sys.path is handled depending on if we can find a copy of + # the stdlib in setup_bootstrap_path. + import sys, os old_sys_path = sys.path[:] + old_cwd = os.getcwd() + sys.path.append(self.goal_dir) + # make sure cwd does not contain a stdlib + os.chdir(self.tmp_dir) + tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c') try: import app_main - app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found + app_main.setup_bootstrap_path(tmp_pypy_c) # stdlib not found assert sys.executable == '' - assert sys.path == old_sys_path + assert sys.path == old_sys_path + [self.goal_dir] app_main.setup_bootstrap_path(self.fake_exe) assert sys.executable == self.fake_exe @@ -933,6 +944,7 @@ assert newpath[:len(self.expected_path)] == self.expected_path finally: sys.path[:] = old_sys_path + os.chdir(old_cwd) def test_trunk_can_be_prefix(self): import sys diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -936,6 +936,21 @@ output = s.getvalue() assert "LOAD_GLOBAL" not in output + def test_folding_of_list_constants(self): + source = 'a in [1, 2, 3]' + co = compile(source, '', 'exec') + i = co.co_consts.index((1, 2, 3)) + assert i > -1 + assert isinstance(co.co_consts[i], tuple) + + def test_folding_of_set_constants(self): + source = 'a in {1, 2, 3}' + co = compile(source, '', 'exec') + i = co.co_consts.index(set([1, 2, 3])) + assert i > -1 + assert isinstance(co.co_consts[i], frozenset) + + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} 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 @@ -7,7 +7,7 @@ appleveldefs = { } interpleveldefs = { - '__version__': 'space.wrap("0.6")', + '__version__': 'space.wrap("0.7")', 'load_library': 'libraryobj.load_library', @@ -30,6 +30,8 @@ 'typeoffsetof': 'func.typeoffsetof', 'rawaddressof': 'func.rawaddressof', 'getcname': 'func.getcname', + 'newp_handle': 'handle.newp_handle', + 'from_handle': 'handle.from_handle', '_get_types': 'func._get_types', 'string': 'func.string', diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -394,6 +394,19 @@ return self.length +class W_CDataHandle(W_CData): + _attrs_ = ['w_keepalive'] + _immutable_fields_ = ['w_keepalive'] + + def __init__(self, space, cdata, ctype, w_keepalive): + W_CData.__init__(self, space, cdata, ctype) + self.w_keepalive = w_keepalive + + def _repr_extra(self): + w_repr = self.space.repr(self.w_keepalive) + return "handle to %s" % (self.space.str_w(w_repr),) + + W_CData.typedef = TypeDef( 'CData', __module__ = '_cffi_backend', 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 @@ -172,8 +172,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = ['is_file', 'cache_array_type'] - _immutable_fields_ = ['is_file', 'cache_array_type?'] + _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr'] + _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr'] kind = "pointer" cache_array_type = None @@ -186,6 +186,7 @@ extra = " *" self.is_file = (ctitem.name == "struct _IO_FILE" or ctitem.name == "struct $FILE") + self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid) W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/handle.py @@ -0,0 +1,93 @@ +import weakref +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import unwrap_spec +from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj +from pypy.module._weakref.interp__weakref import dead_ref +from rpython.rtyper.lltypesystem import lltype, rffi + + +def reduced_value(s): + while True: + divide = s & 1 + s >>= 1 + if not divide: + return s + +# ____________________________________________________________ + + +class CffiHandles: + def __init__(self, space): + self.handles = [] + self.look_distance = 0 + + def reserve_next_handle_index(self): + # The reservation ordering done here is tweaked for pypy's + # memory allocator. We look from index 'look_distance'. + # Look_distance increases from 0. But we also look at + # "look_distance/2" or "/4" or "/8", etc. If we find that one + # of these secondary locations is free, we assume it's because + # there was recently a minor collection; so we reset + # look_distance to 0 and start again from the lowest locations. + length = len(self.handles) + for d in range(self.look_distance, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + s = reduced_value(d) + if self.handles[s]() is None: + break + # restart from the beginning + for d in range(0, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + # full! extend, but don't use '!=' here + self.handles = self.handles + [dead_ref] * (length // 3 + 5) + self.look_distance = length + 1 + return length + + def store_handle(self, index, content): + self.handles[index] = weakref.ref(content) + + def fetch_handle(self, index): + if 0 <= index < len(self.handles): + return self.handles[index]() + return None + +def get(space): + return space.fromcache(CffiHandles) + +# ____________________________________________________________ + + at unwrap_spec(w_ctype=ctypeobj.W_CType) +def newp_handle(space, w_ctype, w_x): + if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or + not w_ctype.is_void_ptr): + raise operationerrfmt(space.w_TypeError, + "needs 'void *', got '%s'", w_ctype.name) + index = get(space).reserve_next_handle_index() + _cdata = rffi.cast(rffi.CCHARP, index + 1) + new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x) + get(space).store_handle(index, new_cdataobj) + return new_cdataobj + + at 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): + raise operationerrfmt(space.w_TypeError, + "expected a 'cdata' object with a 'void *' out " + "of new_handle(), got '%s'", ctype.name) + index = rffi.cast(lltype.Signed, w_cdata._cdata) + original_cdataobj = get(space).fetch_handle(index - 1) + # + if isinstance(original_cdataobj, cdataobj.W_CDataHandle): + return original_cdataobj.w_keepalive + else: + if index == 0: + msg = "cannot use from_handle() on NULL pointer" + else: + msg = "'void *' value does not correspond to any object" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) 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 @@ -2732,6 +2732,32 @@ assert x != cast(BIntP, 12344) assert hash(x) == hash(cast(BIntP, 12345)) +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + + def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.6" + assert __version__ == "0.7" diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/test/test_handle.py @@ -0,0 +1,59 @@ +import random +from pypy.module._cffi_backend.handle import CffiHandles, reduced_value + + +def test_reduced_value(): + assert reduced_value(0) == 0 + assert reduced_value(1) == 0 + assert reduced_value(2) == 1 + assert reduced_value(3) == 0 + assert reduced_value(4) == 2 + assert reduced_value(5) == 1 + assert reduced_value(6) == 3 + assert reduced_value(7) == 0 + assert reduced_value(8) == 4 + assert reduced_value(9) == 2 + assert reduced_value(10) == 5 + assert reduced_value(11) == 1 + + +class PseudoWeakRef(object): + _content = 42 + + def __call__(self): + return self._content + + +def test_cffi_handles_1(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + assert len(ch.handles) < 13500 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr + +def test_cffi_handles_2(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + # + if len(expected_content) > 20: + r = random.choice(list(expected_content)) + pwr = expected_content.pop(r) + pwr._content = None + # + assert len(ch.handles) < 100 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -232,9 +232,9 @@ import _rawffi # this should return *all* loaded libs, dlopen(NULL) dll = _rawffi.CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.ptr('Py_IsInitialized', [], 'l')() - assert res[0] == 1 + func = dll.ptr('rand', [], 'i') + res = func() + assert res[0] != 0 def test_libc_load(self): import _rawffi diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") 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 @@ -344,7 +344,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1, external=False) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -70,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: @@ -324,6 +324,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): @@ -356,13 +357,13 @@ self.strides = strides self.backstrides = backstrides self.shape = shape + if dtype is None: + dtype = parent.dtype if isinstance(parent, SliceArray): parent = parent.parent # one level only self.parent = parent self.storage = parent.storage self.order = parent.order - if dtype is None: - dtype = parent.dtype self.dtype = dtype self.size = support.product(shape) * self.dtype.itemtype.get_element_size() self.start = start diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,14 +268,30 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) @@ -373,7 +389,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,12 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -78,7 +84,8 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) @@ -111,8 +118,15 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -279,15 +293,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -333,10 +354,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +390,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +428,8 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,10 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + if self.ptr_size == 8: + assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + else: + assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype def test_pickle_record(self): @@ -723,7 +726,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -778,6 +781,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -790,6 +794,27 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2699,6 +2701,56 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array, zeros + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) + + def test_multidim_subarray(self): + from numpypy import dtype, array + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1684,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1696,10 +1699,68 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + items_w = space.fixedview(w_items) + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if space.len_w(shape) <= 1: + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + for w_item in items_w: + self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) + ofs += size + return arr + + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + # TODO: Make sure the shape and the array match + items_w = space.fixedview(w_items) + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if len(shape) <= 1: + for i in range(len(items_w)): + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + for w_item in items_w: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + self._coerce(space, arr, ofs, dtype, w_item, shape[1:]) + ofs += size + + def coerce(self, space, dtype, w_items): + arr = VoidBoxStorage(self.size, dtype) + self._coerce(space, arr, 0, dtype, w_items, dtype.shape) + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + + def readarray(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, + dtype.shape, arr, W_NDimArray(arr), dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1733,7 +1794,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -487,6 +487,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -586,7 +587,6 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=<.*>) i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -44,6 +44,7 @@ # gc_id call is hoisted out of the loop, the id of a value obviously # can't change ;) assert loop.match_by_id("getitem", """ + ... i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...) ... p33 = getinteriorfield_gc(p31, i26, descr=>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -36,7 +36,7 @@ assert loop0.match(expected) # XXX: The retracing fails to form a loop since j # becomes constant 0 after the bridge and constant 1 at the end of the - # loop. A bridge back to the peramble is produced instead. + # loop. A bridge back to the peramble is produced instead. #assert loop1.match(expected) def test_factorial(self): @@ -242,6 +242,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) + guard_not_invalidated(descr=...) i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -9,8 +9,8 @@ # ____________________________________________________________ - at unwrap_spec(w_depth = WrappedDefault(0)) -def _getframe(space, w_depth): + at unwrap_spec(depth=int) +def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default @@ -18,7 +18,6 @@ This function should be used for internal and specialized purposes only.""" - depth = space.int_w(w_depth) if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -7,7 +7,6 @@ from pypy.objspace.std.bytearraytype import ( makebytearraydata_w, new_bytearray, W_AbstractBytearrayObject) from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.listobject import get_list_index from pypy.objspace.std.model import registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.register_all import register_all @@ -403,19 +402,25 @@ w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): + if space.isinstance_w(w_prefix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_prefix)]) + return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + w_start, w_stop) + w_prefix = space.wrap(space.bufferstr_new_w(w_prefix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) -def str_startswith__Bytearray_Tuple_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): - w_str = str__Bytearray(space, w_bytearray) - w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in - space.unpackiterable(w_prefix)]) - return stringobject.str_startswith__String_Tuple_ANY_ANY(space, w_str, w_prefix, - w_start, w_stop) - def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): + if space.isinstance_w(w_suffix, space.w_tuple): + w_str = str__Bytearray(space, w_bytearray) + w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in + space.fixedview(w_suffix)]) + return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) w_str = str__Bytearray(space, w_bytearray) return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, @@ -585,7 +590,7 @@ _setitem_slice_helper(space, w_bytearray.data, start, step, slicelength, sequence2, empty_elem='\x00') def delitem__Bytearray_ANY(space, w_bytearray, w_idx): - idx = get_list_index(space, w_idx) + idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray index") try: del w_bytearray.data[idx] except IndexError: diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -1,14 +1,16 @@ -from pypy.interpreter import gateway from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import ( + WrappedDefault, applevel, interp2app, unwrap_spec) from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.signature import Signature from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import negate -from rpython.rlib import rerased, jit +from rpython.rlib import jit, rerased from rpython.rlib.debug import mark_dict_non_null -from rpython.rlib.objectmodel import r_dict, specialize, newlist_hint -from rpython.tool.sourcetools import func_with_new_name +from rpython.rlib.objectmodel import newlist_hint, r_dict, specialize +from rpython.tool.sourcetools import func_renamer, func_with_new_name UNROLL_CUTOFF = 5 @@ -18,7 +20,7 @@ return space.is_w(space.type(w_key), space.w_str) def _never_equal_to_string(space, w_lookup_type): - """ Handles the case of a non string key lookup. + """Handles the case of a non string key lookup. Types that have a sane hash/eq function should allow us to return True directly to signal that the key is not in the dict in any case. XXX The types should provide such a flag. """ @@ -32,7 +34,7 @@ @specialize.call_location() def w_dict_unrolling_heuristic(w_dct): - """ In which cases iterating over dict items can be unrolled. + """In which cases iterating over dict items can be unrolled. Note that w_dct is an instance of W_DictMultiObject, not necesarilly an actual dict """ @@ -40,24 +42,11 @@ w_dct.length() <= UNROLL_CUTOFF) -def negate(f): - def _negator(self, space, w_other): - # no need to use space.is_ / space.not_ - tmp = f(self, space, w_other) - if tmp is space.w_NotImplemented: - return space.w_NotImplemented - elif tmp is space.w_False: - return space.w_True - else: - return space.w_False - _negator.func_name = 'negate-%s' % f.func_name - return _negator - class W_DictMultiObject(W_Root): @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, - instance=False, strdict=False, kwargs=False): - + instance=False, strdict=False, + kwargs=False): if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy assert w_type is None @@ -67,11 +56,9 @@ elif space.config.objspace.std.withmapdict and instance: from pypy.objspace.std.mapdict import MapDictStrategy strategy = space.fromcache(MapDictStrategy) - elif instance or strdict or module: assert w_type is None strategy = space.fromcache(StringDictStrategy) - elif kwargs: assert w_type is None from pypy.objspace.std.kwargsdict import EmptyKwargsDictStrategy @@ -92,7 +79,7 @@ self.dstorage = storage def __repr__(w_self): - """ representation for debugging purposes """ + """representation for debugging purposes""" return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): @@ -105,12 +92,10 @@ def missing_method(w_dict, space, w_key): if not space.is_w(space.type(w_dict), space.w_dict): - w_missing = space.lookup(w_dict, "__missing__") - if w_missing is None: - return None - return space.get_and_call_function(w_missing, w_dict, w_key) - else: - return None + w_missing = space.lookup(w_dict, '__missing__') + if w_missing is not None: + return space.get_and_call_function(w_missing, w_dict, w_key) + return None def initialize_content(w_self, list_pairs_w): for w_k, w_v in list_pairs_w: @@ -163,7 +148,7 @@ if self.length() != w_other.length(): return space.w_False iteratorimplementation = self.iteritems() - while 1: + while True: w_key, w_val = iteratorimplementation.next_item() if w_key is None: break @@ -240,7 +225,8 @@ space.raise_key_error(w_key) def descr_reversed(self, space): - raise OperationError(space.w_TypeError, space.wrap('argument to reversed() must be a sequence')) + raise OperationError(space.w_TypeError, space.wrap( + 'argument to reversed() must be a sequence')) def descr_copy(self, space): """D.copy() -> a shallow copy of D""" @@ -292,16 +278,13 @@ """D.clear() -> None. Remove all items from D.""" self.clear() - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_get(self, space, w_key, w_default): """D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.""" w_value = self.getitem(w_key) - if w_value is not None: - return w_value - else: - return w_default + return w_value if w_value is not None else w_default - @gateway.unwrap_spec(defaults_w='args_w') + @unwrap_spec(defaults_w='args_w') def descr_pop(self, space, w_key, defaults_w): """D.pop(k[,d]) -> v, remove specified key and return the corresponding value\nIf key is not found, d is returned if given, @@ -332,7 +315,7 @@ space.wrap("popitem(): dictionary is empty")) return space.newtuple([w_key, w_value]) - @gateway.unwrap_spec(w_default=gateway.WrappedDefault(None)) + @unwrap_spec(w_default=WrappedDefault(None)) def descr_setdefault(self, space, w_key, w_default): """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D""" return self.setdefault(w_key, w_default) @@ -364,7 +347,7 @@ _add_indirections() -app = gateway.applevel(''' +app = applevel(''' def dictrepr(currently_in_repr, d): if len(d) == 0: return "{}" @@ -400,46 +383,46 @@ d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)''', - __new__ = gateway.interp2app(W_DictMultiObject.descr_new), - fromkeys = gateway.interp2app(W_DictMultiObject.descr_fromkeys, - as_classmethod=True), + __new__ = interp2app(W_DictMultiObject.descr_new), + fromkeys = interp2app(W_DictMultiObject.descr_fromkeys, + as_classmethod=True), __hash__ = None, - __repr__ = gateway.interp2app(W_DictMultiObject.descr_repr), - __init__ = gateway.interp2app(W_DictMultiObject.descr_init), + __repr__ = interp2app(W_DictMultiObject.descr_repr), + __init__ = interp2app(W_DictMultiObject.descr_init), - __eq__ = gateway.interp2app(W_DictMultiObject.descr_eq), - __ne__ = gateway.interp2app(W_DictMultiObject.descr_ne), - __lt__ = gateway.interp2app(W_DictMultiObject.descr_lt), - __le__ = gateway.interp2app(W_DictMultiObject.descr_le), - __gt__ = gateway.interp2app(W_DictMultiObject.descr_gt), - __ge__ = gateway.interp2app(W_DictMultiObject.descr_ge), + __eq__ = interp2app(W_DictMultiObject.descr_eq), + __ne__ = interp2app(W_DictMultiObject.descr_ne), + __lt__ = interp2app(W_DictMultiObject.descr_lt), + __le__ = interp2app(W_DictMultiObject.descr_le), + __gt__ = interp2app(W_DictMultiObject.descr_gt), From noreply at buildbot.pypy.org Thu May 23 03:15:11 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Thu, 23 May 2013 03:15:11 +0200 (CEST) Subject: [pypy-commit] pypy remove-string-smm: Kill XXXs on imports. Message-ID: <20130523011511.A25D51C0328@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-string-smm Changeset: r64506:eb42aa593e38 Date: 2013-05-23 00:01 +0200 http://bitbucket.org/pypy/pypy/changeset/eb42aa593e38/ Log: Kill XXXs on imports. diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -12,12 +12,12 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.stringobject import string_escape_encode -from pypy.objspace.std.unicodeobject import W_UnicodeObject # XXX: kill this whem SMMs are dead -from pypy.objspace.std.noneobject import W_NoneObject # XXX: and this one. -from pypy.objspace.std.stringobject import W_StringObject # XXX: and this too. -from pypy.objspace.std.tupleobject import W_TupleObject # XXX: ... -from pypy.objspace.std.intobject import W_IntObject # XXX: ... -from pypy.objspace.std.sliceobject import W_SliceObject # XXX: WTF. +from pypy.objspace.std.unicodeobject import W_UnicodeObject +from pypy.objspace.std.noneobject import W_NoneObject +from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.sliceobject import W_SliceObject class W_BytearrayObject(W_AbstractBytearrayObject): From noreply at buildbot.pypy.org Thu May 23 03:38:52 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 23 May 2013 03:38:52 +0200 (CEST) Subject: [pypy-commit] pypy py3k: list.__radd__ is now gone thanks to MM removal Message-ID: <20130523013852.4EDA91C331E@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64507:878788fa042a Date: 2013-05-22 18:37 -0700 http://bitbucket.org/pypy/pypy/changeset/878788fa042a/ Log: list.__radd__ is now gone thanks to MM removal diff --git a/lib-python/3/test/test_descrtut.py b/lib-python/3/test/test_descrtut.py --- a/lib-python/3/test/test_descrtut.py +++ b/lib-python/3/test/test_descrtut.py @@ -188,7 +188,6 @@ '__mul__', '__ne__', '__new__', - '__radd__', '__reduce__', '__reduce_ex__', '__repr__', From noreply at buildbot.pypy.org Thu May 23 13:17:09 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 23 May 2013 13:17:09 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: reseting token on call_assembler is no longer legal - it can be whatever really Message-ID: <20130523111709.5E2701C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64508:bfc2ad83198e Date: 2013-05-23 13:16 +0200 http://bitbucket.org/pypy/pypy/changeset/bfc2ad83198e/ Log: reseting token on call_assembler is no longer legal - it can be whatever really diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1156,16 +1156,6 @@ pmc.B_offs(self.mc.currpos(), c.EQ) return pos - def _call_assembler_reset_vtoken(self, jd, vloc): - from rpython.jit.backend.llsupport.descr import FieldDescr - fielddescr = jd.vable_token_descr - assert isinstance(fielddescr, FieldDescr) - ofs = fielddescr.offset - tmploc = self._regalloc.get_scratch_reg(INT) - self.mov_loc_loc(vloc, r.ip) - self.mc.MOV_ri(tmploc.value, 0) - self.mc.STR_ri(tmploc.value, r.ip.value, ofs) - def _call_assembler_load_result(self, op, result_loc): if op.result is not None: # load the return value from (tmploc, 0) diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -902,7 +902,6 @@ # res = CALL assembler_call_helper(pframe) # jmp @done # @fastpath: - # RESET_VABLE # res = GETFIELD(pframe, 'result') # @done: # @@ -922,24 +921,6 @@ vable = lltype.nullptr(llmemory.GCREF.TO) # # Emulate the fast path - def reset_vable(jd, vable): - if jd.index_of_virtualizable != -1: - fielddescr = jd.vable_token_descr - NULL = lltype.nullptr(llmemory.GCREF.TO) - self.cpu.bh_setfield_gc(vable, NULL, fielddescr) - faildescr = self.cpu.get_latest_descr(pframe) - if faildescr == self.cpu.done_with_this_frame_descr_int: - reset_vable(jd, vable) - return self.cpu.get_int_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_ref: - reset_vable(jd, vable) - return self.cpu.get_ref_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_float: - reset_vable(jd, vable) - return self.cpu.get_float_value(pframe, 0) - elif faildescr == self.cpu.done_with_this_frame_descr_void: - reset_vable(jd, vable) - return None # assembler_helper_ptr = jd.assembler_helper_adr.ptr # fish try: 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 @@ -228,11 +228,8 @@ jmp_location = self._call_assembler_patch_je(result_loc, je_location) - # Path B: fast path. Must load the return value, and reset the token + # Path B: fast path. Must load the return value - # Reset the vable token --- XXX really too much special logic here:-( - if jd.index_of_virtualizable >= 0: - self._call_assembler_reset_vtoken(jd, vloc) # self._call_assembler_load_result(op, result_loc) # diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1951,15 +1951,6 @@ # return jmp_location - def _call_assembler_reset_vtoken(self, jd, vloc): - from rpython.jit.backend.llsupport.descr import FieldDescr - fielddescr = jd.vable_token_descr - assert isinstance(fielddescr, FieldDescr) - vtoken_ofs = fielddescr.offset - self.mc.MOV(edx, vloc) # we know vloc is on the current frame - self.mc.MOV_mi((edx.value, vtoken_ofs), 0) - # in the line above, TOKEN_NONE = 0 - def _call_assembler_load_result(self, op, result_loc): if op.result is not None: # load the return value from the dead frame's value index 0 diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -857,10 +857,6 @@ def assembler_call_helper(deadframe, virtualizableref): fail_descr = self.cpu.get_latest_descr(deadframe) - if vinfo is not None: - virtualizable = lltype.cast_opaque_ptr( - vinfo.VTYPEPTR, virtualizableref) - vinfo.reset_vable_token(virtualizable) try: fail_descr.handle_fail(deadframe, self.metainterp_sd, jd) except jitexc.JitException, e: From noreply at buildbot.pypy.org Thu May 23 13:18:25 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 23 May 2013 13:18:25 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: no longer used Message-ID: <20130523111825.B42D01C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64509:88092ee8c322 Date: 2013-05-23 13:17 +0200 http://bitbucket.org/pypy/pypy/changeset/88092ee8c322/ Log: no longer used diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py --- a/rpython/jit/metainterp/virtualizable.py +++ b/rpython/jit/metainterp/virtualizable.py @@ -220,10 +220,6 @@ return lltype.cast_opaque_ptr(VTYPEPTR, virtualizable) self.cast_gcref_to_vtype = cast_gcref_to_vtype - def reset_vable_token(virtualizable): - virtualizable.vable_token = TOKEN_NONE - self.reset_vable_token = reset_vable_token - def clear_vable_token(virtualizable): virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: From noreply at buildbot.pypy.org Thu May 23 13:29:23 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 23 May 2013 13:29:23 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: we're not supposed to touch anything between guard_not_forced and finish' Message-ID: <20130523112923.BFEB51C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64510:266af5b37bc6 Date: 2013-05-23 13:27 +0200 http://bitbucket.org/pypy/pypy/changeset/266af5b37bc6/ Log: we're not supposed to touch anything between guard_not_forced and finish' diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -2274,10 +2274,10 @@ # in case the force_token has not been recorded, record it here # to make sure we know the virtualizable can be broken. However, the # contents of the virtualizable should be generally correct - self.generate_guard(rop.GUARD_NOT_FORCED, None) self.history.record(rop.FORCE_TOKEN, [], force_token_box) self.history.record(rop.SETFIELD_GC, [vbox, force_token_box], None, descr=vinfo.vable_token_descr) + self.generate_guard(rop.GUARD_NOT_FORCED, None) def compile_exit_frame_with_exception(self, valuebox): self.store_token_in_vable() From noreply at buildbot.pypy.org Thu May 23 13:39:21 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 23 May 2013 13:39:21 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: merge default Message-ID: <20130523113921.483961C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64511:e2daec7825a5 Date: 2013-05-23 13:38 +0200 http://bitbucket.org/pypy/pypy/changeset/e2daec7825a5/ Log: merge default diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -364,8 +364,6 @@ # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] - if config.translation.platform == 'arm' and '_continuation' in modules: - modules.remove('_continuation') config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -25,3 +25,6 @@ .. branch: remove-list-smm-2 Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,12 +124,14 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - os_thread.setup_threads(space) - rffi.aroundstate.before() + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - rthread.gc_thread_start() + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -9,8 +9,8 @@ # ____________________________________________________________ - at unwrap_spec(w_depth = WrappedDefault(0)) -def _getframe(space, w_depth): + at unwrap_spec(depth=int) +def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is given, return the frame object that many calls below the top of the stack. If that is deeper than the call stack, ValueError is raised. The default @@ -18,7 +18,6 @@ This function should be used for internal and specialized purposes only.""" - depth = space.int_w(w_depth) if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -663,6 +663,15 @@ class2type[base] = w_type self._interplevel_classes[w_type] = base + # register other things + from pypy.objspace.std.dictmultiobject import W_DictMultiObject + from pypy.objspace.std.listobject import W_ListObject + from pypy.objspace.std.setobject import W_SetObject + + self._interplevel_classes[self.w_dict] = W_DictMultiObject + self._interplevel_classes[self.w_list] = W_ListObject + self._interplevel_classes[self.w_set] = W_SetObject + @specialize.memo() def _get_interplevel_cls(self, w_type): if not hasattr(self, "_interplevel_classes"): diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -3,6 +3,8 @@ from rpython.config.config import ChoiceOption, StrOption, Config from rpython.config.config import ConfigError from rpython.config.support import detect_number_of_processors +from rpython.jit.backend.detect_cpu import autodetect +from rpython.jit.backend.detect_cpu import MODEL_X86, MODEL_X86_NO_SSE2, MODEL_X86_64 DEFL_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() # and just small enough to prevend inlining of some rlist functions. @@ -12,10 +14,13 @@ DEFL_LOW_INLINE_THRESHOLD = DEFL_INLINE_THRESHOLD / 2.0 DEFL_GC = "minimark" -if sys.platform.startswith("linux"): - DEFL_ROOTFINDER_WITHJIT = "asmgcc" + +_is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) + +if sys.platform.startswith("linux") and _is_x86: + DEFL_ROOTFINDER = "asmgcc" else: - DEFL_ROOTFINDER_WITHJIT = "shadowstack" + DEFL_ROOTFINDER = "shadowstack" IS_64_BITS = sys.maxint > 2147483647 @@ -89,7 +94,7 @@ ChoiceOption("gcrootfinder", "Strategy for finding GC Roots (framework GCs only)", ["n/a", "shadowstack", "asmgcc"], - "shadowstack", + DEFL_ROOTFINDER, cmdline="--gcrootfinder", requires={ "shadowstack": [("translation.gctransformer", "framework")], @@ -112,7 +117,7 @@ BoolOption("jit", "generate a JIT", default=False, suggests=[("translation.gc", DEFL_GC), - ("translation.gcrootfinder", DEFL_ROOTFINDER_WITHJIT), + ("translation.gcrootfinder", DEFL_ROOTFINDER), ("translation.list_comprehension_operations", True)]), ChoiceOption("jit_backend", "choose the backend for the JIT", ["auto", "x86", "x86-without-sse2", 'arm'], @@ -276,7 +281,9 @@ ]), ChoiceOption("platform", "target platform", ['host'] + PLATFORMS, default='host', - cmdline='--platform'), + cmdline='--platform', + requires={"arm": [("translation.gcrootfinder", "shadowstack")]}, + suggests={"arm": [("translation.jit_backend", "arm")]}), ]) diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1066,9 +1066,10 @@ @arguments("box", "orgpc") def opimpl_raise(self, exc_value_box, orgpc): # xxx hack - clsbox = self.cls_of_box(exc_value_box) - self.metainterp.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], - resumepc=orgpc) + if not self.metainterp.heapcache.is_class_known(exc_value_box): + clsbox = self.cls_of_box(exc_value_box) + self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], + resumepc=orgpc) self.metainterp.class_of_last_exc_is_const = True self.metainterp.last_exc_value_box = exc_value_box self.metainterp.popframe() @@ -1890,7 +1891,9 @@ self.staticdata.warmrunnerdesc.hooks.on_abort(reason, jd_sd.jitdriver, greenkey, - jd_sd.warmstate.get_location_str(greenkey)) + jd_sd.warmstate.get_location_str(greenkey), + self.staticdata.logger_ops._make_log_operations(), + self.history.operations) self.staticdata.stats.aborted() def blackhole_if_trace_too_long(self): diff --git a/rpython/jit/metainterp/test/test_jitiface.py b/rpython/jit/metainterp/test/test_jitiface.py --- a/rpython/jit/metainterp/test/test_jitiface.py +++ b/rpython/jit/metainterp/test/test_jitiface.py @@ -7,18 +7,20 @@ from rpython.rtyper.annlowlevel import hlstr from rpython.jit.metainterp.jitprof import Profiler + class JitHookInterfaceTests(object): # !!!note!!! - don't subclass this from the backend. Subclass the LL # class later instead def test_abort_quasi_immut(self): reasons = [] - + class MyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): assert jitdriver is myjitdriver assert len(greenkey) == 1 reasons.append(reason) assert greenkey_repr == 'blah' + assert len(operations) > 1 iface = MyJitIface() @@ -27,8 +29,10 @@ class Foo: _immutable_fields_ = ['a?'] + def __init__(self, a): self.a = a + def f(a, x): foo = Foo(a) total = 0 @@ -47,7 +51,7 @@ def test_on_compile(self): called = [] - + class MyJitIface(JitHookInterface): def after_compile(self, di): called.append(("compile", di.greenkey[1].getint(), diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -5,8 +5,6 @@ from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rstring import StringBuilder -import py - class TestLLtype(LLJitMixin): def test_dont_record_repeated_guard_class(self): @@ -628,3 +626,22 @@ res = self.interp_operations(fn, [0]) assert res == 1 self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0) + + def test_raise_known_class_no_guard_class(self): + def raise_exc(cls): + raise cls + + def fn(n): + if n: + cls = ValueError + else: + cls = TypeError + try: + raise_exc(cls) + except ValueError: + return -1 + return n + + res = self.interp_operations(fn, [1]) + assert res == -1 + self.check_operations_history(guard_class=0) diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py --- a/rpython/jit/metainterp/virtualizable.py +++ b/rpython/jit/metainterp/virtualizable.py @@ -234,6 +234,10 @@ self.tracing_before_residual_call = tracing_before_residual_call def tracing_after_residual_call(virtualizable): + """ + Returns whether or not the virtualizable was forced during a + CALL_MAY_FORCE. + """ virtualizable = cast_gcref_to_vtype(virtualizable) if virtualizable.vable_token: # not modified by the residual call; assert that it is still diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -926,7 +926,7 @@ of JIT running like JIT loops compiled, aborts etc. An instance of this class will be available as policy.jithookiface. """ - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): """ A hook called each time a loop is aborted with jitdriver and greenkey where it started, reason is a string why it got aborted """ diff --git a/rpython/rlib/jit_hooks.py b/rpython/rlib/jit_hooks.py --- a/rpython/rlib/jit_hooks.py +++ b/rpython/rlib/jit_hooks.py @@ -1,11 +1,10 @@ +from rpython.annotator import model as annmodel +from rpython.rlib.objectmodel import specialize +from rpython.rtyper.annlowlevel import (cast_instance_to_base_ptr, + cast_base_ptr_to_instance, llstr) +from rpython.rtyper.extregistry import ExtRegistryEntry +from rpython.rtyper.lltypesystem import llmemory, lltype, rclass -from rpython.rtyper.extregistry import ExtRegistryEntry -from rpython.annotator import model as annmodel -from rpython.rtyper.lltypesystem import llmemory, lltype -from rpython.rtyper.lltypesystem import rclass -from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr,\ - cast_base_ptr_to_instance, llstr -from rpython.rlib.objectmodel import specialize def register_helper(s_result): def wrapper(helper): diff --git a/rpython/tool/error.py b/rpython/tool/error.py --- a/rpython/tool/error.py +++ b/rpython/tool/error.py @@ -2,11 +2,15 @@ """ error handling features, just a way of displaying errors """ -from rpython.tool.ansi_print import ansi_log -from rpython.flowspace.model import Variable import sys import py + +from rpython.flowspace.model import Variable +from rpython.rlib import jit +from rpython.tool.ansi_print import ansi_log + + log = py.log.Producer("error") py.log.setconsumer("error", ansi_log) @@ -14,7 +18,8 @@ SHOW_ANNOTATIONS = True SHOW_DEFAULT_LINES_OF_CODE = 0 -def source_lines1(graph, block, operindex=None, offset=None, long=False, \ + +def source_lines1(graph, block, operindex=None, offset=None, long=False, show_lines_of_code=SHOW_DEFAULT_LINES_OF_CODE): if block is not None: if block is graph.returnblock: @@ -32,23 +37,24 @@ else: if block is None or not block.operations: return [] + def toline(operindex): return offset2lineno(graph.func.func_code, block.operations[operindex].offset) if operindex is None: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) if not long: return ['?'] here = None else: operline = toline(operindex) if long: - linerange = (toline(0), toline(-1)) + linerange = (toline(0), toline(-1)) here = operline else: linerange = (operline, operline) here = None lines = ["Happened at file %s line %d" % (graph.filename, here or linerange[0]), ""] - for n in range(max(0, linerange[0]-show_lines_of_code), \ + for n in range(max(0, linerange[0]-show_lines_of_code), min(linerange[1]+1+show_lines_of_code, len(graph_lines)+graph.startline)): if n == here: prefix = '==> ' @@ -136,6 +142,7 @@ from rpython.translator.tool.pdbplus import PdbPlusShow from rpython.translator.driver import log t = drv.translator + class options: huge = 100 @@ -161,6 +168,7 @@ pdb_plus_show.start(tb) + at jit.elidable def offset2lineno(c, stopat): tab = c.co_lnotab line = c.co_firstlineno @@ -170,4 +178,4 @@ if addr > stopat: break line = line + ord(tab[i+1]) - return line \ No newline at end of file + return line diff --git a/rpython/translator/c/src/stacklet/slp_platformselect.h b/rpython/translator/c/src/stacklet/slp_platformselect.h --- a/rpython/translator/c/src/stacklet/slp_platformselect.h +++ b/rpython/translator/c/src/stacklet/slp_platformselect.h @@ -8,6 +8,8 @@ #include "switch_x86_64_gcc.h" /* gcc on amd64 */ #elif defined(__GNUC__) && defined(__i386__) #include "switch_x86_gcc.h" /* gcc on X86 */ +#elif defined(__GNUC__) && defined(__arm__) +#include "switch_arm_gcc.h" /* gcc on arm */ #else #error "Unsupported platform!" #endif diff --git a/rpython/translator/c/src/stacklet/switch_arm_gcc.h b/rpython/translator/c/src/stacklet/switch_arm_gcc.h new file mode 100644 --- /dev/null +++ b/rpython/translator/c/src/stacklet/switch_arm_gcc.h @@ -0,0 +1,40 @@ + +static void __attribute__((optimize("O3"))) *slp_switch(void *(*save_state)(void*, void*), + void *(*restore_state)(void*, void*), + void *extra) +{ + void *result; + __asm__ volatile ( + "mov r3, %[save_state]\n" + /* save values in calee saved registers for later */ + "mov r4, %[restore_state]\n" + "mov r5, %[extra]\n" + "mov r0, sp\n" /* arg 1: current (old) stack pointer */ + "mov r1, r5\n" /* arg 2: extra */ + "blx r3\n" /* call save_state() */ + + /* skip the rest if the return value is null */ + "cmp r0, #0\n" + "beq zero\n" + + "mov sp, r0\n" /* change the stack pointer */ + + /* From now on, the stack pointer is modified, but the content of the + stack is not restored yet. It contains only garbage here. */ + "mov r1, r5\n" /* arg 2: extra */ + /* arg 1: current (new) stack pointer is already in r0*/ + "blx r4\n" /* call restore_state() */ + + /* The stack's content is now restored. */ + "zero:\n" + "mov %[result], r0\n" + + : [result]"=r"(result) /* output variables */ + /* input variables */ + : [restore_state]"r"(restore_state), + [save_state]"r"(save_state), + [extra]"r"(extra) + : "lr", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r13" + ); + return result; +} From noreply at buildbot.pypy.org Thu May 23 14:09:21 2013 From: noreply at buildbot.pypy.org (fijal) Date: Thu, 23 May 2013 14:09:21 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: if we're in the middle of handle-async-forcing then we cannot really Message-ID: <20130523120921.B84471C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64512:e521b3b40fe5 Date: 2013-05-23 14:08 +0200 http://bitbucket.org/pypy/pypy/changeset/e521b3b40fe5/ Log: if we're in the middle of handle-async-forcing then we cannot really have a virtualizable in an odd state - it should be normal diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1068,8 +1068,8 @@ # xxx hack if not self.metainterp.heapcache.is_class_known(exc_value_box): clsbox = self.cls_of_box(exc_value_box) - self.generate_guard(rop.GUARD_CLASS, exc_value_box, [clsbox], - resumepc=orgpc) + self.metainterp.generate_guard(rop.GUARD_CLASS, exc_value_box, + [clsbox], resumepc=orgpc) self.metainterp.class_of_last_exc_is_const = True self.metainterp.last_exc_value_box = exc_value_box self.metainterp.popframe() diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -1218,8 +1218,7 @@ virtualizable = self.decode_ref(numb.nums[index]) if self.resume_after_guard_not_forced == 1: # in the middle of handle_async_forcing() - if not vinfo.is_token_nonnull_gcref(virtualizable): - raise AlreadyForced + assert vinfo.is_token_nonnull_gcref(virtualizable) vinfo.reset_token_gcref(virtualizable) else: # just jumped away from assembler (case 4 in the comment in From noreply at buildbot.pypy.org Thu May 23 16:44:47 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:47 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed line-endings in SPyVM>>#print:-primitive implementation Message-ID: <20130523144447.E27411C094F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r403:454209dcb8dc Date: 2013-05-22 14:56 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/454209dcb8dc/ Log: fixed line-endings in SPyVM>>#print:-primitive implementation diff --git a/spyvm/plugins/vmdebugging.py b/spyvm/plugins/vmdebugging.py --- a/spyvm/plugins/vmdebugging.py +++ b/spyvm/plugins/vmdebugging.py @@ -32,5 +32,5 @@ def debugPrint(interp, s_frame, w_rcvr, w_string): if not isinstance(w_string, model.W_BytesObject): raise error.PrimitiveFailedError() - print w_string.as_string() + print w_string.as_string().replace('\r', '\n') return w_rcvr From noreply at buildbot.pypy.org Thu May 23 16:44:49 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:49 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added FilePlugin preparations and named primitive: primitiveDirectoryDelimitor Message-ID: <20130523144449.0B2A51C3321@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r404:3c2b0be2fb6c Date: 2013-05-22 14:58 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/3c2b0be2fb6c/ Log: added FilePlugin preparations and named primitive: primitiveDirectoryDelimitor diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py new file mode 100644 --- /dev/null +++ b/spyvm/plugins/fileplugin.py @@ -0,0 +1,12 @@ +from spyvm import model, error +from spyvm.plugins.plugin import Plugin +from spyvm.primitives import PrimitiveFailedError + + +FilePlugin = Plugin() + + + at FilePlugin.expose_primitive(unwrap_spec=[object]) +def primitiveDirectoryDelimitor(interp, s_frame, w_rcvr): + import os + return interp.space.wrap_char(os.path.sep) diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -834,6 +834,9 @@ elif signature[0] == "SocketPlugin": from spyvm.plugins.socket import SocketPlugin return SocketPlugin.call(signature[1], interp, s_frame, argcount, s_method) + elif signature[0] == "FilePlugin": + from spyvm.plugins.fileplugin import FilePlugin + return FilePlugin.call(signature[1], interp, s_frame, argcount, s_method) elif signature[0] == "VMDebugging": from spyvm.plugins.vmdebugging import DebuggingPlugin return DebuggingPlugin.call(signature[1], interp, s_frame, argcount, s_method) From noreply at buildbot.pypy.org Thu May 23 16:44:53 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:53 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added message-wise debugging when commenting in debugging() at the end of interpreter.py. Message-ID: <20130523144453.CAB871C3326@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r408:50d994dd37ff Date: 2013-05-23 10:48 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/50d994dd37ff/ Log: added message-wise debugging when commenting in debugging() at the end of interpreter.py. we miss a skip... added named-primitive collecting the same way diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -847,3 +847,87 @@ Interpreter.step = bytecode_step_translated +# Smalltalk debugging facilities, patching Interpreter and ContextPartShadow +# in order to enable tracing/jumping for message sends etc. +def debugging(): + def stepping_debugger_init(original): + def meth(self, space, image=None, image_name="", trace=False, + max_stack_depth=constants.MAX_LOOP_DEPTH): + return_value = original(self, space, image=image, + image_name=image_name, trace=trace, + max_stack_depth=max_stack_depth) + # ############################################################## + + self.message_stepping = False + self.halt_on_failing_primitives = False + + # ############################################################## + return return_value + return meth + + Interpreter.__init__ = stepping_debugger_init(Interpreter.__init__) + + def stepping_debugger_send(original): + """When interp.message_stepping is True, we halt on every call of ContextPartShadow._sendSelector. + The method is not called for bytecode message sends (see constants.SPECIAL_SELECTORS)""" + def meth(self, w_selector, argcount, interp, + receiver, receiverclassshadow): + if interp.message_stepping: + if argcount == 0: + print "-> %s %s" % (receiver.as_repr_string(), + w_selector.as_string()) + elif argcount == 1: + print "-> %s %s %s" % (receiver.as_repr_string(), + w_selector.as_string(), + self.peek(0).as_repr_string()) + else: + print "-> %s %s %r" % (receiver.as_repr_string(), + w_selector.as_string(), + [self.peek(argcount-1-i) for i in range(argcount)]) + import pdb; pdb.set_trace() + return original(self, w_selector, argcount, interp, receiver, receiverclassshadow) + return meth + + ContextPartShadow._sendSelector = stepping_debugger_send(ContextPartShadow._sendSelector) + + def stepping_debugger_failed_primitive_halt(original): + def meth(self, code, interp, argcount, s_method, w_selector): + try: + original(self, code, interp, argcount, s_method, w_selector) + except primitives.PrimitiveFailedError, e: + if interp.halt_on_failing_primitives: + func = primitives.prim_holder.prim_table[code] + if func.func_name != 'raise_failing_default' and code != 83: + import pdb; pdb.set_trace() + try: + func(interp, self, argcount, s_method) # will fail again + except primitives.PrimitiveFailedError: + pass + raise e + return meth + + ContextPartShadow._call_primitive = stepping_debugger_failed_primitive_halt(ContextPartShadow._call_primitive) + + def trace_missing_named_primitives(original): + def meth(interp, s_frame, argcount, s_method=None): + try: + return original(interp, s_frame, argcount, s_method=s_method) + except primitives.PrimitiveFailedError, e: + space = interp.space + w_description = s_method.w_self().literalat0(space, 1) + if not isinstance(w_description, model.W_PointersObject) or w_description.size() < 2: + raise e + w_modulename = w_description.at0(space, 0) + w_functionname = w_description.at0(space, 1) + if not (isinstance(w_modulename, model.W_BytesObject) and + isinstance(w_functionname, model.W_BytesObject)): + raise e + signature = (w_modulename.as_string(), w_functionname.as_string()) + debugging.missing_named_primitives.add(signature) + raise e + return meth + + primitives.prim_table[primitives.EXTERNAL_CALL] = trace_missing_named_primitives(primitives.prim_table[primitives.EXTERNAL_CALL]) + debugging.missing_named_primitives = set() + +# debugging() From noreply at buildbot.pypy.org Thu May 23 16:44:54 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:54 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed whitespaces in fileplugin Message-ID: <20130523144454.EB2CB1C3327@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r409:2974eb121e5a Date: 2013-05-23 10:49 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/2974eb121e5a/ Log: fixed whitespaces in fileplugin moved import-statement to the top diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -1,3 +1,4 @@ +import os from spyvm import model, error from spyvm.plugins.plugin import Plugin from spyvm.primitives import PrimitiveFailedError, index1_0 @@ -7,28 +8,26 @@ @FilePlugin.expose_primitive(unwrap_spec=[object]) def primitiveDirectoryDelimitor(interp, s_frame, w_rcvr): - import os return interp.space.wrap_char(os.path.sep) @FilePlugin.expose_primitive(unwrap_spec=[object, str, index1_0]) def primitiveDirectoryLookup(interp, s_frame, w_file_directory, full_path, index): - import os - print full_path - if full_path == '': - contents = os.listdir(os.path.sep) - else: - if not os.path.isdir(full_path): - raise PrimitiveFailedError - contents = os.listdir(full_path) - space = interp.space - if index >= len(contents): - return space.w_nil - name = sorted(contents)[index] - file_path = os.path.join(full_path, name) - assert os.path.exists(file_path) - creationTime = space.wrap_int(0) - modificationTime = space.wrap_int(0) - dirFlag = space.w_true if os.path.isdir(file_path) else space.w_false - fileSize = space.wrap_int(os.path.getsize(file_path)) - return space.wrap_list([space.wrap_string(name), creationTime, modificationTime, dirFlag, fileSize]) + if full_path == '': + contents = os.listdir(os.path.sep) + else: + if not os.path.isdir(full_path): + raise PrimitiveFailedError + contents = os.listdir(full_path) + space = interp.space + if index >= len(contents): + return space.w_nil + py_name = sorted(contents)[index] + file_path = os.path.join(full_path, py_name) + assert os.path.exists(file_path) + name = space.wrap_string(py_name) + creationTime = space.wrap_int(0) + modificationTime = space.wrap_int(0) + dirFlag = space.w_true if os.path.isdir(file_path) else space.w_false + fileSize = space.wrap_int(os.path.getsize(file_path)) + return space.wrap_list([name, creationTime, modificationTime, dirFlag, fileSize]) From noreply at buildbot.pypy.org Thu May 23 16:44:56 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:56 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: FilePlugin modifications: Message-ID: <20130523144456.0405D1C094F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r410:b654baadddd1 Date: 2013-05-23 11:29 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/b654baadddd1/ Log: FilePlugin modifications: - added modification time and creation time to the directory lookup primitive - added FileOpen/Close primitives - added FileAtEnd primitive diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -1,10 +1,11 @@ -import os +import os, stat from spyvm import model, error from spyvm.plugins.plugin import Plugin from spyvm.primitives import PrimitiveFailedError, index1_0 FilePlugin = Plugin() +os.stat_float_times(False) @FilePlugin.expose_primitive(unwrap_spec=[object]) def primitiveDirectoryDelimitor(interp, s_frame, w_rcvr): @@ -22,12 +23,52 @@ if index >= len(contents): return space.w_nil py_name = sorted(contents)[index] - file_path = os.path.join(full_path, py_name) - assert os.path.exists(file_path) + try: + file_path = os.path.join(full_path, py_name) + except OSError: + raise PrimitiveFailedError + file_info = os.stat(file_path) name = space.wrap_string(py_name) - creationTime = space.wrap_int(0) - modificationTime = space.wrap_int(0) - dirFlag = space.w_true if os.path.isdir(file_path) else space.w_false - fileSize = space.wrap_int(os.path.getsize(file_path)) + creationTime = smalltalk_timestamp(space, file_info.st_ctime) + modificationTime = smalltalk_timestamp(space, file_info.st_mtime) + dirFlag = space.w_true if stat.S_IFDIR & file_info.st_mode else space.w_false + fileSize = space.wrap_int(file_info.st_size) return space.wrap_list([name, creationTime, modificationTime, dirFlag, fileSize]) + at FilePlugin.expose_primitive(unwrap_spec=[object, str, object]) +def primitiveFileOpen(interp, s_frame, w_rcvr, file_path, w_writeable_flag): + space = interp.space + if w_writeable_flag is space.w_true: + mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC + else: + mode = os.O_RDONLY + if not os.path.exists(file_path): + return space.w_nil + try: + file_descriptor = os.open(file_path, mode, 0666) + except OSError: + raise PrimitiveFailedError() + return space.wrap_int(file_descriptor) + + at FilePlugin.expose_primitive(unwrap_spec=[object, int]) +def primitiveFileClose(interp, s_frame, w_rcvr, fd): + try: + os.close(fd) + except OSError: + raise PrimitiveFailedError() + return w_rcvr + + at FilePlugin.expose_primitive(unwrap_spec=[object, int]) +def primitiveFileAtEnd(interp, s_frame, w_rcvr, fd): + py_file = os.fdopen(fd) + stat = os.fstat(fd) + if py_file.tell() < stat.st_size: + return interp.space.w_true + else: + return interp.space.w_false + +def smalltalk_timestamp(space, sec_since_epoch): + import time + from spyvm.primitives import secs_between_1901_and_1970 + sec_since_1901 = sec_since_epoch + secs_between_1901_and_1970 + return space.wrap_uint(sec_since_1901) From noreply at buildbot.pypy.org Thu May 23 16:44:50 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:50 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: extracted the actual primitive call in _sendSelector, to enable patching of primitive calls and more specific vm-debugging utilities Message-ID: <20130523144450.27CA31C3323@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r405:5abbe32fec87 Date: 2013-05-22 15:00 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/5abbe32fec87/ Log: extracted the actual primitive call in _sendSelector, to enable patching of primitive calls and more specific vm-debugging utilities may also help with factoring out print-tracing, eventually... diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -347,32 +347,9 @@ code = s_method.primitive() if code: - # the primitive pushes the result (if any) onto the stack itself - if interp.should_trace(): - print "%sActually calling primitive %d" % (interp._last_indent, code,) - func = primitives.prim_holder.prim_table[code] - # ################################################################## - if interp.trace: - print "%s-> primitive %d \t(in #%s, named #%s)" % ( - ' ' * (interp.max_stack_depth - interp.remaining_stack_depth), - code, self.w_method()._likely_methodname, w_selector.as_string()) try: - # note: argcount does not include rcvr - return func(interp, self, argcount, s_method) + return self._call_primitive(code, interp, argcount, s_method, w_selector) except primitives.PrimitiveFailedError: - # ############################################################## - # if interp.trace and func.func_name != 'raise_failing_default' and code != 83: - # # import pdb; pdb.set_trace() - # try: - # func(interp, self, argcount, s_method) # will fail again - # except primitives.PrimitiveFailedError: - # pass - if interp.trace: - print "%s primitive FAILED" % ( - ' ' * (interp.max_stack_depth - interp.remaining_stack_depth),) - - if interp.should_trace(True): - print "PRIMITIVE FAILED: %d %s" % (s_method.primitive, w_selector.as_string(),) pass # ignore this error and fall back to the Smalltalk version arguments = self.pop_and_return_n(argcount) s_frame = s_method.create_frame(self.space, receiver, arguments, self) @@ -409,6 +386,29 @@ return interp.stack_frame(s_frame) + def _call_primitive(self, code, interp, argcount, s_method, w_selector): + # the primitive pushes the result (if any) onto the stack itself + if interp.should_trace(): + print "%sActually calling primitive %d" % (interp._last_indent, code,) + func = primitives.prim_holder.prim_table[code] + # ################################################################## + if interp.trace: + print "%s-> primitive %d \t(in #%s, named #%s)" % ( + ' ' * (interp.max_stack_depth - interp.remaining_stack_depth), + code, self.w_method()._likely_methodname, w_selector.as_string()) + try: + # note: argcount does not include rcvr + return func(interp, self, argcount, s_method) + except primitives.PrimitiveFailedError, e: + if interp.trace: + print "%s primitive FAILED" % ( + ' ' * (interp.max_stack_depth - interp.remaining_stack_depth),) + + if interp.should_trace(True): + print "PRIMITIVE FAILED: %d %s" % (s_method.primitive, w_selector.as_string(),) + raise e + + def _return(self, return_value, interp, s_return_to): # for tests, when returning from the top-level context if s_return_to is None: From noreply at buildbot.pypy.org Thu May 23 16:44:57 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:57 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added skipping to the smalltalk-debugger-functionality Message-ID: <20130523144457.5667C1C094F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r411:edb22d518256 Date: 2013-05-23 14:45 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/edb22d518256/ Log: added skipping to the smalltalk-debugger-functionality diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -870,8 +870,12 @@ def stepping_debugger_send(original): """When interp.message_stepping is True, we halt on every call of ContextPartShadow._sendSelector. The method is not called for bytecode message sends (see constants.SPECIAL_SELECTORS)""" - def meth(self, w_selector, argcount, interp, + def meth(s_context, w_selector, argcount, interp, receiver, receiverclassshadow): + options = [False] + def skip(): options[0] = True; print 'skipping #%s' % w_selector.as_string() + def pstack(): print s_context.print_stack() + def thisContext(): print s_context if interp.message_stepping: if argcount == 0: print "-> %s %s" % (receiver.as_repr_string(), @@ -879,13 +883,21 @@ elif argcount == 1: print "-> %s %s %s" % (receiver.as_repr_string(), w_selector.as_string(), - self.peek(0).as_repr_string()) + s_context.peek(0).as_repr_string()) else: print "-> %s %s %r" % (receiver.as_repr_string(), w_selector.as_string(), - [self.peek(argcount-1-i) for i in range(argcount)]) + [s_context.peek(argcount-1-i) for i in range(argcount)]) import pdb; pdb.set_trace() - return original(self, w_selector, argcount, interp, receiver, receiverclassshadow) + if options[0]: + m_s = interp.message_stepping + interp.message_stepping = False + try: + return original(s_context, w_selector, argcount, interp, receiver, receiverclassshadow) + finally: + interp.message_stepping = m_s + else: + return original(s_context, w_selector, argcount, interp, receiver, receiverclassshadow) return meth ContextPartShadow._sendSelector = stepping_debugger_send(ContextPartShadow._sendSelector) From noreply at buildbot.pypy.org Thu May 23 16:44:51 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:51 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed primitive 'image name' (121), it should include a full path Message-ID: <20130523144451.5C1771C3324@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r406:f8a202c96f2f Date: 2013-05-22 15:58 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/f8a202c96f2f/ Log: fixed primitive 'image name' (121), it should include a full path added primitive 'vm path' diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -974,13 +974,17 @@ #____________________________________________________________________________ # Misc Primitives (138 - 149) +VM_PATH = 142 CLONE = 148 + at expose_primitive(VM_PATH, unwrap_spec=[object]) +def func(interp, s_frame, w_receiver): + return interp.space.wrap_string(os.path.join(os.getcwd(), '')) + @expose_primitive(CLONE, unwrap_spec=[object]) def func(interp, s_frame, w_arg): return w_arg.clone(interp.space) - # ___________________________________________________________________________ # File primitives (150-169) # (XXX they are obsolete in Squeak and done with a plugin) diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -119,6 +119,7 @@ if path is None: path = "Squeak.image" + path = os.path.join(os.getcwd(), path) try: f = open_file_as_stream(path, mode="rb", buffering=0) except OSError as e: From noreply at buildbot.pypy.org Thu May 23 16:44:58 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:58 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: removed the argcount from ContextPartShadow>>short_str in favor of counting colons in method_str Message-ID: <20130523144458.718B21C094F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r412:90b4534942c9 Date: 2013-05-23 16:43 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/90b4534942c9/ Log: removed the argcount from ContextPartShadow>>short_str in favor of counting colons in method_str diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -82,7 +82,7 @@ s_new_context.push(nlr.value) except ProcessSwitch, p: if self.trace: - print "====== Switch from: %s to: %s ======" % (s_new_context.short_str(0), p.s_new_context.short_str(0)) + print "====== Switch from: %s to: %s ======" % (s_new_context.short_str(), p.s_new_context.short_str()) s_new_context = p.s_new_context def c_loop(self, s_context, may_context_switch=True): @@ -357,7 +357,7 @@ # ###################################################################### if interp.trace: - print interp.padding() + s_frame.short_str(argcount) + print interp.padding() + s_frame.short_str() return interp.stack_frame(s_frame) @@ -380,7 +380,7 @@ # ###################################################################### if interp.trace: - print '%s%s missing: #%s' % (interp.padding('#'), s_frame.short_str(0), w_selector.as_string()) + print '%s%s missing: #%s' % (interp.padding('#'), s_frame.short_str(), w_selector.as_string()) if not objectmodel.we_are_translated(): import pdb; pdb.set_trace() diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -727,7 +727,7 @@ if method: desc = self.method_str() else: - desc = self.short_str(0) + desc = self.short_str() return padding + ' ', '%s\n%s%s' % (ret_str, padding, desc) @@ -830,7 +830,7 @@ def is_closure_context(self): return True - def short_str(self, argcount): + def short_str(self): return 'BlockContext of %s (%s) [%d]' % ( self.w_method().get_identifier_string(), self.w_receiver().as_repr_string(), @@ -983,7 +983,9 @@ retval += "\nStack : " + str(self._temps_and_stack[:self._stack_ptr]) return retval - def short_str(self, argcount): + def short_str(self): + method_str = self.method_str() + argcount = method_str.count(':') if argcount == 0: return '%s (rcvr: %s) [pc: %d]' % ( self.method_str(), From noreply at buildbot.pypy.org Thu May 23 16:44:52 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:52 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added named primitive FilePlugin>>primitiveDirectoryLookup Message-ID: <20130523144452.8F4081C3325@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r407:82471b6e5fad Date: 2013-05-22 15:59 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/82471b6e5fad/ Log: added named primitive FilePlugin>>primitiveDirectoryLookup diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -1,12 +1,34 @@ from spyvm import model, error from spyvm.plugins.plugin import Plugin -from spyvm.primitives import PrimitiveFailedError +from spyvm.primitives import PrimitiveFailedError, index1_0 FilePlugin = Plugin() - @FilePlugin.expose_primitive(unwrap_spec=[object]) def primitiveDirectoryDelimitor(interp, s_frame, w_rcvr): import os return interp.space.wrap_char(os.path.sep) + + at FilePlugin.expose_primitive(unwrap_spec=[object, str, index1_0]) +def primitiveDirectoryLookup(interp, s_frame, w_file_directory, full_path, index): + import os + print full_path + if full_path == '': + contents = os.listdir(os.path.sep) + else: + if not os.path.isdir(full_path): + raise PrimitiveFailedError + contents = os.listdir(full_path) + space = interp.space + if index >= len(contents): + return space.w_nil + name = sorted(contents)[index] + file_path = os.path.join(full_path, name) + assert os.path.exists(file_path) + creationTime = space.wrap_int(0) + modificationTime = space.wrap_int(0) + dirFlag = space.w_true if os.path.isdir(file_path) else space.w_false + fileSize = space.wrap_int(os.path.getsize(file_path)) + return space.wrap_list([space.wrap_string(name), creationTime, modificationTime, dirFlag, fileSize]) + From noreply at buildbot.pypy.org Thu May 23 16:44:59 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:44:59 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed a bug in fileplugin primitives Message-ID: <20130523144459.A3C261C094F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r413:51996b35860b Date: 2013-05-23 16:44 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/51996b35860b/ Log: fixed a bug in fileplugin primitives diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -62,7 +62,7 @@ def primitiveFileAtEnd(interp, s_frame, w_rcvr, fd): py_file = os.fdopen(fd) stat = os.fstat(fd) - if py_file.tell() < stat.st_size: + if py_file.tell() >= stat.st_size: return interp.space.w_true else: return interp.space.w_false From noreply at buildbot.pypy.org Thu May 23 16:45:00 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Thu, 23 May 2013 16:45:00 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: in the smalltalk debugging tools, renamed skip to over Message-ID: <20130523144500.B338E1C094F@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r414:597318b660c2 Date: 2013-05-23 16:44 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/597318b660c2/ Log: in the smalltalk debugging tools, renamed skip to over diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -873,9 +873,9 @@ def meth(s_context, w_selector, argcount, interp, receiver, receiverclassshadow): options = [False] - def skip(): options[0] = True; print 'skipping #%s' % w_selector.as_string() + def next(): interp.message_stepping = True; print 'Now continue (c).' + def over(): options[0] = True; print 'Skipping #%s. You still need to continue(c).' % w_selector.as_string() def pstack(): print s_context.print_stack() - def thisContext(): print s_context if interp.message_stepping: if argcount == 0: print "-> %s %s" % (receiver.as_repr_string(), From noreply at buildbot.pypy.org Thu May 23 18:27:43 2013 From: noreply at buildbot.pypy.org (bivab) Date: Thu, 23 May 2013 18:27:43 +0200 (CEST) Subject: [pypy-commit] pypy default: this check happens too early in the translation, so that the platform is not yet set creating translation conflicts on cross translation builds Message-ID: <20130523162743.440E01C00BD@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64513:bb929d024d07 Date: 2013-05-23 13:42 +0000 http://bitbucket.org/pypy/pypy/changeset/bb929d024d07/ Log: this check happens too early in the translation, so that the platform is not yet set creating translation conflicts on cross translation builds diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -3,8 +3,6 @@ from rpython.config.config import ChoiceOption, StrOption, Config from rpython.config.config import ConfigError from rpython.config.support import detect_number_of_processors -from rpython.jit.backend.detect_cpu import autodetect -from rpython.jit.backend.detect_cpu import MODEL_X86, MODEL_X86_NO_SSE2, MODEL_X86_64 DEFL_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() # and just small enough to prevend inlining of some rlist functions. @@ -15,9 +13,7 @@ DEFL_GC = "minimark" -_is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) - -if sys.platform.startswith("linux") and _is_x86: +if sys.platform.startswith("linux"): DEFL_ROOTFINDER_WITHJIT = "asmgcc" else: DEFL_ROOTFINDER_WITHJIT = "shadowstack" From noreply at buildbot.pypy.org Thu May 23 18:38:27 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Thu, 23 May 2013 18:38:27 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Merge default Message-ID: <20130523163827.283811C1578@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64514:75782b4f223f Date: 2013-05-23 17:29 +0200 http://bitbucket.org/pypy/pypy/changeset/75782b4f223f/ Log: Merge default diff too long, truncating to 2000 out of 12012 lines diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -324,7 +324,12 @@ if self._close: self._sock.close() else: - self._sock._decref_socketios() + try: + self._sock._decref_socketios() + except AttributeError: + pass # bah, someone built a _fileobject manually + # with some unexpected replacement of the + # _socketobject class self._sock = None def __del__(self): diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -2,7 +2,11 @@ import unittest import codecs import locale -import sys, StringIO, _testcapi +import sys, StringIO +try: + import _testcapi +except ImportError: + _testcapi = None class Queue(object): """ @@ -1387,7 +1391,7 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if encoding not in broken_incremental_coders and _testcapi: # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -7,7 +7,8 @@ import subprocess from copy import copy, deepcopy -from test.test_support import run_unittest, TESTFN, unlink, get_attribute +from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, + import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -236,7 +237,10 @@ def test_get_config_h_filename(self): config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print +try: + from _testcapi import traceback_print +except ImportError: + traceback_print = None from StringIO import StringIO import sys import unittest @@ -176,6 +179,8 @@ class TracebackFormatTests(unittest.TestCase): def test_traceback_format(self): + if traceback_print is None: + raise unittest.SkipTest('Requires _testcapi') try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1609,7 +1609,10 @@ self.assertEqual("{}".format(u), '__unicode__ overridden') def test_encode_decimal(self): - from _testcapi import unicode_encodedecimal + try: + from _testcapi import unicode_encodedecimal + except ImportError: + raise unittest.SkipTest('Requires _testcapi') self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -130,7 +130,7 @@ RegrTest('test_bz2.py', usemodules='bz2'), RegrTest('test_calendar.py'), RegrTest('test_call.py', core=True), - RegrTest('test_capi.py'), + RegrTest('test_capi.py', usemodules='cpyext'), RegrTest('test_cd.py'), RegrTest('test_cfgparser.py'), RegrTest('test_cgi.py'), @@ -177,7 +177,7 @@ RegrTest('test_cprofile.py'), RegrTest('test_crypt.py', usemodules='crypt'), RegrTest('test_csv.py', usemodules='_csv'), - RegrTest('test_ctypes.py', usemodules="_rawffi thread"), + RegrTest('test_ctypes.py', usemodules="_rawffi thread cpyext"), RegrTest('test_curses.py'), RegrTest('test_datetime.py', usemodules='binascii struct'), RegrTest('test_dbm.py'), diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -54,4 +54,9 @@ fp, filename, description = imp.find_module('_testcapi', path=[output_dir]) imp.load_module('_testcapi', fp, filename, description) -compile_shared() +try: + import cpyext +except ImportError: + raise ImportError("No module named '_testcapi'") +else: + compile_shared() diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -121,12 +121,10 @@ __import__(name) except (ImportError, CompilationError, py.test.skip.Exception), e: errcls = e.__class__.__name__ - config.add_warning( + raise Exception( "The module %r is disabled\n" % (modname,) + "because importing %s raised %s\n" % (name, errcls) + str(e)) - raise ConflictConfigError("--withmod-%s: %s" % (modname, - errcls)) return validator else: return None @@ -217,10 +215,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), @@ -365,6 +359,7 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0.0' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.1.rst @@ -0,0 +1,46 @@ +============================== +PyPy 2.0.1 - Bohr Smørrebrød +============================== + +We're pleased to announce PyPy 2.0.1. This is a stable bugfix release +over `2.0`_. You can download it here: + + http://pypy.org/download.html + +The fixes are mainly about fatal errors or crashes in our stdlib. See +below for more details. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +- fix an occasional crash in the JIT that ends in `RPython Fatal error: + NotImplementedError`__. + +- `id(x)` is now always a positive number (except on int/float/long/complex). + This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux). + +- fix crashes of callback-from-C-functions (with cffi) when used together + with Stackless features, on asmgcc (i.e. Linux only). Now `gevent should + work better`__. + +- work around an eventlet issue with `socket._decref_socketios()`__. + +.. __: https://bugs.pypy.org/issue1482 +.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html +.. __: https://bugs.pypy.org/issue1468 +.. _2.0: release-2.0.0.html + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,46 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged 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 @@ -8,5 +8,29 @@ .. branch: numpy-pickle Pickling of numpy arrays and dtypes (including record dtypes) +.. branch: remove-array-smm +Remove multimethods in the arraymodule + +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback + +.. branch: remove-set-smm +Remove multi-methods on sets + .. branch: numpy-subarrays -It is now possible to create arrays and dtypes that use subarrays +Implement subarrays for numpy + +.. branch: remove-dict-smm +Remove multi-methods on dict + +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list + +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -10,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -120,6 +122,17 @@ source = rffi.charp2str(ll_source) return _pypy_execute_source(source) + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + if space.config.objspace.usemodules.thread: + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + if space.config.objspace.usemodules.thread: + rthread.gc_thread_start() + w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), space.builtin_modules['__builtin__']) @@ -137,6 +150,8 @@ return 0 return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, 'pypy_setup_home': pypy_setup_home} def call_finish(space): diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -853,9 +853,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -864,6 +865,37 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists/sets of constants in the context of "in"/"not in". + + lists are folded into tuples, sets into frozensets, otherwise + returns False + """ + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -973,3 +973,30 @@ counts = self.count_instructions(source3) assert counts[ops.BUILD_LIST] == 1 assert ops.BUILD_LIST_FROM_ARG not in counts + + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): 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 @@ -903,22 +903,33 @@ expected_path = [str(prefix.join(subdir).ensure(dir=1)) for subdir in ('lib_pypy', 'lib-python/%s' % cpy_ver)] + # an empty directory from where we can't find the stdlib + tmp_dir = str(udir.join('tmp').ensure(dir=1)) self.w_goal_dir = self.space.wrap(goal_dir) self.w_fake_exe = self.space.wrap(str(fake_exe)) self.w_expected_path = self.space.wrap(expected_path) self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir)) + self.w_tmp_dir = self.space.wrap(tmp_dir) + foo_py = prefix.join('foo.py').write("pass") self.w_foo_py = self.space.wrap(str(foo_py)) def test_setup_bootstrap_path(self): - import sys + # Check how sys.path is handled depending on if we can find a copy of + # the stdlib in setup_bootstrap_path. + import sys, os old_sys_path = sys.path[:] + old_cwd = os.getcwd() + sys.path.append(self.goal_dir) + # make sure cwd does not contain a stdlib + os.chdir(self.tmp_dir) + tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c') try: import app_main - app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found + app_main.setup_bootstrap_path(tmp_pypy_c) # stdlib not found assert sys.executable == '' assert sys.path == old_sys_path + [self.goal_dir] @@ -933,6 +944,7 @@ assert newpath[:len(self.expected_path)] == self.expected_path finally: sys.path[:] = old_sys_path + os.chdir(old_cwd) def test_trunk_can_be_prefix(self): import sys diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -936,6 +936,21 @@ output = s.getvalue() assert "LOAD_GLOBAL" not in output + def test_folding_of_list_constants(self): + source = 'a in [1, 2, 3]' + co = compile(source, '', 'exec') + i = co.co_consts.index((1, 2, 3)) + assert i > -1 + assert isinstance(co.co_consts[i], tuple) + + def test_folding_of_set_constants(self): + source = 'a in {1, 2, 3}' + co = compile(source, '', 'exec') + i = co.co_consts.index(set([1, 2, 3])) + assert i > -1 + assert isinstance(co.co_consts[i], frozenset) + + class AppTestCallMethod(object): spaceconfig = {'objspace.opcodes.CALL_METHOD': True} 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 @@ -7,7 +7,7 @@ appleveldefs = { } interpleveldefs = { - '__version__': 'space.wrap("0.6")', + '__version__': 'space.wrap("0.7")', 'load_library': 'libraryobj.load_library', @@ -30,6 +30,8 @@ 'typeoffsetof': 'func.typeoffsetof', 'rawaddressof': 'func.rawaddressof', 'getcname': 'func.getcname', + 'newp_handle': 'handle.newp_handle', + 'from_handle': 'handle.from_handle', '_get_types': 'func._get_types', 'string': 'func.string', diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -114,8 +114,11 @@ ge = _make_comparison('ge') def hash(self): - h = (objectmodel.compute_identity_hash(self.ctype) ^ - rffi.cast(lltype.Signed, self._cdata)) + h = rffi.cast(lltype.Signed, self._cdata) + # To hash pointers in dictionaries. Assumes that h shows some + # alignment (to 4, 8, maybe 16 bytes), so we use the following + # formula to avoid the trailing bits being always 0. + h = h ^ (h >> 4) return self.space.wrap(h) def getitem(self, w_index): @@ -391,6 +394,19 @@ return self.length +class W_CDataHandle(W_CData): + _attrs_ = ['w_keepalive'] + _immutable_fields_ = ['w_keepalive'] + + def __init__(self, space, cdata, ctype, w_keepalive): + W_CData.__init__(self, space, cdata, ctype) + self.w_keepalive = w_keepalive + + def _repr_extra(self): + w_repr = self.space.repr(self.w_keepalive) + return "handle to %s" % (self.space.str_w(w_repr),) + + W_CData.typedef = TypeDef( 'CData', __module__ = '_cffi_backend', 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 @@ -172,8 +172,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = ['is_file', 'cache_array_type'] - _immutable_fields_ = ['is_file', 'cache_array_type?'] + _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr'] + _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr'] kind = "pointer" cache_array_type = None @@ -186,6 +186,7 @@ extra = " *" self.is_file = (ctitem.name == "struct _IO_FILE" or ctitem.name == "struct $FILE") + self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid) W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/handle.py @@ -0,0 +1,93 @@ +import weakref +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import unwrap_spec +from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj +from pypy.module._weakref.interp__weakref import dead_ref +from rpython.rtyper.lltypesystem import lltype, rffi + + +def reduced_value(s): + while True: + divide = s & 1 + s >>= 1 + if not divide: + return s + +# ____________________________________________________________ + + +class CffiHandles: + def __init__(self, space): + self.handles = [] + self.look_distance = 0 + + def reserve_next_handle_index(self): + # The reservation ordering done here is tweaked for pypy's + # memory allocator. We look from index 'look_distance'. + # Look_distance increases from 0. But we also look at + # "look_distance/2" or "/4" or "/8", etc. If we find that one + # of these secondary locations is free, we assume it's because + # there was recently a minor collection; so we reset + # look_distance to 0 and start again from the lowest locations. + length = len(self.handles) + for d in range(self.look_distance, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + s = reduced_value(d) + if self.handles[s]() is None: + break + # restart from the beginning + for d in range(0, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + # full! extend, but don't use '!=' here + self.handles = self.handles + [dead_ref] * (length // 3 + 5) + self.look_distance = length + 1 + return length + + def store_handle(self, index, content): + self.handles[index] = weakref.ref(content) + + def fetch_handle(self, index): + if 0 <= index < len(self.handles): + return self.handles[index]() + return None + +def get(space): + return space.fromcache(CffiHandles) + +# ____________________________________________________________ + + at unwrap_spec(w_ctype=ctypeobj.W_CType) +def newp_handle(space, w_ctype, w_x): + if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or + not w_ctype.is_void_ptr): + raise operationerrfmt(space.w_TypeError, + "needs 'void *', got '%s'", w_ctype.name) + index = get(space).reserve_next_handle_index() + _cdata = rffi.cast(rffi.CCHARP, index + 1) + new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x) + get(space).store_handle(index, new_cdataobj) + return new_cdataobj + + at 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): + raise operationerrfmt(space.w_TypeError, + "expected a 'cdata' object with a 'void *' out " + "of new_handle(), got '%s'", ctype.name) + index = rffi.cast(lltype.Signed, w_cdata._cdata) + original_cdataobj = get(space).fetch_handle(index - 1) + # + if isinstance(original_cdataobj, cdataobj.W_CDataHandle): + return original_cdataobj.w_keepalive + else: + if index == 0: + msg = "cannot use from_handle() on NULL pointer" + else: + msg = "'void *' value does not correspond to any object" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) 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,8 +365,9 @@ BInt = new_primitive_type("int") BFloat = new_primitive_type("float") for i in range(1, 20): - if (hash(cast(BChar, chr(i))) != - hash(cast(BInt, i))): + x1 = cast(BChar, chr(i)) + x2 = cast(BInt, i) + if hash(x1) != hash(x2): break else: raise AssertionError("hashes are equal") @@ -2723,6 +2724,40 @@ assert x.__name__ == '' assert hasattr(x, '__doc__') +def test_different_types_of_ptr_equality(): + BVoidP = new_pointer_type(new_void_type()) + BIntP = new_pointer_type(new_primitive_type("int")) + x = cast(BVoidP, 12345) + assert x == cast(BIntP, 12345) + assert x != cast(BIntP, 12344) + assert hash(x) == hash(cast(BIntP, 12345)) + +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + + def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.6" + assert __version__ == "0.7" diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/test/test_handle.py @@ -0,0 +1,59 @@ +import random +from pypy.module._cffi_backend.handle import CffiHandles, reduced_value + + +def test_reduced_value(): + assert reduced_value(0) == 0 + assert reduced_value(1) == 0 + assert reduced_value(2) == 1 + assert reduced_value(3) == 0 + assert reduced_value(4) == 2 + assert reduced_value(5) == 1 + assert reduced_value(6) == 3 + assert reduced_value(7) == 0 + assert reduced_value(8) == 4 + assert reduced_value(9) == 2 + assert reduced_value(10) == 5 + assert reduced_value(11) == 1 + + +class PseudoWeakRef(object): + _content = 42 + + def __call__(self): + return self._content + + +def test_cffi_handles_1(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + assert len(ch.handles) < 13500 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr + +def test_cffi_handles_2(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + # + if len(expected_content) > 20: + r = random.choice(list(expected_content)) + pwr = expected_content.pop(r) + pwr._content = None + # + assert len(ch.handles) < 100 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py --- a/pypy/module/_ffi/test/test_funcptr.py +++ b/pypy/module/_ffi/test/test_funcptr.py @@ -74,9 +74,9 @@ from _ffi import CDLL, types # this should return *all* loaded libs, dlopen(NULL) dll = CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.getfunc('Py_IsInitialized', [], types.slong)() - assert res == 1 + # libm should be loaded + res = dll.getfunc('sqrt', [types.double], types.double)(1.0) + assert res == 1.0 def test_callfunc(self): from _ffi import CDLL, types @@ -139,7 +139,7 @@ def test_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr() { return &dummy; } DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; } """ @@ -158,7 +158,7 @@ def test_convert_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto """ @@ -170,7 +170,7 @@ def _as_ffi_pointer_(self, ffitype): assert ffitype is types.void_p return self.value - + libfoo = CDLL(self.libfoo_name) get_dummy = libfoo.getfunc('get_dummy', [], types.sint) get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p) @@ -259,7 +259,7 @@ def test_typed_pointer_args(self): """ - extern int dummy; // defined in test_void_result + extern int dummy; // defined in test_void_result DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto """ @@ -551,7 +551,7 @@ from _ffi import CDLL, types libfoo = CDLL(self.libfoo_name) raises(TypeError, "libfoo.getfunc('sum_xy', [types.void], types.sint)") - + def test_OSError_loading(self): from _ffi import CDLL, types raises(OSError, "CDLL('I do not exist')") @@ -606,7 +606,7 @@ from _rawffi import FUNCFLAG_STDCALL libm = CDLL(self.libm_name) pow_addr = libm.getaddressindll('pow') - wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', + wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', [types.double, types.double], types.double, FUNCFLAG_STDCALL) try: wrong_pow(2, 3) == 8 @@ -622,7 +622,7 @@ from _rawffi import FUNCFLAG_STDCALL kernel = WinDLL('Kernel32.dll') sleep_addr = kernel.getaddressindll('Sleep') - sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], + sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], types.void, FUNCFLAG_STDCALL) sleep(10) diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -232,9 +232,9 @@ import _rawffi # this should return *all* loaded libs, dlopen(NULL) dll = _rawffi.CDLL(None) - # Assume CPython, or PyPy compiled with cpyext - res = dll.ptr('Py_IsInitialized', [], 'l')() - assert res[0] == 1 + func = dll.ptr('rand', [], 'i') + res = func() + assert res[0] != 0 def test_libc_load(self): import _rawffi diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") 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 @@ -344,7 +344,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=True) # XXX should not be exported + error=-1, external=False) @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -69,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: @@ -356,13 +357,13 @@ self.strides = strides self.backstrides = backstrides self.shape = shape + if dtype is None: + dtype = parent.dtype if isinstance(parent, SliceArray): parent = parent.parent # one level only self.parent = parent self.storage = parent.storage self.order = parent.order - if dtype is None: - dtype = parent.dtype self.dtype = dtype self.size = support.product(shape) * self.dtype.itemtype.get_element_size() self.start = start diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py --- a/pypy/module/micronumpy/arrayimpl/sort.py +++ b/pypy/module/micronumpy/arrayimpl/sort.py @@ -12,7 +12,7 @@ from rpython.rlib.objectmodel import specialize from pypy.interpreter.error import OperationError from pypy.module.micronumpy.base import W_NDimArray -from pypy.module.micronumpy import types +from pypy.module.micronumpy import interp_dtype, types from pypy.module.micronumpy.iter import AxisIterator INT_SIZE = rffi.sizeof(lltype.Signed) @@ -20,7 +20,7 @@ def make_sort_function(space, itemtype, comp_type, count=1): TP = itemtype.T step = rffi.sizeof(TP) - + class Repr(object): def __init__(self, index_stride_size, stride_size, size, values, indexes, index_start, start): @@ -69,13 +69,12 @@ class ArgArrayRepWithStorage(Repr): def __init__(self, index_stride_size, stride_size, size): - from pypy.module.micronumpy import interp_dtype start = 0 dtype = interp_dtype.get_dtype_cache(space).w_longdtype self.indexes = dtype.itemtype.malloc(size*dtype.get_size()) - self.values = alloc_raw_storage(size * stride_size, + self.values = alloc_raw_storage(size * stride_size, track_allocation=False) - Repr.__init__(self, index_stride_size, stride_size, + Repr.__init__(self, index_stride_size, stride_size, size, self.values, self.indexes, start, start) def __del__(self): @@ -97,7 +96,7 @@ for i in range(stop-start): retval.setitem(i, lst.getitem(i+start)) return retval - + if count < 2: def arg_lt(a, b): # Does numpy do <= ? @@ -109,14 +108,13 @@ return True elif a[0][i] > b[0][i]: return False - # Does numpy do True? + # Does numpy do True? return False ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length, arg_getitem_slice, arg_lt) def argsort(arr, space, w_axis, itemsize): - from pypy.module.micronumpy import interp_dtype if w_axis is space.w_None: # note that it's fine ot pass None here as we're not going # to pass the result around (None is the link to base in slices) @@ -182,7 +180,7 @@ class SortCache(object): built = False - + def __init__(self, space): if self.built: return diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -14,6 +14,7 @@ from pypy.module.micronumpy.interp_arrayops import where from pypy.module.micronumpy import interp_ufuncs from rpython.rlib.objectmodel import specialize, instantiate +from rpython.rlib.nonconst import NonConstant class BogusBytecode(Exception): @@ -40,6 +41,10 @@ TWO_ARG_FUNCTIONS = ["dot", 'take'] THREE_ARG_FUNCTIONS = ['where'] +class W_TypeObject(W_Root): + def __init__(self, name): + self.name = name + class FakeSpace(object): w_ValueError = "ValueError" w_TypeError = "TypeError" @@ -48,17 +53,17 @@ w_NotImplementedError = "NotImplementedError" w_None = None - w_bool = "bool" - w_int = "int" - w_float = "float" - w_list = "list" - w_long = "long" - w_tuple = 'tuple' - w_slice = "slice" - w_str = "str" - w_unicode = "unicode" - w_complex = "complex" - w_dict = "dict" + w_bool = W_TypeObject("bool") + w_int = W_TypeObject("int") + w_float = W_TypeObject("float") + w_list = W_TypeObject("list") + w_long = W_TypeObject("long") + w_tuple = W_TypeObject('tuple') + w_slice = W_TypeObject("slice") + w_str = W_TypeObject("str") + w_unicode = W_TypeObject("unicode") + w_complex = W_TypeObject("complex") + w_dict = W_TypeObject("dict") def __init__(self): """NOT_RPYTHON""" @@ -73,6 +78,13 @@ def issequence_w(self, w_obj): return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray) + def len(self, w_obj): + assert isinstance(w_obj, ListObject) + return self.wrap(len(w_obj.items)) + + def getattr(self, w_obj, w_attr): + return StringObject(NonConstant('foo')) + def isinstance_w(self, w_obj, w_tp): return w_obj.tp == w_tp diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,14 +268,30 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) @@ -373,7 +389,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -65,6 +65,10 @@ self.float_type = None self.shape = list(shape) self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -80,7 +84,8 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) @@ -113,6 +118,9 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + def descr_get_subdtype(self, space): return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) @@ -423,6 +431,7 @@ fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,10 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + if self.ptr_size == 8: + assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) + else: + assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype class AppTestTypes(BaseAppTestDtypes): @@ -768,6 +771,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -798,7 +802,8 @@ assert dt.shape == (10,) assert dt.kind == 'V' assert dt.fields == None - assert dt.subdtype == (dtype("float64"), (10,)) + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) def test_pickle_record(self): from numpypy import array, dtype diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2700,7 +2702,7 @@ assert a[1]['y'] == 1 def test_subarrays(self): - from numpypy import dtype, array + from numpypy import dtype, array, zeros d = dtype([("x", "int", 3), ("y", "float", 5)]) a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) @@ -2713,6 +2715,42 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) + + def test_multidim_subarray(self): + from numpypy import dtype, array + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1686,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1702,16 +1703,47 @@ class VoidType(BaseType, BaseStringType): T = lltype.Char - def coerce(self, space, dtype, w_items): + def _coerce(self, space, arr, ofs, dtype, w_items, shape): items_w = space.fixedview(w_items) - arr = VoidBoxStorage(self.size, dtype) - ofs = 0 for i in range(len(items_w)): subdtype = dtype.subdtype itemtype = subdtype.itemtype - w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) - itemtype.store(arr, 0, ofs, w_box) - ofs += itemtype.get_element_size() + if space.len_w(shape) <= 1: + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + for w_item in items_w: + self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) + ofs += size + return arr + + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + # TODO: Make sure the shape and the array match + items_w = space.fixedview(w_items) + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if len(shape) <= 1: + for i in range(len(items_w)): + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + for w_item in items_w: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + self._coerce(space, arr, ofs, dtype, w_item, shape[1:]) + ofs += size + + def coerce(self, space, dtype, w_items): + arr = VoidBoxStorage(self.size, dtype) + self._coerce(space, arr, 0, dtype, w_items, dtype.shape) return interp_boxes.W_VoidBox(arr, 0, dtype) @jit.unroll_safe @@ -1720,12 +1752,13 @@ for k in range(self.get_element_size()): arr.storage[k + ofs] = box.arr.storage[k + box.ofs] - def read(self, arr, i, offset, dtype=None): + def readarray(self, arr, i, offset, dtype=None): from pypy.module.micronumpy.base import W_NDimArray if dtype is None: dtype = arr.dtype strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) - implementation = SliceArray(i + offset, strides, backstrides, dtype.shape, arr, arr, dtype.subdtype) + implementation = SliceArray(i + offset, strides, backstrides, + dtype.shape, arr, W_NDimArray(arr), dtype.subdtype) return W_NDimArray(implementation) NonNativeVoidType = VoidType diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py --- a/pypy/module/pypyjit/interp_resop.py +++ b/pypy/module/pypyjit/interp_resop.py @@ -75,16 +75,19 @@ cache.w_optimize_hook = w_hook cache.in_recursion = NonConstant(False) + def set_abort_hook(space, w_hook): """ set_abort_hook(hook) Set a hook (callable) that will be called each time there is tracing aborted due to some reason. - The hook will be called as in: hook(jitdriver_name, greenkey, reason) + The hook will be called with the signature: + + hook(jitdriver_name, greenkey, reason, operations) Reason is a string, the meaning of other arguments is the same - as attributes on JitLoopInfo object + as attributes on JitLoopInfo object. """ cache = space.fromcache(Cache) cache.w_abort_hook = w_hook diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,26 +1,29 @@ from rpython.jit.codewriter.policy import JitPolicy +from rpython.rlib import jit_hooks from rpython.rlib.jit import JitHookInterface, Counters -from rpython.rlib import jit_hooks + from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\ - WrappedOp, W_JitLoopInfo +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): space = self.space cache = space.fromcache(Cache) if cache.in_recursion: return if space.is_true(cache.w_abort_hook): cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) try: try: space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, - greenkey, greenkey_repr), - space.wrap( - Counters.counter_names[reason])) + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) except OperationError, e: e.write_unraisable(space, "jit hook ", cache.w_abort_hook) finally: diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py --- a/pypy/module/pypyjit/test/test_jit_hook.py +++ b/pypy/module/pypyjit/test/test_jit_hook.py @@ -16,6 +16,7 @@ from rpython.jit.metainterp.typesystem import llhelper from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters + class MockJitDriverSD(object): class warmstate(object): @staticmethod @@ -34,8 +35,10 @@ jitdrivers_sd = [MockJitDriverSD] + class AppTestJitHook(object): spaceconfig = dict(usemodules=('pypyjit',)) + def setup_class(cls): if cls.runappdirect: py.test.skip("Can't run this test with -A") @@ -86,7 +89,7 @@ def interp_on_abort(): pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver, - greenkey, 'blah') + greenkey, 'blah', Logger(MockSD), []) space = cls.space cls.w_on_compile = space.wrap(interp2app(interp_on_compile)) @@ -189,12 +192,12 @@ import pypyjit l = [] - def hook(jitdriver_name, greenkey, reason): - l.append((jitdriver_name, reason)) + def hook(jitdriver_name, greenkey, reason, operations): + l.append((jitdriver_name, reason, operations)) pypyjit.set_abort_hook(hook) self.on_abort() - assert l == [('pypyjit', 'ABORT_TOO_LONG')] + assert l == [('pypyjit', 'ABORT_TOO_LONG', [])] def test_on_optimize(self): import pypyjit diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/bug1.py @@ -0,0 +1,57 @@ +import cffi, thread, time, sys + + +ffi = cffi.FFI() + +ffi.cdef(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4); +""") + +lib = ffi.verify(""" + long foobar(long a, long b, long c, long d, long e, long f, + long a2, long b2, long c2, long d2, long e2, long f2, + long a3, long b3, long c3, long d3, long e3, long f3, + long a4, long b4, long c4, long d4, long e4, long f4) + { + return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7); + } +""") + + +def runme(): + for j in range(10): + for i in range(10000): + args = [i-k for k in range(24)] + x = lib.foobar(*args) + (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2, + a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args + assert x == ( + a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 + + (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) + + (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) + + (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7)) + +done = [] + +def submain(): + try: + runme() + err = None + except: + err = sys.exc_info() + done.append(err) + +for i in range(2): + thread.start_new_thread(submain, ()) +while len(done) < 2: + time.sleep(0.1) + +for err in done: + if err is not None: + raise err[0], err[1], err[2] diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -0,0 +1,14 @@ +import os, sys, py, subprocess + +localdir = os.path.dirname(os.path.abspath(__file__)) + + +def test_bug1(): + if not sys.platform.startswith('linux'): + py.test.skip("linux-only test") + + cmdline = ['taskset', '-c', '0', + sys.executable, os.path.join(localdir, 'bug1.py')] + popen = subprocess.Popen(cmdline) + err = popen.wait() + assert err == 0 diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -487,6 +487,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -586,7 +587,6 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=<.*>) i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -44,6 +44,7 @@ # gc_id call is hoisted out of the loop, the id of a value obviously # can't change ;) assert loop.match_by_id("getitem", """ + ... i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...) ... p33 = getinteriorfield_gc(p31, i26, descr=>) diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -36,7 +36,7 @@ assert loop0.match(expected) # XXX: The retracing fails to form a loop since j From noreply at buildbot.pypy.org Thu May 23 18:38:28 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Thu, 23 May 2013 18:38:28 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Close the numpy-pickle branch Message-ID: <20130523163828.76EED1C1578@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64515:9d03c982e8d1 Date: 2013-05-23 18:37 +0200 http://bitbucket.org/pypy/pypy/changeset/9d03c982e8d1/ Log: Close the numpy-pickle branch From noreply at buildbot.pypy.org Thu May 23 18:38:29 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Thu, 23 May 2013 18:38:29 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge numpy-pickle Message-ID: <20130523163829.E1DDE1C1578@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: Changeset: r64516:7e2569700210 Date: 2013-05-23 18:37 +0200 http://bitbucket.org/pypy/pypy/changeset/7e2569700210/ Log: Merge numpy-pickle diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -151,6 +151,7 @@ if w_fields == space.w_None: self.fields = None else: + self.fields = {} ofs_and_items = [] size = 0 for key in space.listview(w_fields): @@ -338,8 +339,9 @@ elif char == 'V': num = 20 basename = 'void' - w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - return dtype_from_list(space, space.newlist([])) + itemtype = types.VoidType(size) + return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(size), + "V", space.gettypefor(interp_boxes.W_VoidBox)) else: assert char == 'U' basename = 'unicode' diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -281,17 +281,6 @@ assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype - def test_pickle_record(self): - from numpypy import array, dtype - from cPickle import loads, dumps - - d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) - assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) - - new_d = loads(dumps(d)) - - assert new_d.__reduce__() == d.__reduce__() - class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): import numpypy as numpy @@ -769,6 +758,7 @@ assert isinstance(unicode_(3), unicode) class AppTestRecordDtypes(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): from numpypy import dtype, void @@ -815,6 +805,30 @@ assert dt.subdtype == (dtype(float), (10,)) assert dt.base == dtype(float) + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() + + def test_pickle_record_subarrays(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32", (3,)), ("y", "int32", (2,)), ("z", "int32", (4,)), ("value", float, (5,))]) + new_d = loads(dumps(d)) + + keys = d.fields.keys() + keys.sort() + assert keys == ["value", "x", "y", "z"] + + assert new_d.itemsize == d.itemsize == 76 + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) From noreply at buildbot.pypy.org Thu May 23 18:44:15 2013 From: noreply at buildbot.pypy.org (mattip) Date: Thu, 23 May 2013 18:44:15 +0200 (CEST) Subject: [pypy-commit] pypy default: fix for missing module Message-ID: <20130523164415.9855B1C3321@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r64517:6349ccab6c2c Date: 2013-05-23 19:41 +0300 http://bitbucket.org/pypy/pypy/changeset/6349ccab6c2c/ Log: fix for missing module diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -65,7 +65,8 @@ del working_modules["termios"] del working_modules["_minimal_curses"] - del working_modules["cppyy"] # not tested on win32 + if "cppyy" in working_modules: + del working_modules["cppyy"] # not tested on win32 # The _locale module is needed by site.py on Windows default_modules["_locale"] = None @@ -78,7 +79,8 @@ del working_modules["_minimal_curses"] del working_modules["termios"] del working_modules["_multiprocessing"] # depends on rctime - del working_modules["cppyy"] # depends on ctypes + if "cppyy" in working_modules: + del working_modules["cppyy"] # depends on ctypes module_dependencies = { From noreply at buildbot.pypy.org Thu May 23 21:32:41 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 23 May 2013 21:32:41 +0200 (CEST) Subject: [pypy-commit] pypy default: Run pypy/tool/import_cffi Message-ID: <20130523193241.8B7731C00BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64518:a57f07766fff Date: 2013-05-23 21:31 +0200 http://bitbucket.org/pypy/pypy/changeset/a57f07766fff/ Log: Run pypy/tool/import_cffi 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,5 +4,5 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "0.6" -__version_info__ = (0, 6) +__version__ = "0.7" +__version_info__ = (0, 7) 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 @@ -73,15 +73,15 @@ if name.startswith('RTLD_'): setattr(self, name, getattr(backend, name)) # - BVoidP = self._get_cached_btype(model.voidp_type) + self.BVoidP = self._get_cached_btype(model.voidp_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(BVoidP, 0) + FFI.NULL = self.cast(self.BVoidP, 0) FFI.CData, FFI.CType = backend._get_types() else: # ctypes backend: attach these constants to the instance - self.NULL = self.cast(BVoidP, 0) + self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() def cdef(self, csource, override=False): @@ -346,6 +346,12 @@ self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.append(']') + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + def _make_ffi_library(ffi, libname, flags): import os @@ -372,8 +378,8 @@ BType = ffi._get_cached_btype(tp) try: value = backendlib.load_function(BType, name) - except KeyError: - raise AttributeError(name) + except KeyError as e: + raise AttributeError('%s: %s' % (name, e)) library.__dict__[name] = value return # diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -16,6 +16,7 @@ class CTypesData(object): __metaclass__ = CTypesType __slots__ = ['__weakref__'] + __name__ = '' def __init__(self, *args): raise TypeError("cannot instantiate %r" % (self.__class__,)) @@ -491,6 +492,8 @@ elif BItem in (getbtype(model.PrimitiveType('signed char')), getbtype(model.PrimitiveType('unsigned char'))): kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' else: kind = 'generic' # @@ -546,13 +549,13 @@ def __setitem__(self, index, value): self._as_ctype_ptr[index] = BItem._to_ctypes(value) - if kind == 'charp': + if kind == 'charp' or kind == 'voidp': @classmethod - def _arg_to_ctypes(cls, value): - if isinstance(value, bytes): - return ctypes.c_char_p(value) + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) else: - return super(CTypesPtr, cls)._arg_to_ctypes(value) + return super(CTypesPtr, cls)._arg_to_ctypes(*value) if kind == 'charp' or kind == 'bytep': def _to_string(self, maxlen): diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -15,6 +15,20 @@ def patch_extension_kwds(self, kwds): pass + def find_module(self, module_name, path, so_suffix): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] != so_suffix: + return None + return filename + def collect_types(self): self._typesdict = {} self._generate("collecttype") @@ -427,9 +441,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -1,4 +1,4 @@ -import sys +import sys, os import types from . import model, ffiplatform @@ -20,6 +20,16 @@ # up in kwds['export_symbols']. kwds.setdefault('export_symbols', self.export_symbols) + def find_module(self, module_name, path, so_suffix): + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + return None + def collect_types(self): pass # not needed in the generic engine @@ -216,9 +226,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -102,21 +102,10 @@ path = pkg.__path__ else: path = None - try: - f, filename, descr = imp.find_module(self.get_module_name(), - path) - except ImportError: + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffix()) + if filename is None: return - if f is not None: - f.close() - if filename.lower().endswith('.py'): - # on PyPy, if there are both .py and .pypy-19.so files in - # the same directory, the .py file is returned. That's the - # case after a setuptools installation. We never want to - # load the .py file here... - filename = filename[:-3] + _get_so_suffix() - if not os.path.isfile(filename): - return self.modulefilename = filename self._vengine.collect_types() self._has_module = True diff --git a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py @@ -971,6 +971,16 @@ s.c = -4 assert s.c == -4 + def test_bitfield_enum(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef(""" + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_anonymous_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("typedef struct { int a; } foo_t;") diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -28,3 +28,12 @@ assert ffi.typeof("long(*)(long, long**, ...)").cname == ( "long(*)(long, long * *, ...)") assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True + + def test_new_handle(self): + ffi = FFI(backend=self.Backend()) + o = [2, 3, 4] + p = ffi.new_handle(o) + assert ffi.typeof(p) == ffi.typeof("void *") + assert ffi.from_handle(p) is o + assert ffi.from_handle(ffi.cast("char *", p)) is o + py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_function.py b/pypy/module/test_lib_pypy/cffi_tests/test_function.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_function.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_function.py @@ -334,6 +334,31 @@ assert lib.EE == -5 assert lib.FF == -4 + def test_void_star_accepts_string(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(const void *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + + def test_signed_char_star_accepts_string(self): + if self.Backend is CTypesBackend: + py.test.skip("not supported by the ctypes backend") + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(signed char *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + + def test_unsigned_char_star_accepts_string(self): + if self.Backend is CTypesBackend: + py.test.skip("not supported by the ctypes backend") + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(unsigned char *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + def test_missing_function(self): ffi = FFI(backend=self.Backend()) ffi.cdef(""" @@ -341,3 +366,19 @@ """) m = ffi.dlopen("m") assert not hasattr(m, 'nonexistent') + + def test_wraps_from_stdlib(self): + import functools + ffi = FFI(backend=self.Backend()) + ffi.cdef(""" + double sin(double x); + """) + def my_decorator(f): + @functools.wraps(f) + def wrapper(*args): + return f(*args) + 100 + return wrapper + m = ffi.dlopen("m") + sin100 = my_decorator(m.sin) + x = sin100(1.23) + assert x == math.sin(1.23) + 100 diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py @@ -522,6 +522,18 @@ py.test.raises(OverflowError, "s.b = 4") assert s.b == 3 +def test_struct_with_bitfield_enum(): + ffi = FFI() + code = """ + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """ + ffi.cdef(code) + ffi.verify(code) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_unsupported_struct_with_bitfield_ellipsis(): ffi = FFI() py.test.raises(NotImplementedError, ffi.cdef, diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py b/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py @@ -24,6 +24,12 @@ modules = ('cffi', '_cffi_backend') except ImportError: modules = ('cffi', '_cffi_backend', 'pycparser') + try: + import ply + except ImportError: + pass + else: + modules += ('ply',) # needed for older versions of pycparser for module in modules: target = imp.find_module(module)[1] os.symlink(target, os.path.join(site_packages, From noreply at buildbot.pypy.org Thu May 23 21:32:44 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 23 May 2013 21:32:44 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130523193244.548711C00BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64519:464ddfab7de6 Date: 2013-05-23 21:32 +0200 http://bitbucket.org/pypy/pypy/changeset/464ddfab7de6/ Log: merge heads diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -65,7 +65,8 @@ del working_modules["termios"] del working_modules["_minimal_curses"] - del working_modules["cppyy"] # not tested on win32 + if "cppyy" in working_modules: + del working_modules["cppyy"] # not tested on win32 # The _locale module is needed by site.py on Windows default_modules["_locale"] = None @@ -78,7 +79,8 @@ del working_modules["_minimal_curses"] del working_modules["termios"] del working_modules["_multiprocessing"] # depends on rctime - del working_modules["cppyy"] # depends on ctypes + if "cppyy" in working_modules: + del working_modules["cppyy"] # depends on ctypes module_dependencies = { 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 @@ -31,3 +31,6 @@ .. branch: remove-tuple-smm Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -70,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: @@ -324,6 +324,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): @@ -356,13 +357,13 @@ self.strides = strides self.backstrides = backstrides self.shape = shape + if dtype is None: + dtype = parent.dtype if isinstance(parent, SliceArray): parent = parent.parent # one level only self.parent = parent self.storage = parent.storage self.order = parent.order - if dtype is None: - dtype = parent.dtype self.dtype = dtype self.size = support.product(shape) * self.dtype.itemtype.get_element_size() self.start = start diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,14 +268,30 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) @@ -373,7 +389,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,12 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -78,7 +84,8 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) @@ -111,8 +118,15 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -137,6 +151,7 @@ if w_fields == space.w_None: self.fields = None else: + self.fields = {} ofs_and_items = [] size = 0 for key in space.listview(w_fields): @@ -279,15 +294,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -317,8 +339,9 @@ elif char == 'V': num = 20 basename = 'void' - w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - return dtype_from_list(space, space.newlist([])) + itemtype = types.VoidType(size) + return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(size), + "V", space.gettypefor(interp_boxes.W_VoidBox)) else: assert char == 'U' basename = 'unicode' @@ -333,10 +356,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +392,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +430,8 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,23 +275,12 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype - def test_pickle_record(self): - from numpypy import array, dtype - from cPickle import loads, dumps - - d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) - assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) - - new_d = loads(dumps(d)) - - assert new_d.__reduce__() == d.__reduce__() - class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): import numpypy as numpy @@ -726,7 +715,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -769,6 +758,7 @@ assert isinstance(unicode_(3), unicode) class AppTestRecordDtypes(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): from numpypy import dtype, void @@ -781,6 +771,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -793,6 +784,51 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) + + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() + + def test_pickle_record_subarrays(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32", (3,)), ("y", "int32", (2,)), ("z", "int32", (4,)), ("value", float, (5,))]) + new_d = loads(dumps(d)) + + keys = d.fields.keys() + keys.sort() + assert keys == ["value", "x", "y", "z"] + + assert new_d.itemsize == d.itemsize == 76 + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2699,6 +2701,56 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array, zeros + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) + + def test_multidim_subarray(self): + from numpypy import dtype, array + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1684,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1696,10 +1699,68 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + items_w = space.fixedview(w_items) + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if space.len_w(shape) <= 1: + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + for w_item in items_w: + self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) + ofs += size + return arr + + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + # TODO: Make sure the shape and the array match + items_w = space.fixedview(w_items) + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if len(shape) <= 1: + for i in range(len(items_w)): + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + for w_item in items_w: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + self._coerce(space, arr, ofs, dtype, w_item, shape[1:]) + ofs += size + + def coerce(self, space, dtype, w_items): + arr = VoidBoxStorage(self.size, dtype) + self._coerce(space, arr, 0, dtype, w_items, dtype.shape) + return interp_boxes.W_VoidBox(arr, 0, dtype) + + @jit.unroll_safe + def store(self, arr, i, ofs, box): + assert isinstance(box, interp_boxes.W_VoidBox) + for k in range(self.get_element_size()): + arr.storage[k + ofs] = box.arr.storage[k + box.ofs] + + def readarray(self, arr, i, offset, dtype=None): + from pypy.module.micronumpy.base import W_NDimArray + if dtype is None: + dtype = arr.dtype + strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order) + implementation = SliceArray(i + offset, strides, backstrides, + dtype.shape, arr, W_NDimArray(arr), dtype.subdtype) + return W_NDimArray(implementation) + NonNativeVoidType = VoidType NonNativeStringType = StringType @@ -1733,7 +1794,7 @@ if not space.issequence_w(w_item): raise OperationError(space.w_TypeError, space.wrap( "expected sequence")) - if len(self.offsets_and_fields) != space.int_w(space.len(w_item)): + if len(self.offsets_and_fields) != space.len_w(w_item): raise OperationError(space.w_ValueError, space.wrap( "wrong length")) items_w = space.fixedview(w_item) diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,20 +1,17 @@ """Generic iterator implementations""" + +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.gateway import interp2app, interpindirect2app from pypy.interpreter.error import OperationError -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.stdtypedef import StdTypeDef -class W_AbstractIterObject(W_Object): - __slots__ = () - -class W_AbstractSeqIterObject(W_AbstractIterObject): - from pypy.objspace.std.itertype import iter_typedef as typedef - - def __init__(w_self, w_seq, index=0): +class W_AbstractSeqIterObject(W_Root): + def __init__(self, w_seq, index=0): if index < 0: index = 0 - w_self.w_seq = w_seq - w_self.index = index + self.w_seq = w_seq + self.index = index def getlength(self, space): if self.w_seq is None: @@ -26,102 +23,155 @@ w_len = space.wrap(0) return w_len + def descr_iter(self, space): + return self + + def descr_next(self, space): + raise NotImplementedError + + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('seqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) + + def descr_length_hint(self, space): + return self.getlength(space) + +W_AbstractSeqIterObject.typedef = StdTypeDef( + "sequenceiterator", + __doc__ = '''iter(collection) -> iterator +iter(callable, sentinel) -> iterator + +Get an iterator from an object. In the first form, the argument must +supply its own iterator, or be a sequence. +In the second form, the callable is called until it returns the sentinel.''', + __iter__ = interp2app(W_AbstractSeqIterObject.descr_iter), + next = interpindirect2app(W_AbstractSeqIterObject.descr_next), + __reduce__ = interp2app(W_AbstractSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_AbstractSeqIterObject.descr_length_hint), +) +W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False + + class W_SeqIterObject(W_AbstractSeqIterObject): """Sequence iterator implementation for general sequences.""" -class W_FastListIterObject(W_AbstractSeqIterObject): # XXX still needed - """Sequence iterator specialized for lists. - """ + def descr_next(self, space): + if self.w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + self.index += 1 + return w_item + + +class W_FastListIterObject(W_AbstractSeqIterObject): + """Sequence iterator specialized for lists.""" + + def descr_next(self, space): + from pypy.objspace.std.listobject import W_ListObject + w_seq = self.w_seq + if w_seq is None: + raise OperationError(space.w_StopIteration, space.w_None) + assert isinstance(w_seq, W_ListObject) + index = self.index + try: + w_item = w_seq.getitem(index) + except IndexError: + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item + class W_FastTupleIterObject(W_AbstractSeqIterObject): """Sequence iterator specialized for tuples, accessing directly their RPython-level list of wrapped objects. """ - def __init__(w_self, w_seq, wrappeditems): - W_AbstractSeqIterObject.__init__(w_self, w_seq) - w_self.tupleitems = wrappeditems + def __init__(self, w_seq, wrappeditems): + W_AbstractSeqIterObject.__init__(self, w_seq) + self.tupleitems = wrappeditems -class W_ReverseSeqIterObject(W_Object): - from pypy.objspace.std.itertype import reverse_iter_typedef as typedef + def descr_next(self, space): + if self.tupleitems is None: + raise OperationError(space.w_StopIteration, space.w_None) + index = self.index + try: + w_item = self.tupleitems[index] + except IndexError: + self.tupleitems = None + self.w_seq = None + raise OperationError(space.w_StopIteration, space.w_None) + self.index = index + 1 + return w_item - def __init__(w_self, space, w_seq, index=-1): - w_self.w_seq = w_seq - w_self.w_len = space.len(w_seq) - w_self.index = space.int_w(w_self.w_len) + index +class W_ReverseSeqIterObject(W_Root): + def __init__(self, space, w_seq, index=-1): + self.w_seq = w_seq + self.w_len = space.len(w_seq) + self.index = space.int_w(self.w_len) + index -registerimplementation(W_SeqIterObject) -registerimplementation(W_FastListIterObject) -registerimplementation(W_FastTupleIterObject) -registerimplementation(W_ReverseSeqIterObject) + def descr_reduce(self, space): + """ + XXX to do: remove this __reduce__ method and do + a registration with copy_reg, instead. + """ + from pypy.interpreter.mixedmodule import MixedModule + w_mod = space.getbuiltinmodule('_pickle_support') + mod = space.interp_w(MixedModule, w_mod) + new_inst = mod.get('reverseseqiter_new') + tup = [self.w_seq, space.wrap(self.index)] + return space.newtuple([new_inst, space.newtuple(tup)]) -def iter__SeqIter(space, w_seqiter): - return w_seqiter + def descr_length_hint(self, space): + if self.w_seq is None: + return space.wrap(0) + index = self.index + 1 + w_length = space.len(self.w_seq) + # if length of sequence is less than index :exhaust iterator + if space.is_true(space.gt(space.wrap(self.index), w_length)): + w_len = space.wrap(0) + self.w_seq = None + else: + w_len = space.wrap(index) + if space.is_true(space.lt(w_len, space.wrap(0))): + w_len = space.wrap(0) + return w_len -def next__SeqIter(space, w_seqiter): - if w_seqiter.w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index += 1 - return w_item + def descr_iter(self, space): + return self + def descr_next(self, space): + if self.w_seq is None or self.index < 0: + raise OperationError(space.w_StopIteration, space.w_None) + try: + w_item = space.getitem(self.w_seq, space.wrap(self.index)) + self.index -= 1 + except OperationError, e: + self.w_seq = None + if not e.match(space, space.w_IndexError): + raise + raise OperationError(space.w_StopIteration, space.w_None) + return w_item -def iter__FastTupleIter(space, w_seqiter): - return w_seqiter - -def next__FastTupleIter(space, w_seqiter): - if w_seqiter.tupleitems is None: - raise OperationError(space.w_StopIteration, space.w_None) - index = w_seqiter.index - try: - w_item = w_seqiter.tupleitems[index] - except IndexError: - w_seqiter.tupleitems = None - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__FastListIter(space, w_seqiter): - return w_seqiter - -def next__FastListIter(space, w_seqiter): - from pypy.objspace.std.listobject import W_ListObject - w_seq = w_seqiter.w_seq - if w_seq is None: - raise OperationError(space.w_StopIteration, space.w_None) - assert isinstance(w_seq, W_ListObject) - index = w_seqiter.index - try: - w_item = w_seq.getitem(index) - except IndexError: - w_seqiter.w_seq = None - raise OperationError(space.w_StopIteration, space.w_None) - w_seqiter.index = index + 1 - return w_item - - -def iter__ReverseSeqIter(space, w_seqiter): - return w_seqiter - -def next__ReverseSeqIter(space, w_seqiter): - if w_seqiter.w_seq is None or w_seqiter.index < 0: - raise OperationError(space.w_StopIteration, space.w_None) - try: - w_item = space.getitem(w_seqiter.w_seq, space.wrap(w_seqiter.index)) - w_seqiter.index -= 1 - except OperationError, e: - w_seqiter.w_seq = None - if not e.match(space, space.w_IndexError): - raise - raise OperationError(space.w_StopIteration, space.w_None) - return w_item - -register_all(vars()) +W_ReverseSeqIterObject.typedef = StdTypeDef( + "reversesequenceiterator", + __iter__ = interp2app(W_ReverseSeqIterObject.descr_iter), + next = interp2app(W_ReverseSeqIterObject.descr_next), + __reduce__ = interp2app(W_ReverseSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_ReverseSeqIterObject.descr_length_hint), +) +W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/itertype.py b/pypy/objspace/std/itertype.py deleted file mode 100644 --- a/pypy/objspace/std/itertype.py +++ /dev/null @@ -1,85 +0,0 @@ -from pypy.interpreter import gateway -from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.interpreter.error import OperationError - -# ____________________________________________________________ - -def descr_seqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - - # cpython does not support pickling iterators but stackless python do - #msg = 'Pickling for iterators dissabled as cpython does not support it' - #raise OperationError(space.w_TypeError, space.wrap(msg)) - - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('seqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_seqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(w_self, W_AbstractSeqIterObject) - return w_self.getlength(space) - -# ____________________________________________________________ - -def descr_reverseseqiter__reduce__(w_self, space): - """ - XXX to do: remove this __reduce__ method and do - a registration with copy_reg, instead. - """ - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - from pypy.interpreter.mixedmodule import MixedModule - w_mod = space.getbuiltinmodule('_pickle_support') - mod = space.interp_w(MixedModule, w_mod) - new_inst = mod.get('reverseseqiter_new') - tup = [w_self.w_seq, space.wrap(w_self.index)] - return space.newtuple([new_inst, space.newtuple(tup)]) - - -def descr_reverseseqiter__length_hint__(space, w_self): - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(w_self, W_ReverseSeqIterObject) - if w_self.w_seq is None: - return space.wrap(0) - index = w_self.index + 1 - w_length = space.len(w_self.w_seq) - # if length of sequence is less than index :exhaust iterator - if space.is_true(space.gt(space.wrap(w_self.index), w_length)): - w_len = space.wrap(0) - w_self.w_seq = None - else: - w_len = space.wrap(index) - if space.is_true(space.lt(w_len, space.wrap(0))): - w_len = space.wrap(0) - return w_len - -# ____________________________________________________________ -iter_typedef = StdTypeDef("sequenceiterator", - __doc__ = '''iter(collection) -> iterator -iter(callable, sentinel) -> iterator - -Get an iterator from an object. In the first form, the argument must -supply its own iterator, or be a sequence. -In the second form, the callable is called until it returns the sentinel.''', - - __reduce__ = gateway.interp2app(descr_seqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_seqiter__length_hint__), - ) -iter_typedef.acceptable_as_base_class = False - -reverse_iter_typedef = StdTypeDef("reversesequenceiterator", - - __reduce__ = gateway.interp2app(descr_reverseseqiter__reduce__), - __length_hint__ = gateway.interp2app(descr_reverseseqiter__length_hint__), - ) -reverse_iter_typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,5 +1,14 @@ +"""The builtin list implementation + +Lists optimize their storage by holding certain primitive datatypes in +unwrapped form. For more information: + +http://morepypy.blogspot.com/2011/10/more-compact-lists-with-list-strategies.html + +""" + import operator -from sys import maxint +import sys from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt @@ -18,11 +27,11 @@ from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject -from pypy.objspace.std.util import negate, get_positive_index -from rpython.rlib import rerased, jit, debug +from pypy.objspace.std.util import get_positive_index, negate +from rpython.rlib import debug, jit, rerased from rpython.rlib.listsort import make_timsort_class -from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) +from rpython.rlib.objectmodel import ( + instantiate, newlist_hint, resizelist_hint, specialize) from rpython.tool.sourcetools import func_with_new_name __all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] @@ -130,26 +139,26 @@ class W_ListObject(W_Root): - def __init__(w_self, space, wrappeditems, sizehint=-1): + + def __init__(self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) - w_self.space = space + self.space = space if space.config.objspace.std.withliststrategies: - w_self.strategy = get_strategy_from_list_objects(space, - wrappeditems, - sizehint) + self.strategy = get_strategy_from_list_objects(space, wrappeditems, + sizehint) else: - w_self.strategy = space.fromcache(ObjectListStrategy) - w_self.init_from_list_w(wrappeditems) + self.strategy = space.fromcache(ObjectListStrategy) + self.init_from_list_w(wrappeditems) @staticmethod def from_storage_and_strategy(space, storage, strategy): - w_self = instantiate(W_ListObject) - w_self.space = space - w_self.strategy = strategy - w_self.lstorage = storage + self = instantiate(W_ListObject) + self.space = space + self.strategy = strategy + self.lstorage = storage if not space.config.objspace.std.withliststrategies: - w_self.switch_to_object_strategy() - return w_self + self.switch_to_object_strategy() + return self @staticmethod def newlist_str(space, list_s): @@ -157,10 +166,10 @@ storage = strategy.erase(list_s) return W_ListObject.from_storage_and_strategy(space, storage, strategy) - def __repr__(w_self): + def __repr__(self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, - w_self.lstorage._x) + return "%s(%s, %s)" % (self.__class__.__name__, self.strategy, + self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -216,7 +225,7 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): + def find(self, w_item, start=0, end=sys.maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) @@ -590,14 +599,14 @@ 'L.remove(value) -- remove first occurrence of value' # needs to be safe against eq_w() mutating the w_list behind our back try: - i = self.find(w_value, 0, maxint) + i = self.find(w_value, 0, sys.maxint) except ValueError: raise OperationError(space.w_ValueError, space.wrap("list.remove(x): x not in list")) if i < self.length(): # otherwise list was mutated self.pop(i) - @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) def descr_index(self, space, w_value, w_start, w_stop): '''L.index(value, [start, [stop]]) -> integer -- return first index of value''' diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -44,7 +44,6 @@ from pypy.objspace.std.longtype import long_typedef from pypy.objspace.std.unicodetype import unicode_typedef from pypy.objspace.std.nonetype import none_typedef - from pypy.objspace.std.itertype import iter_typedef self.pythontypes = [value for key, value in result.__dict__.items() if not key.startswith('_')] # don't look @@ -81,6 +80,7 @@ self.pythontypes.append(dictmultiobject.W_DictMultiObject.typedef) self.pythontypes.append(setobject.W_SetObject.typedef) self.pythontypes.append(setobject.W_FrozensetObject.typedef) + self.pythontypes.append(iterobject.W_AbstractSeqIterObject.typedef) # the set of implementation types self.typeorder = { @@ -95,10 +95,6 @@ longobject.W_LongObject: [], noneobject.W_NoneObject: [], complexobject.W_ComplexObject: [], - iterobject.W_SeqIterObject: [], - iterobject.W_FastListIterObject: [], - iterobject.W_FastTupleIterObject: [], - iterobject.W_ReverseSeqIterObject: [], unicodeobject.W_UnicodeObject: [], pypy.interpreter.pycode.PyCode: [], pypy.interpreter.special.Ellipsis: [], diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -19,6 +19,7 @@ from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject +from pypy.objspace.std.iterobject import W_AbstractSeqIterObject from pypy.objspace.std.listobject import W_ListObject from pypy.objspace.std.longobject import W_LongObject, newlong from pypy.objspace.std.noneobject import W_NoneObject @@ -668,6 +669,8 @@ self._interplevel_classes[self.w_list] = W_ListObject self._interplevel_classes[self.w_set] = W_SetObject self._interplevel_classes[self.w_tuple] = W_AbstractTupleObject + self._interplevel_classes[self.w_sequenceiterator] = \ + W_AbstractSeqIterObject @specialize.memo() def _get_interplevel_cls(self, w_type): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -18,18 +18,18 @@ class W_BaseSetObject(W_Root): typedef = None - def __init__(w_self, space, w_iterable=None): + def __init__(self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" - w_self.space = space - set_strategy_and_setdata(space, w_self, w_iterable) + self.space = space + set_strategy_and_setdata(space, self, w_iterable) - def __repr__(w_self): + def __repr__(self): """representation for debugging purposes""" - reprlist = [repr(w_item) for w_item in w_self.getkeys()] - return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist)) + reprlist = [repr(w_item) for w_item in self.getkeys()] + return "<%s(%s)>" % (self.__class__.__name__, ', '.join(reprlist)) - def from_storage_and_strategy(w_self, storage, strategy): - obj = w_self._newobj(w_self.space, None) + def from_storage_and_strategy(self, storage, strategy): + obj = self._newobj(self.space, None) assert isinstance(obj, W_BaseSetObject) obj.strategy = strategy obj.sstorage = storage @@ -501,11 +501,11 @@ class W_SetObject(W_BaseSetObject): - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" - if type(w_self) is W_SetObject: + if type(self) is W_SetObject: return W_SetObject(space, w_iterable) - w_type = space.type(w_self) + w_type = space.type(self) w_obj = space.allocate_instance(W_SetObject, w_type) W_SetObject.__init__(w_obj, space, w_iterable) return w_obj @@ -577,11 +577,11 @@ class W_FrozensetObject(W_BaseSetObject): hash = 0 - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new frozenset by taking ownership of 'w_iterable'.""" - if type(w_self) is W_FrozensetObject: + if type(self) is W_FrozensetObject: return W_FrozensetObject(space, w_iterable) - w_type = space.type(w_self) + w_type = space.type(self) w_obj = space.allocate_instance(W_FrozensetObject, w_type) W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj @@ -1439,9 +1439,9 @@ class W_SetIterObject(W_Root): - def __init__(w_self, space, iterimplementation): - w_self.space = space - w_self.iterimplementation = iterimplementation + def __init__(self, space, iterimplementation): + self.space = space + self.iterimplementation = iterimplementation def descr_length_hint(self, space): return space.wrap(self.iterimplementation.length()) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -14,13 +14,13 @@ def make_specialised_class(typetuple): assert type(typetuple) == tuple - nValues = len(typetuple) - iter_n = unrolling_iterable(range(nValues)) + typelen = len(typetuple) + iter_n = unrolling_iterable(range(typelen)) class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space - assert len(values_w) == nValues + assert len(values_w) == typelen for i in iter_n: w_obj = values_w[i] val_type = typetuple[i] @@ -37,10 +37,10 @@ setattr(self, 'value%s' % i, unwrapped) def length(self): - return nValues + return typelen def tolist(self): - list_w = [None] * nValues + list_w = [None] * typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -54,7 +54,7 @@ def descr_hash(self, space): mult = 1000003 x = 0x345678 - z = nValues + z = typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] == object: @@ -76,7 +76,7 @@ if not isinstance(w_other, W_AbstractTupleObject): return space.w_NotImplemented if not isinstance(w_other, cls): - if nValues != w_other.length(): + if typelen != w_other.length(): return space.w_False for i in iter_n: myval = getattr(self, 'value%s' % i) @@ -102,7 +102,7 @@ def getitem(self, space, index): if index < 0: - index += nValues + index += typelen for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) diff --git a/pypy/objspace/std/test/test_lengthhint.py b/pypy/objspace/std/test/test_lengthhint.py --- a/pypy/objspace/std/test/test_lengthhint.py +++ b/pypy/objspace/std/test/test_lengthhint.py @@ -74,7 +74,7 @@ self._test_length_hint(self.space.wrap(u'Y' * self.SIZE)) def test_tuple(self): - self._test_length_hint(self.space.newtuple(self.ITEMS)) + self._test_length_hint(self.space.wrap(tuple(self.ITEMS))) def test_reversed(self): # test the generic reversed iterator (w_foo lacks __reversed__) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,8 +1,11 @@ +"""The builtin tuple implementation""" + import sys -from pypy.interpreter import gateway + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice @@ -177,8 +180,7 @@ count += 1 return space.wrap(count) - @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), - w_stop=gateway.WrappedDefault(sys.maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) def descr_index(self, space, w_obj, w_start, w_stop): """index(obj, [start, [stop]]) -> first index that obj appears in the diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -3,8 +3,6 @@ from rpython.config.config import ChoiceOption, StrOption, Config from rpython.config.config import ConfigError from rpython.config.support import detect_number_of_processors -from rpython.jit.backend.detect_cpu import autodetect -from rpython.jit.backend.detect_cpu import MODEL_X86, MODEL_X86_NO_SSE2, MODEL_X86_64 DEFL_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() # and just small enough to prevend inlining of some rlist functions. @@ -15,9 +13,7 @@ DEFL_GC = "minimark" -_is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) - -if sys.platform.startswith("linux") and _is_x86: +if sys.platform.startswith("linux"): DEFL_ROOTFINDER_WITHJIT = "asmgcc" else: DEFL_ROOTFINDER_WITHJIT = "shadowstack" diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py --- a/rpython/jit/codewriter/effectinfo.py +++ b/rpython/jit/codewriter/effectinfo.py @@ -21,6 +21,7 @@ OS_NONE = 0 # normal case, no oopspec OS_ARRAYCOPY = 1 # "list.ll_arraycopy" OS_STR2UNICODE = 2 # "str.str2unicode" + OS_SHRINK_ARRAY = 3 # rgc.ll_shrink_array # OS_STR_CONCAT = 22 # "stroruni.concat" OS_STR_SLICE = 23 # "stroruni.slice" @@ -82,8 +83,10 @@ OS_JIT_FORCE_VIRTUAL = 120 # for debugging: - _OS_CANRAISE = set([OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, - OS_RAW_MALLOC_VARSIZE_CHAR, OS_JIT_FORCE_VIRTUAL]) + _OS_CANRAISE = set([ + OS_NONE, OS_STR2UNICODE, OS_LIBFFI_CALL, OS_RAW_MALLOC_VARSIZE_CHAR, + OS_JIT_FORCE_VIRTUAL, OS_SHRINK_ARRAY, + ]) def __new__(cls, readonly_descrs_fields, readonly_descrs_arrays, write_descrs_fields, write_descrs_arrays, diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py --- a/rpython/jit/codewriter/jtransform.py +++ b/rpython/jit/codewriter/jtransform.py @@ -398,6 +398,8 @@ prepare = self._handle_libffi_call elif oopspec_name.startswith('math.sqrt'): prepare = self._handle_math_sqrt_call + elif oopspec_name.startswith('rgc.'): + prepare = self._handle_rgc_call else: prepare = self.prepare_builtin_call try: @@ -1779,6 +1781,12 @@ return self._handle_oopspec_call(op, args, EffectInfo.OS_MATH_SQRT, EffectInfo.EF_ELIDABLE_CANNOT_RAISE) + def _handle_rgc_call(self, op, oopspec_name, args): + if oopspec_name == 'rgc.ll_shrink_array': + return self._handle_oopspec_call(op, args, EffectInfo.OS_SHRINK_ARRAY, EffectInfo.EF_CAN_RAISE) + else: + raise NotImplementedError(oopspec_name) + def rewrite_op_jit_force_quasi_immutable(self, op): v_inst, c_fieldname = op.args descr1 = self.cpu.fielddescrof(v_inst.concretetype.TO, diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -136,6 +136,10 @@ assert size <= MAX_CONST_LEN self._chars = [None] * size + def shrink(self, length): + assert length >= 0 + del self._chars[length:] + def setup_slice(self, longerlist, start, stop): assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] @@ -554,6 +558,9 @@ if oopspecindex == EffectInfo.OS_STR2UNICODE: if self.opt_call_str_STR2UNICODE(op): return + if oopspecindex == EffectInfo.OS_SHRINK_ARRAY: + if self.opt_call_SHRINK_ARRAY(op): + return self.emit_operation(op) optimize_CALL_PURE = optimize_CALL @@ -721,6 +728,19 @@ return True return False + def opt_call_SHRINK_ARRAY(self, op): + v1 = self.getvalue(op.getarg(1)) + v2 = self.getvalue(op.getarg(2)) + # If the index is constant, if the argument is virtual (we only support + # VStringPlainValue for now) we can optimize away the call. + if v2.is_constant() and v1.is_virtual() and isinstance(v1, VStringPlainValue): + length = v2.box.getint() + v1.shrink(length) + self.last_emitted_operation = REMOVED + self.make_equal_to(op.result, v1) + return True + return False + def generate_modified_call(self, oopspecindex, args, result, mode): oopspecindex += mode.OS_offset cic = self.optimizer.metainterp_sd.callinfocollection diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py --- a/rpython/jit/metainterp/test/test_string.py +++ b/rpython/jit/metainterp/test/test_string.py @@ -1,16 +1,14 @@ import py -from rpython.jit.codewriter.policy import StopAtXPolicy -from rpython.jit.metainterp.test.support import LLJitMixin, OOJitMixin +from rpython.jit.metainterp.test.support import LLJitMixin from rpython.rlib.debug import debug_print -from rpython.rlib.jit import JitDriver, dont_look_inside, we_are_jitted,\ - promote_string -from rpython.rlib.rstring import StringBuilder -from rpython.rtyper.ootypesystem import ootype +from rpython.rlib.jit import (JitDriver, dont_look_inside, we_are_jitted, + promote_string) +from rpython.rlib.rstring import StringBuilder, UnicodeBuilder class StringTests: - _str, _chr = str, chr + _str, _chr, _StringBuilder = str, chr, StringBuilder def test_eq_residual(self): _str = self._str @@ -358,7 +356,7 @@ s1 = self.meta_interp(f, []) s2 = f() for c1, c2 in zip(s1.chars, s2): - assert c1==c2 + assert c1 == c2 def test_virtual_strings_boxed(self): _str = self._str @@ -516,6 +514,95 @@ self.meta_interp(f, [0]) self.check_resops(call=7) + def test_join_chars(self): + jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) + _str = self._str + + def f(a, b, c): + i = 0 + while i < 10: + jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) + x = [] + if a: + x.append(_str("a")) + if b: + x.append(_str("b")) + if c: + x.append(_str("c")) + i += len(_str("").join(x)) + return i + res = self.meta_interp(f, [1, 1, 1]) + assert res == f(True, True, True) + # The "".join should be unrolled, since the length of x is known since + # it is virtual, ensure there are no calls to ll_join_chars, or + # allocations. + self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, + 'int_add': 2, 'int_is_true': 3}) + + def test_virtual_copystringcontent(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord(b.build()[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_virtual_copystringcontent2(self): + jitdriver = JitDriver(reds=['n', 'result'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def main(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(6) + b.append(_str("Hello!")) + result += ord((b.build() + _str("xyz"))[0]) + n -= 1 + return result + res = self.meta_interp(main, [9]) + assert res == main(9) + + def test_bytearray(self): + py.test.skip("implement it") + + def f(i): + b = bytearray("abc") + b[1] = i + return b[1] + + res = self.interp_operations(f, [13]) + assert res == 13 + + def test_shrink_array(self): + jitdriver = JitDriver(reds=['result', 'n'], greens=[]) + _str, _StringBuilder = self._str, self._StringBuilder + + def f(n): + result = 0 + while n >= 0: + jitdriver.jit_merge_point(n=n, result=result) + b = _StringBuilder(20) + b.append(_str("Testing!")) + result += len(b.build()) + n -= 1 + return result + + res = self.meta_interp(f, [9]) + assert res == f(9) + self.check_resops({ + 'jump': 1, 'guard_true': 2, 'int_ge': 2, 'int_add': 2, 'int_sub': 2 + }) + + #class TestOOtype(StringTests, OOJitMixin): # CALL = "oosend" # CALL_PURE = "oosend_pure" @@ -524,8 +611,9 @@ CALL = "call" CALL_PURE = "call_pure" + class TestLLtypeUnicode(TestLLtype): - _str, _chr = unicode, unichr + _str, _chr, _StringBuilder = unicode, unichr, UnicodeBuilder def test_str2unicode(self): _str = self._str @@ -569,64 +657,3 @@ self.check_resops(call_pure=0, unicodesetitem=0, call=2, newunicode=0, unicodegetitem=0, copyunicodecontent=0) - - def test_join_chars(self): - jitdriver = JitDriver(reds=['a', 'b', 'c', 'i'], greens=[]) - def f(a, b, c): - i = 0 - while i < 10: - jitdriver.jit_merge_point(a=a, b=b, c=c, i=i) - x = [] - if a: - x.append("a") - if b: - x.append("b") - if c: - x.append("c") - i += len("".join(x)) - return i - res = self.meta_interp(f, [1, 1, 1]) - assert res == f(True, True, True) - # The "".join should be unrolled, since the length of x is known since - # it is virtual, ensure there are no calls to ll_join_chars, or - # allocations. - self.check_resops({'jump': 1, 'guard_true': 5, 'int_lt': 2, - 'int_add': 2, 'int_is_true': 3}) - - def test_virtual_copystringcontent(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord(b.build()[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_virtual_copystringcontent2(self): - jitdriver = JitDriver(reds=['n', 'result'], greens=[]) - def main(n): - result = 0 - while n >= 0: - jitdriver.jit_merge_point(n=n, result=result) - b = StringBuilder(6) - b.append("Hello!") - result += ord((b.build() + "xyz")[0]) - n -= 1 - return result - res = self.meta_interp(main, [9]) - assert res == main(9) - - def test_bytearray(self): - py.test.skip("implement it") - def f(i): - b = bytearray("abc") - b[1] = i - return b[1] - - res = self.interp_operations(f, [13]) - assert res == 13 diff --git a/rpython/rlib/rgc.py b/rpython/rlib/rgc.py --- a/rpython/rlib/rgc.py +++ b/rpython/rlib/rgc.py @@ -183,6 +183,7 @@ return True return False + @jit.oopspec('list.ll_arraycopy(source, dest, source_start, dest_start, length)') @enforceargs(None, None, int, int, int) @specialize.ll() @@ -229,6 +230,9 @@ keepalive_until_here(source) keepalive_until_here(dest) + + at jit.oopspec('rgc.ll_shrink_array(p, smallerlength)') + at specialize.ll() def ll_shrink_array(p, smallerlength): from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import keepalive_until_here @@ -249,16 +253,15 @@ ARRAY = getattr(TP, TP._arrayfld) offset = (llmemory.offsetof(TP, TP._arrayfld) + llmemory.itemoffsetof(ARRAY, 0)) - source_addr = llmemory.cast_ptr_to_adr(p) + offset - dest_addr = llmemory.cast_ptr_to_adr(newp) + offset + source_addr = llmemory.cast_ptr_to_adr(p) + offset + dest_addr = llmemory.cast_ptr_to_adr(newp) + offset llmemory.raw_memcopy(source_addr, dest_addr, llmemory.sizeof(ARRAY.OF) * smallerlength) keepalive_until_here(p) keepalive_until_here(newp) return newp -ll_shrink_array._annspecialcase_ = 'specialize:ll' -ll_shrink_array._jit_look_inside_ = False + def no_collect(func): func._dont_inline_ = True diff --git a/rpython/rtyper/module/ll_os.py b/rpython/rtyper/module/ll_os.py --- a/rpython/rtyper/module/ll_os.py +++ b/rpython/rtyper/module/ll_os.py @@ -682,7 +682,7 @@ @registering_if(os, 'getpid') def register_os_getpid(self): - return self.extdef_for_os_function_returning_int('getpid') + return self.extdef_for_os_function_returning_int('getpid', threadsafe=False) @registering_if(os, 'getgid') def register_os_getgid(self): From noreply at buildbot.pypy.org Fri May 24 00:16:51 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 24 May 2013 00:16:51 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130523221651.876921C00BD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64520:b2f349753621 Date: 2013-05-23 15:15 -0700 http://bitbucket.org/pypy/pypy/changeset/b2f349753621/ Log: merge default 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,5 +4,5 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "0.6" -__version_info__ = (0, 6) +__version__ = "0.7" +__version_info__ = (0, 7) 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 @@ -73,15 +73,15 @@ if name.startswith('RTLD_'): setattr(self, name, getattr(backend, name)) # - BVoidP = self._get_cached_btype(model.voidp_type) + self.BVoidP = self._get_cached_btype(model.voidp_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(BVoidP, 0) + FFI.NULL = self.cast(self.BVoidP, 0) FFI.CData, FFI.CType = backend._get_types() else: # ctypes backend: attach these constants to the instance - self.NULL = self.cast(BVoidP, 0) + self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() def cdef(self, csource, override=False): @@ -346,6 +346,12 @@ self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.append(']') + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + def _make_ffi_library(ffi, libname, flags): import os @@ -372,8 +378,8 @@ BType = ffi._get_cached_btype(tp) try: value = backendlib.load_function(BType, name) - except KeyError: - raise AttributeError(name) + except KeyError as e: + raise AttributeError('%s: %s' % (name, e)) library.__dict__[name] = value return # diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -16,6 +16,7 @@ class CTypesData(object): __metaclass__ = CTypesType __slots__ = ['__weakref__'] + __name__ = '' def __init__(self, *args): raise TypeError("cannot instantiate %r" % (self.__class__,)) @@ -491,6 +492,8 @@ elif BItem in (getbtype(model.PrimitiveType('signed char')), getbtype(model.PrimitiveType('unsigned char'))): kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' else: kind = 'generic' # @@ -546,13 +549,13 @@ def __setitem__(self, index, value): self._as_ctype_ptr[index] = BItem._to_ctypes(value) - if kind == 'charp': + if kind == 'charp' or kind == 'voidp': @classmethod - def _arg_to_ctypes(cls, value): - if isinstance(value, bytes): - return ctypes.c_char_p(value) + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) else: - return super(CTypesPtr, cls)._arg_to_ctypes(value) + return super(CTypesPtr, cls)._arg_to_ctypes(*value) if kind == 'charp' or kind == 'bytep': def _to_string(self, maxlen): diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -15,6 +15,20 @@ def patch_extension_kwds(self, kwds): pass + def find_module(self, module_name, path, so_suffix): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] != so_suffix: + return None + return filename + def collect_types(self): self._typesdict = {} self._generate("collecttype") @@ -427,9 +441,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -1,4 +1,4 @@ -import sys +import sys, os import types from . import model, ffiplatform @@ -20,6 +20,16 @@ # up in kwds['export_symbols']. kwds.setdefault('export_symbols', self.export_symbols) + def find_module(self, module_name, path, so_suffix): + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + return None + def collect_types(self): pass # not needed in the generic engine @@ -216,9 +226,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -102,21 +102,10 @@ path = pkg.__path__ else: path = None - try: - f, filename, descr = imp.find_module(self.get_module_name(), - path) - except ImportError: + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffix()) + if filename is None: return - if f is not None: - f.close() - if filename.lower().endswith('.py'): - # on PyPy, if there are both .py and .pypy-19.so files in - # the same directory, the .py file is returned. That's the - # case after a setuptools installation. We never want to - # load the .py file here... - filename = filename[:-3] + _get_so_suffix() - if not os.path.isfile(filename): - return self.modulefilename = filename self._vengine.collect_types() self._has_module = True diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -68,7 +68,8 @@ del working_modules["_minimal_curses"] del working_modules["_posixsubprocess"] -# del working_modules["cppyy"] # not tested on win32 + if "cppyy" in working_modules: + del working_modules["cppyy"] # not tested on win32 # The _locale module is needed by site.py on Windows default_modules["_locale"] = None @@ -81,7 +82,8 @@ del working_modules["_minimal_curses"] del working_modules["termios"] del working_modules["_multiprocessing"] # depends on rctime -# del working_modules["cppyy"] # depends on ctypes + if "cppyy" in working_modules: + del working_modules["cppyy"] # depends on ctypes module_dependencies = { diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -151,6 +151,7 @@ if w_fields == space.w_None: self.fields = None else: + self.fields = {} ofs_and_items = [] size = 0 for key in space.listview(w_fields): @@ -338,8 +339,9 @@ elif char == 'V': num = 20 basename = 'void' - w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - return dtype_from_list(space, space.newlist([])) + itemtype = types.VoidType(size) + return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(size), + "V", space.gettypefor(interp_boxes.W_VoidBox)) else: assert char == 'U' basename = 'unicode' diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -280,17 +280,6 @@ assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype - def test_pickle_record(self): - from numpypy import array, dtype - from cPickle import loads, dumps - - d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) - assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) - - new_d = loads(dumps(d)) - - assert new_d.__reduce__() == d.__reduce__() - class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): import numpypy as numpy @@ -768,6 +757,7 @@ assert isinstance(unicode_(3), str) class AppTestRecordDtypes(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): from numpypy import dtype, void @@ -814,6 +804,30 @@ assert dt.subdtype == (dtype(float), (10,)) assert dt.base == dtype(float) + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() + + def test_pickle_record_subarrays(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32", (3,)), ("y", "int32", (2,)), ("z", "int32", (4,)), ("value", float, (5,))]) + new_d = loads(dumps(d)) + + keys = d.fields.keys() + keys.sort() + assert keys == ["value", "x", "y", "z"] + + assert new_d.itemsize == d.itemsize == 76 + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.__func__(cls) diff --git a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py @@ -971,6 +971,16 @@ s.c = -4 assert s.c == -4 + def test_bitfield_enum(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef(""" + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_anonymous_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("typedef struct { int a; } foo_t;") diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -28,3 +28,12 @@ assert ffi.typeof("long(*)(long, long**, ...)").cname == ( "long(*)(long, long * *, ...)") assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True + + def test_new_handle(self): + ffi = FFI(backend=self.Backend()) + o = [2, 3, 4] + p = ffi.new_handle(o) + assert ffi.typeof(p) == ffi.typeof("void *") + assert ffi.from_handle(p) is o + assert ffi.from_handle(ffi.cast("char *", p)) is o + py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_function.py b/pypy/module/test_lib_pypy/cffi_tests/test_function.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_function.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_function.py @@ -334,6 +334,31 @@ assert lib.EE == -5 assert lib.FF == -4 + def test_void_star_accepts_string(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(const void *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + + def test_signed_char_star_accepts_string(self): + if self.Backend is CTypesBackend: + py.test.skip("not supported by the ctypes backend") + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(signed char *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + + def test_unsigned_char_star_accepts_string(self): + if self.Backend is CTypesBackend: + py.test.skip("not supported by the ctypes backend") + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(unsigned char *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + def test_missing_function(self): ffi = FFI(backend=self.Backend()) ffi.cdef(""" @@ -341,3 +366,19 @@ """) m = ffi.dlopen("m") assert not hasattr(m, 'nonexistent') + + def test_wraps_from_stdlib(self): + import functools + ffi = FFI(backend=self.Backend()) + ffi.cdef(""" + double sin(double x); + """) + def my_decorator(f): + @functools.wraps(f) + def wrapper(*args): + return f(*args) + 100 + return wrapper + m = ffi.dlopen("m") + sin100 = my_decorator(m.sin) + x = sin100(1.23) + assert x == math.sin(1.23) + 100 diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py @@ -522,6 +522,18 @@ py.test.raises(OverflowError, "s.b = 4") assert s.b == 3 +def test_struct_with_bitfield_enum(): + ffi = FFI() + code = """ + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """ + ffi.cdef(code) + ffi.verify(code) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_unsupported_struct_with_bitfield_ellipsis(): ffi = FFI() py.test.raises(NotImplementedError, ffi.cdef, diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py b/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py @@ -24,6 +24,12 @@ modules = ('cffi', '_cffi_backend') except ImportError: modules = ('cffi', '_cffi_backend', 'pycparser') + try: + import ply + except ImportError: + pass + else: + modules += ('ply',) # needed for older versions of pycparser for module in modules: target = imp.find_module(module)[1] os.symlink(target, os.path.join(site_packages, diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -3,8 +3,6 @@ from rpython.config.config import ChoiceOption, StrOption, Config from rpython.config.config import ConfigError from rpython.config.support import detect_number_of_processors -from rpython.jit.backend.detect_cpu import autodetect -from rpython.jit.backend.detect_cpu import MODEL_X86, MODEL_X86_NO_SSE2, MODEL_X86_64 DEFL_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() # and just small enough to prevend inlining of some rlist functions. @@ -15,9 +13,7 @@ DEFL_GC = "minimark" -_is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) - -if sys.platform.startswith("linux") and _is_x86: +if sys.platform.startswith("linux"): DEFL_ROOTFINDER_WITHJIT = "asmgcc" else: DEFL_ROOTFINDER_WITHJIT = "shadowstack" From noreply at buildbot.pypy.org Fri May 24 09:49:43 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:43 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: work on calls that release and reaquire the gil Message-ID: <20130524074943.506C81C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64521:f3faf8d05904 Date: 2013-05-22 10:56 -0500 http://bitbucket.org/pypy/pypy/changeset/f3faf8d05904/ Log: work on calls that release and reaquire the gil diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py --- a/rpython/jit/backend/arm/callbuilder.py +++ b/rpython/jit/backend/arm/callbuilder.py @@ -6,6 +6,7 @@ from rpython.jit.backend.arm.jump import remap_frame_layout from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.assembler import saved_registers from rpython.jit.backend.arm.helper.regalloc import check_imm_arg @@ -26,7 +27,6 @@ self.asm.push_gcmap(self.mc, gcmap, store=True) def pop_gcmap(self): - assert not self.is_call_release_gil self.asm._reload_frame_if_necessary(self.mc) self.asm.pop_gcmap(self.mc) @@ -69,19 +69,59 @@ self.mc.gen_load_int(r.ip.value, n, cond=fcond) self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value, cond=fcond) + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + + def call_releasegil_addr_and_move_real_arguments(self): + assert not self.asm._is_asmgcc() + from rpython.jit.backend.arm.regalloc import CoreRegisterManager + with saved_registers(self.mc, CoreRegisterManager.save_around_call_regs): + self.mc.BL(self.asm.releasegil_addr) + # + if not we_are_translated(): # for testing: we should not access + self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more + # + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got + assert not self.asm._is_asmgcc() + gpr_to_save, vfp_to_save = self.get_result_locs() + with saved_registers(self.mc, gpr_to_save, vfp_to_save): + self.mc.BL(self.asm.reacqgil_addr) + # + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again + # + # for shadowstack, done for us by _reload_frame_if_necessary() + + def get_result_locs(self): + raise NotImplementedError + class SoftFloatCallBuilder(ARMCallbuilder): + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [r.r0, r.r1], [] + assert self.resloc.is_reg() + return [r.r0], [] + def load_result(self): + # ensure the result is wellformed and stored in the correct location resloc = self.resloc - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg(): - # move result to the allocated register - self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg(): - self.asm._ensure_result_bit_extension(resloc, - self.ressize, self.ressigned) + if resloc is None: + return + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + # move result to the allocated register + if resloc is not r.r0: + self.asm.mov_loc_loc(r.r0, resloc) + self.asm._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) def _collect_stack_args(self, arglocs): @@ -140,10 +180,11 @@ num += 1 count += 1 # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later # If this happens to be the case we remap the register to r4 and use r4 # to call the function - if self.fnloc in non_float_regs: + if self.fnloc in non_float_regs or self.fnloc.is_stack(): non_float_locs.append(self.fnloc) non_float_regs.append(r.r4) self.fnloc = r.r4 @@ -195,10 +236,11 @@ on_stack += 1 self._push_stack_args(stack_args, on_stack*WORD) # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later # If this happens to be the case we remap the register to r4 and use r4 # to call the function - if self.fnloc in non_float_regs: + if self.fnloc in non_float_regs or self.fnloc.is_stack(): non_float_locs.append(self.fnloc) non_float_regs.append(r.r4) self.fnloc = r.r4 @@ -212,8 +254,15 @@ # ensure the result is wellformed and stored in the correct location if resloc is not None and resloc.is_reg(): self.asm._ensure_result_bit_extension(resloc, - self.ressize, self.ressigned) + self.ressize, self.ressign) + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [], [r.d0] + assert self.resloc.is_reg() + return [r.r0], [] def get_callbuilder(cpu, assembler, fnloc, arglocs, diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1032,10 +1032,10 @@ assert 0, 'xxx revisit this' # self._emit_call(op, callargs, fcond) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) + self._emit_guard_may_force(guard_op, arglocs[1 + numargs:]) return fcond - def _emit_guard_may_force(self, guard_op, arglocs, numargs): + def _emit_guard_may_force(self, guard_op, arglocs): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) @@ -1044,68 +1044,13 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): - + numargs = op.numargs() + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - self._emit_call(op, arglocs, result_loc, is_call_release_gil=True) - self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) + self._emit_call(op, arglocs, is_call_release_gil=True) + self._emit_guard_may_force(guard_op, guardargs) return fcond - # first, close the stack in the sense of the asmgcc GC root tracker - #gcrootmap = self.cpu.gc_ll_descr.gcrootmap - #numargs = op.numargs() - #callargs = arglocs[2:numargs + 1] # extract the arguments to the call - #adr = arglocs[1] - #resloc = arglocs[0] - - #if gcrootmap: - # # we put the gcmap now into the frame before releasing the GIL, - # # and pop it below after reacquiring the GIL. The assumption - # # is that this gcmap describes correctly the situation at any - # # point in-between: all values containing GC pointers should - # # be safely saved out of registers by now, and will not be - # # manipulated by any of the following CALLs. - # gcmap = self._regalloc.get_gcmap(noregs=True) - # self.push_gcmap(self.mc, gcmap, store=True) - # self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - ## do the call - #descr = op.getdescr() - #size = descr.get_result_size() - #signed = descr.is_result_signed() - ## - #self._emit_call(adr, callargs, fcond, - # resloc, (size, signed), - # is_call_release_gil=True) - ## then reopen the stack - #if gcrootmap: - # self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - # self.pop_gcmap(self.mc) # remove the gcmap saved above - - - def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): - # Save caller saved registers and do the call - # NOTE: We assume that the floating point registers won't be modified. - assert gcrootmap.is_shadow_stack - with saved_registers(self.mc, regalloc.rm.save_around_call_regs): - self._emit_call(imm(self.releasegil_addr), [], - fcond, is_call_release_gil=True) - - def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): - # save the previous result into the stack temporarily, in case it is in - # a caller saved register. - # NOTE: like with call_release_gil(), we assume that we don't need to - # save vfp regs in this case. Besides the result location - regs_to_save = [] - vfp_regs_to_save = [] - if save_loc and save_loc in regalloc.rm.save_around_call_regs: - regs_to_save.append(save_loc) - regs_to_save.append(r.ip) # for alingment - elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs: - vfp_regs_to_save.append(save_loc) - assert gcrootmap.is_shadow_stack - # call the reopenstack() function (also reacquiring the GIL) - with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): - self._emit_call(imm(self.reacqgil_addr), [], fcond, - is_call_release_gil=True) - self._reload_frame_if_necessary(self.mc) def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() 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 @@ -372,6 +372,9 @@ self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + def _is_asmgcc(self): + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + return bool(gcrootmap) and not gcrootmap.is_shadow_stack def debug_bridge(descr_number, rawstart, codeendpos): diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py --- a/rpython/jit/backend/llsupport/callbuilder.py +++ b/rpython/jit/backend/llsupport/callbuilder.py @@ -8,12 +8,13 @@ # is it for the main CALL of a call_release_gil? is_call_release_gil = False - # set by save_result_value() - tmpresloc = None + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + def __init__(self, assembler, fnloc, arglocs, resloc, restype, ressize): - # Avoid tons of issues with a non-immediate fnloc by sticking it - # as an extra argument if needed self.fnloc = fnloc self.arglocs = arglocs self.asm = assembler @@ -21,7 +22,6 @@ self.resloc = resloc self.restype = restype self.ressize = ressize - self.ressigned = False def emit_no_collect(self): """Emit a call that cannot collect.""" @@ -52,6 +52,12 @@ self.pop_gcmap() self.load_result() + def call_releasegil_addr_and_move_real_arguments(self): + raise NotImplementedError + + def move_real_result_and_call_reacqgil_addr(self): + raise NotImplementedError + def select_call_release_gil_mode(self): """Overridden in CallBuilder64""" self.is_call_release_gil = True @@ -62,6 +68,17 @@ def push_gcmap(self): raise NotImplementedError + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + def pop_gcmap(self): raise NotImplementedError diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -999,10 +999,6 @@ self.implement_guard(guard_token, checkfalsecond) return genop_cmp_guard_float - def _is_asmgcc(self): - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: result_type = FLOAT diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -19,23 +19,21 @@ return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - - class CallBuilderX86(AbstractCallBuilder): # max number of words we have room in esp; if we need more for # arguments, we need to decrease esp temporarily stack_max = PASS_ON_MY_FRAME - # this can be set to guide more complex calls: gives the detailed - # type of the arguments - argtypes = "" - ressign = False + # set by save_result_value() + tmpresloc = None def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT, ressize=WORD): AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, resloc, restype, ressize) + # Avoid tons of issues with a non-immediate fnloc by sticking it + # as an extra argument if needed self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) if not self.fnloc_is_immediate: self.fnloc = None @@ -96,17 +94,6 @@ gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) self.asm.push_gcmap(self.mc, gcmap, store=True) - def push_gcmap_for_call_release_gil(self): - assert self.is_call_release_gil - # we put the gcmap now into the frame before releasing the GIL, - # and pop it after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self.asm._regalloc.get_gcmap(noregs=True) - self.asm.push_gcmap(self.mc, gcmap, store=True) - def pop_gcmap(self): self.asm._reload_frame_if_necessary(self.mc) if self.change_extra_stack_depth: From noreply at buildbot.pypy.org Fri May 24 09:49:45 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:45 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: call_assembler support Message-ID: <20130524074945.1C4D01C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64522:fee3b922df85 Date: 2013-05-22 12:49 -0500 http://bitbucket.org/pypy/pypy/changeset/fee3b922df85/ Log: call_assembler support diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -27,6 +27,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.arm import callbuilder class AssemblerARM(ResOpAssembler): @@ -1417,6 +1418,21 @@ # return shiftsize + def simple_call(self, fnloc, arglocs, result_loc=r.r0): + if result_loc.is_vfp_reg(): + result_type = FLOAT + result_size = DOUBLE_WORD + elif result_loc is None: + result_type = VOID + result_size = 0 + else: + result_type = INT + result_size = WORD + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -942,14 +942,14 @@ vloc = imm(0) self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op), guard_op.numargs()) + regalloc._prepare_guard(guard_op)) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self.simple_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], result_loc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self.simple_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, result_loc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -560,18 +560,9 @@ calldescr = op.getdescr() assert isinstance(calldescr, CallDescr) assert len(calldescr.arg_classes) == op.numargs() - 1 + for i in range(op.numargs()): args[i + 3] = self.loc(op.getarg(i)) - # spill variables that need to be saved around calls - self.vfprm.before_call(save_all_regs=save_all_regs) - if not save_all_regs: - gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap - if gcrootmap and gcrootmap.is_shadow_stack: - save_all_regs = 2 - self.rm.before_call(save_all_regs=save_all_regs) - if op.result: - resloc = self.after_call(op.result) - args[0] = resloc size = calldescr.get_result_size() sign = calldescr.is_result_signed() @@ -581,8 +572,23 @@ sign_loc = imm(0) args[1] = imm(size) args[2] = sign_loc + + args[0] = self._call(op, args, force_store, save_all_regs) + return args + + def _call(self, op, arglocs, force_store=[], save_all_regs=False): + # spill variables that need to be saved around calls + self.vfprm.before_call(save_all_regs=save_all_regs) + if not save_all_regs: + gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap + if gcrootmap and gcrootmap.is_shadow_stack: + save_all_regs = 2 + self.rm.before_call(save_all_regs=save_all_regs) self.before_call_called = True - return args + resloc = None + if op.result: + resloc = self.after_call(op.result) + return resloc def prepare_op_call_malloc_gc(self, op, fcond): return self._prepare_call(op) @@ -1164,12 +1170,11 @@ prepare_guard_call_release_gil = prepare_guard_call_may_force def prepare_guard_call_assembler(self, op, guard_op, fcond): - assert 0, 'xxx needs checking' locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) - call_locs = self._prepare_call(op, save_all_regs=True) + resloc = self._call(op, locs + [tmploc], save_all_regs=True) self.possibly_free_vars(guard_op.getfailargs()) - return locs + [call_locs[0], tmploc] + return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr From noreply at buildbot.pypy.org Fri May 24 09:49:46 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:46 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: passing wrong arg here Message-ID: <20130524074946.8540F1C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64523:27efe60f7f7a Date: 2013-05-23 04:41 -0500 http://bitbucket.org/pypy/pypy/changeset/27efe60f7f7a/ Log: passing wrong arg here diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1045,10 +1045,10 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): numargs = op.numargs() - callargs = arglocs[:numargs + 3] # extract the arguments to the call + callargs = arglocs[:numargs + 3] # extract the arguments to the call guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - self._emit_call(op, arglocs, is_call_release_gil=True) + self._emit_call(op, callargs, is_call_release_gil=True) self._emit_guard_may_force(guard_op, guardargs) return fcond From noreply at buildbot.pypy.org Fri May 24 09:49:47 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:47 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: simple_call_no_collect Message-ID: <20130524074947.D73EE1C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64524:6648cc0bdf7e Date: 2013-05-23 04:42 -0500 http://bitbucket.org/pypy/pypy/changeset/6648cc0bdf7e/ Log: simple_call_no_collect diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -1433,6 +1433,11 @@ result_size) cb.emit() + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs) + cb.emit_no_collect() + + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) From noreply at buildbot.pypy.org Fri May 24 09:49:49 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:49 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: guard_call_may_force Message-ID: <20130524074949.26AAE1C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64525:e94293df0639 Date: 2013-05-23 06:39 -0500 http://bitbucket.org/pypy/pypy/changeset/e94293df0639/ Log: guard_call_may_force diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1028,11 +1028,11 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 3] # extract the arguments to the call - assert 0, 'xxx revisit this' + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # self._emit_call(op, callargs, fcond) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:]) + self._emit_guard_may_force(guard_op, guardargs) return fcond def _emit_guard_may_force(self, guard_op, arglocs): From noreply at buildbot.pypy.org Fri May 24 09:49:50 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:50 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: fixes and cleanup Message-ID: <20130524074950.9BA7B1C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64526:5440ae9341d9 Date: 2013-05-23 09:38 -0500 http://bitbucket.org/pypy/pypy/changeset/5440ae9341d9/ Log: fixes and cleanup diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT, VOID from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -935,23 +935,6 @@ asm_math_operations[oopspecindex](self, op, arglocs, regalloc, fcond) return fcond - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 4: - return - if size == 1: - if not signed: # unsigned char - self.mc.AND_ri(resloc.value, resloc.value, 0xFF) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 24) - self.mc.ASR_ri(resloc.value, resloc.value, 24) - elif size == 2: - if not signed: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.LSR_ri(resloc.value, resloc.value, 16) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.ASR_ri(resloc.value, resloc.value, 16) - def patch_trace(self, faildescr, looptoken, bridge_addr, regalloc): b = InstrBuilder(self.cpu.cpuinfo.arch_version) patch_addr = faildescr._arm_failure_recovery_block @@ -1072,6 +1055,7 @@ save_helper = not is_imm and helper is r.ip else: assert 0, 'unsupported case' + if save_helper: self.mc.PUSH([helper.value], cond=cond) self.load_reg(self.mc, loc, r.fp, offset, cond=cond, helper=helper) diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py --- a/rpython/jit/backend/arm/callbuilder.py +++ b/rpython/jit/backend/arm/callbuilder.py @@ -1,6 +1,6 @@ from rpython.rlib.clibffi import FFI_DEFAULT_ABI from rpython.rlib.objectmodel import we_are_translated -from rpython.jit.metainterp.history import INT, FLOAT +from rpython.jit.metainterp.history import INT, FLOAT, REF from rpython.jit.backend.arm.arch import WORD from rpython.jit.backend.arm import registers as r from rpython.jit.backend.arm.jump import remap_frame_layout @@ -97,6 +97,24 @@ def get_result_locs(self): raise NotImplementedError + def _ensure_result_bit_extension(self, resloc, size, signed): + if size == 4: + return + if size == 1: + if not signed: # unsigned char + self.mc.AND_ri(resloc.value, resloc.value, 0xFF) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 24) + self.mc.ASR_ri(resloc.value, resloc.value, 24) + elif size == 2: + if not signed: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.LSR_ri(resloc.value, resloc.value, 16) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.ASR_ri(resloc.value, resloc.value, 16) + + class SoftFloatCallBuilder(ARMCallbuilder): @@ -120,11 +138,11 @@ # move result to the allocated register if resloc is not r.r0: self.asm.mov_loc_loc(r.r0, resloc) - self.asm._ensure_result_bit_extension(resloc, + self._ensure_result_bit_extension(resloc, self.ressize, self.ressign) - def _collect_stack_args(self, arglocs): + def _collect_and_push_stack_args(self, arglocs): n_args = len(arglocs) reg_args = count_reg_args(arglocs) # all arguments past the 4th go on the stack @@ -152,6 +170,7 @@ self._push_stack_args(stack_args, on_stack*WORD) def prepare_arguments(self): + arglocs = self.arglocs reg_args = count_reg_args(arglocs) self._collect_and_push_stack_args(arglocs) # collect variables that need to go in registers and the registers they @@ -253,7 +272,7 @@ resloc = self.resloc # ensure the result is wellformed and stored in the correct location if resloc is not None and resloc.is_reg(): - self.asm._ensure_result_bit_extension(resloc, + self._ensure_result_bit_extension(resloc, self.ressize, self.ressign) def get_result_locs(self): From noreply at buildbot.pypy.org Fri May 24 09:49:52 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:52 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: do not emit instructions if we are moving to the same location in SAME_AS Message-ID: <20130524074952.1304E1C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64527:191546eab161 Date: 2013-05-23 13:58 -0500 http://bitbucket.org/pypy/pypy/changeset/191546eab161/ Log: do not emit instructions if we are moving to the same location in SAME_AS diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -365,7 +365,8 @@ def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs - self.mov_loc_loc(argloc, resloc) + if argloc is not resloc: + self.mov_loc_loc(argloc, resloc) return fcond emit_op_cast_ptr_to_int = emit_op_same_as From noreply at buildbot.pypy.org Fri May 24 09:49:54 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:54 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: add a location to directly access the stack based on sp Message-ID: <20130524074954.5A3231C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64528:73b3305ea5f3 Date: 2013-05-23 14:02 -0500 http://bitbucket.org/pypy/pypy/changeset/73b3305ea5f3/ Log: add a location to directly access the stack based on sp diff --git a/rpython/jit/backend/arm/locations.py b/rpython/jit/backend/arm/locations.py --- a/rpython/jit/backend/arm/locations.py +++ b/rpython/jit/backend/arm/locations.py @@ -12,6 +12,9 @@ def is_stack(self): return False + def is_raw_sp(self): + return False + def is_reg(self): return False @@ -145,7 +148,27 @@ return self.position + 10000 def is_float(self): - return type == FLOAT + return self.type == FLOAT + +class RawSPStackLocation(AssemblerLocation): + _immutable_ = True + + def __init__(self, sp_offset, type=INT): + if type == FLOAT: + self.width = DOUBLE_WORD + else: + self.width = WORD + self.value = sp_offset + self.type = type + + def __repr__(self): + return 'SP(%s)+%d' % (self.type, self.value,) + + def is_raw_sp(self): + return True + + def is_float(self): + return self.type == FLOAT def imm(i): From noreply at buildbot.pypy.org Fri May 24 09:49:55 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:55 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: support raw stacklocations when moving stuff around and redung the number of redundant loads and stores Message-ID: <20130524074955.D35771C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64529:207b50e53ec8 Date: 2013-05-23 14:03 -0500 http://bitbucket.org/pypy/pypy/changeset/207b50e53ec8/ Log: support raw stacklocations when moving stuff around and redung the number of redundant loads and stores diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -996,20 +996,32 @@ mc.gen_load_int(helper.value, ofs, cond=cond) mc.STR_rr(source.value, base.value, helper.value, cond=cond) + def get_tmp_reg(self, forbidden_regs=None): + if forbidden_regs is None: + return r.ip, False + for x in [r.ip, r.lr]: + if x not in forbidden_regs: + return x, False + # pick some reg, that we need to save + for x in r.all_regs: + if x not in forbidden_regs: + return x, True + assert 0 + def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL): - if not loc.is_reg() and not (loc.is_stack() and loc.type != FLOAT): + if loc.type == FLOAT: raise AssertionError("invalid target for move from imm value") if loc.is_reg(): new_loc = loc - elif loc.is_stack(): - self.mc.PUSH([r.lr.value], cond=cond) + elif loc.is_stack() or loc.is_raw_sp(): new_loc = r.lr else: raise AssertionError("invalid target for move from imm value") self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond) if loc.is_stack(): self.regalloc_mov(new_loc, loc) - self.mc.POP([r.lr.value], cond=cond) + elif loc.is_raw_sp(): + self.store_reg(self.mc, new_loc, r.sp, loc.value, cond=cond, helper=r.ip) def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_imm(): @@ -1018,41 +1030,48 @@ self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond) elif loc.is_stack() and loc.type != FLOAT: # spill a core register - if prev_loc is r.ip: - temp = r.lr - else: - temp = r.ip + temp, save = self.get_tmp_reg([prev_loc, loc]) offset = loc.value is_imm = check_imm_arg(offset, size=0xFFF) - if not is_imm: + if not is_imm and save: self.mc.PUSH([temp.value], cond=cond) self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) - if not is_imm: + if not is_imm and save: self.mc.POP([temp.value], cond=cond) + elif loc.is_raw_sp(): + temp, save = self.get_tmp_reg([prev_loc]) + assert not save + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) else: assert 0, 'unsupported case' def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL): - # disabled for now, has side effects in combination with remap_frame_layout when called from a jump - helper = None # self._regalloc.get_free_reg() + helper = None + offset = prev_loc.value + tmp = None if loc.is_reg(): assert prev_loc.type != FLOAT, 'trying to load from an \ incompatible location into a core register' - assert loc is not r.lr, 'lr is not supported as a target \ - when moving from the stack' # unspill a core register - offset = prev_loc.value is_imm = check_imm_arg(offset, size=0xFFF) - helper = r.lr if helper is None else helper - save_helper = not is_imm and helper is r.lr + helper, save = self.get_tmp_reg([loc]) + save_helper = not is_imm and save elif loc.is_vfp_reg(): assert prev_loc.type == FLOAT, 'trying to load from an \ incompatible location into a float register' # load spilled value into vfp reg - offset = prev_loc.value is_imm = check_imm_arg(offset) - helper = r.ip if helper is None else helper - save_helper = not is_imm and helper is r.ip + helper, save = self.get_tmp_reg() + save_helper = not is_imm and save + elif loc.is_raw_sp(): + tmp = loc + if loc.is_float(): + loc = r.vfp_ip + else: + loc, save_helper = self.get_tmp_reg() + assert not save_helper + helper, save_helper = self.get_tmp_reg([loc]) + assert not save_helper else: assert 0, 'unsupported case' @@ -1062,17 +1081,24 @@ if save_helper: self.mc.POP([helper.value], cond=cond) + if tmp and tmp.is_raw_sp(): + self.store_reg(self.mc, loc, r.sp, tmp.value, cond=cond, helper=helper) + def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_vfp_reg(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond) - self.load_reg(self.mc, loc, r.ip, 0, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([loc]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, prev_loc.getint(), cond=cond) + self.load_reg(self.mc, loc, helper, 0, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif loc.is_stack(): - self.regalloc_push(r.vfp_ip) self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - self.regalloc_pop(r.vfp_ip) + elif loc.is_raw_sp(): + self.regalloc_mov(prev_loc, r.vfp_ip, cond) + self.regalloc_mov(r.vfp_ip, loc, cond) else: assert 0, 'unsupported case' @@ -1085,11 +1111,9 @@ # spill vfp register offset = loc.value is_imm = check_imm_arg(offset) - if not is_imm: - self.mc.PUSH([r.ip.value], cond=cond) - self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond) - if not is_imm: - self.mc.POP([r.ip.value], cond=cond) + self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) + elif loc.is_raw_sp(): + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' @@ -1105,6 +1129,8 @@ self._mov_imm_float_to_loc(prev_loc, loc, cond) elif prev_loc.is_vfp_reg(): self._mov_vfp_reg_to_loc(prev_loc, loc, cond) + elif prev_loc.is_raw_sp(): + assert 0, 'raw sp locs are not supported as source loc' else: assert 0, 'unsupported case' mov_loc_loc = regalloc_mov @@ -1116,23 +1142,29 @@ if vfp_loc.is_vfp_reg(): self.mc.VMOV_rc(reg1.value, reg2.value, vfp_loc.value, cond=cond) elif vfp_loc.is_imm_float(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, vfp_loc.getint(), cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, vfp_loc.getint(), cond=cond) # we need to load one word to loc and one to loc+1 which are # two 32-bit core registers - self.mc.LDR_ri(reg1.value, r.ip.value, cond=cond) - self.mc.LDR_ri(reg2.value, r.ip.value, imm=WORD, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + self.mc.LDR_ri(reg1.value, helper.value, cond=cond) + self.mc.LDR_ri(reg2.value, helper.value, imm=WORD, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif vfp_loc.is_stack() and vfp_loc.type == FLOAT: # load spilled vfp value into two core registers offset = vfp_loc.value if not check_imm_arg(offset, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.LDR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.LDR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.LDR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.LDR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.LDR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.LDR_ri(reg2.value, r.fp.value, @@ -1150,12 +1182,15 @@ # move from two core registers to a float stack location offset = vfp_loc.value if not check_imm_arg(offset + WORD, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.STR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.STR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.STR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.STR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.STR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.STR_ri(reg2.value, r.fp.value, From noreply at buildbot.pypy.org Fri May 24 09:49:57 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:57 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: use raw stacklocations to put arguments on the stack instead of doing a push for each Message-ID: <20130524074957.523BD1C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64530:940f2722fec6 Date: 2013-05-23 14:03 -0500 http://bitbucket.org/pypy/pypy/changeset/940f2722fec6/ Log: use raw stacklocations to put arguments on the stack instead of doing a push for each diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py --- a/rpython/jit/backend/arm/callbuilder.py +++ b/rpython/jit/backend/arm/callbuilder.py @@ -3,6 +3,8 @@ from rpython.jit.metainterp.history import INT, FLOAT, REF from rpython.jit.backend.arm.arch import WORD from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm.locations import RawSPStackLocation from rpython.jit.backend.arm.jump import remap_frame_layout from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder from rpython.jit.backend.arm.helper.assembler import count_reg_args @@ -50,24 +52,32 @@ def _push_stack_args(self, stack_args, on_stack): assert on_stack % 8 == 0 - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.asm.regalloc_push(arg) - self.current_sp -= on_stack + self._adjust_sp(-on_stack) + self.current_sp = on_stack + ofs = 0 + for i, arg in enumerate(stack_args): + if arg is not None: + sp_loc = RawSPStackLocation(ofs, arg.type) + self.asm.regalloc_mov(arg, sp_loc) + ofs += sp_loc.width + else: # alignment word + ofs += WORD def _adjust_sp(self, n): - assert n < 0 - n = abs(n) - - if check_imm_arg(n): - self.mc.ADD_ri(r.sp.value, r.sp.value, n) + # adjust the current stack pointer by n bytes + if n > 0: + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value) else: - self.mc.gen_load_int(r.ip.value, n, cond=fcond) - self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value, cond=fcond) + n = abs(n) + if check_imm_arg(n): + self.mc.SUB_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value) def select_call_release_gil_mode(self): AbstractCallBuilder.select_call_release_gil_mode(self) @@ -75,12 +85,12 @@ def call_releasegil_addr_and_move_real_arguments(self): assert not self.asm._is_asmgcc() from rpython.jit.backend.arm.regalloc import CoreRegisterManager - with saved_registers(self.mc, CoreRegisterManager.save_around_call_regs): + with saved_registers(self.mc, + CoreRegisterManager.save_around_call_regs): self.mc.BL(self.asm.releasegil_addr) - # + if not we_are_translated(): # for testing: we should not access self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more - # def move_real_result_and_call_reacqgil_addr(self): # save the result we just got @@ -88,10 +98,10 @@ gpr_to_save, vfp_to_save = self.get_result_locs() with saved_registers(self.mc, gpr_to_save, vfp_to_save): self.mc.BL(self.asm.reacqgil_addr) - # + if not we_are_translated(): # for testing: now we can accesss self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again - # + # for shadowstack, done for us by _reload_frame_if_necessary() def get_result_locs(self): From noreply at buildbot.pypy.org Fri May 24 09:49:58 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:49:58 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: swap checks Message-ID: <20130524074958.CE67B1C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64531:37592fdca826 Date: 2013-05-23 15:34 -0500 http://bitbucket.org/pypy/pypy/changeset/37592fdca826/ Log: swap checks diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -1438,12 +1438,12 @@ return shiftsize def simple_call(self, fnloc, arglocs, result_loc=r.r0): - if result_loc.is_vfp_reg(): + if result_loc is None: + result_type = VOID + result_size = 0 + elif result_loc.is_vfp_reg(): result_type = FLOAT result_size = DOUBLE_WORD - elif result_loc is None: - result_type = VOID - result_size = 0 else: result_type = INT result_size = WORD From noreply at buildbot.pypy.org Fri May 24 09:50:00 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 09:50:00 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: fix Message-ID: <20130524075000.616421C094F@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64532:ab0b1b7f0c82 Date: 2013-05-23 16:29 -0500 http://bitbucket.org/pypy/pypy/changeset/ab0b1b7f0c82/ Log: fix diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -1032,7 +1032,7 @@ callargs = arglocs[:numargs + 3] # extract the arguments to the call guardargs = arglocs[len(callargs):] # - self._emit_call(op, callargs, fcond) + self._emit_call(op, callargs, fcond=fcond) self._emit_guard_may_force(guard_op, guardargs) return fcond From noreply at buildbot.pypy.org Fri May 24 10:31:54 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 24 May 2013 10:31:54 +0200 (CEST) Subject: [pypy-commit] pypy default: Finally get rid of the large code duplication (with bug reported even Message-ID: <20130524083154.67B4B1C23F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64533:51490363a945 Date: 2013-05-24 10:30 +0200 http://bitbucket.org/pypy/pypy/changeset/51490363a945/ Log: Finally get rid of the large code duplication (with bug reported even nowadays) in pypy/interpreter/pyparser/future.py. diff --git a/pypy/interpreter/pyparser/future.py b/pypy/interpreter/pyparser/future.py --- a/pypy/interpreter/pyparser/future.py +++ b/pypy/interpreter/pyparser/future.py @@ -1,307 +1,3 @@ -""" -This automaton is designed to be invoked on a Python source string -before the real parser starts working, in order to find all legal -'from __future__ import blah'. As soon as something is encountered that -would prevent more future imports, the analysis is aborted. -The resulting legal futures are avaliable in self.flags after the -pass has ended. - -Invocation is through get_futures(src), which returns a field of flags, one per -found correct future import. - -The flags can then be used to set up the parser. -All error detection is left to the parser. - -The reason we are not using the regular lexer/parser toolchain is that -we do not want the overhead of generating tokens for entire files just -to find information that resides in the first few lines of the file. -Neither do we require sane error messages, as this job is handled by -the parser. - -To make the parsing fast, especially when the module is translated to C, -the code has been written in a very serial fashion, using an almost -assembler like style. A further speedup could be achieved by replacing -the "in" comparisons with explicit numeric comparisons. -""" - -from pypy.interpreter.astcompiler.consts import CO_GENERATOR_ALLOWED, \ - CO_FUTURE_DIVISION, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_ABSOLUTE_IMPORT - -def get_futures(future_flags, source): - futures = FutureAutomaton(future_flags, source) - try: - futures.start() - except DoneException, e: - pass - return futures.flags, (futures.lineno, futures.col_offset) - -class DoneException(Exception): - pass - -whitespace = ' \t\f' -whitespace_or_newline = whitespace + '\n\r' -letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz_' -alphanumerics = letters + '1234567890' - -class FutureAutomaton(object): - """ - A future statement must appear near the top of the module. - The only lines that can appear before a future statement are: - - * the module docstring (if any), - * comments, - * blank lines, and - * other future statements. - - The features recognized by Python 2.5 are "generators", - "division", "nested_scopes" and "with_statement", "absolute_import". - "generators", "division" and "nested_scopes" are redundant - in 2.5 because they are always enabled. - - This module parses the input until it encounters something that is - not recognized as a valid future statement or something that may - precede a future statement. - """ - - def __init__(self, future_flags, string): - self.future_flags = future_flags - self.s = string - self.pos = 0 - self.current_lineno = 1 - self.lineno = -1 - self.line_start_pos = 0 - self.col_offset = 0 - self.docstring_consumed = False - self.flags = 0 - self.got_features = 0 - - def getc(self, offset=0): - try: - return self.s[self.pos + offset] - except IndexError: - raise DoneException - - def start(self): - c = self.getc() - if c in ("'", '"', "r", "u") and not self.docstring_consumed: - self.consume_docstring() - elif c == '\\' or c in whitespace_or_newline: - self.consume_empty_line() - elif c == '#': - self.consume_comment() - elif c == 'f': - self.consume_from() - else: - return - - def atbol(self): - self.current_lineno += 1 - self.line_start_pos = self.pos - - def consume_docstring(self): - self.docstring_consumed = True - if self.getc() == "r": - self.pos += 1 - if self.getc() == "u": - self.pos += 1 - endchar = self.getc() - if (self.getc() == self.getc(+1) and - self.getc() == self.getc(+2)): - self.pos += 3 - while 1: # Deal with a triple quoted docstring - c = self.getc() - if c == '\\': - self.pos += 1 - self._skip_next_char_from_docstring() - elif c != endchar: - self._skip_next_char_from_docstring() - else: - self.pos += 1 - if (self.getc() == endchar and - self.getc(+1) == endchar): - self.pos += 2 - self.consume_empty_line() - break - - else: # Deal with a single quoted docstring - self.pos += 1 - while 1: - c = self.getc() - self.pos += 1 - if c == endchar: - self.consume_empty_line() - return - elif c == '\\': - self._skip_next_char_from_docstring() - elif c in '\r\n': - # Syntax error - return - - def _skip_next_char_from_docstring(self): - c = self.getc() - self.pos += 1 - if c == '\n': - self.atbol() - elif c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - - def consume_continuation(self): - c = self.getc() - if c in '\n\r': - self.pos += 1 - self.atbol() - - def consume_empty_line(self): - """ - Called when the remainder of the line can only contain whitespace - and comments. - """ - while self.getc() in whitespace: - self.pos += 1 - if self.getc() == '#': - self.consume_comment() - elif self.getc() == ';': - self.pos += 1 - self.consume_whitespace() - self.start() - elif self.getc() in '\\': - self.pos += 1 - self.consume_continuation() - self.start() - elif self.getc() in '\r\n': - c = self.getc() - self.pos += 1 - if c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - else: - self.atbol() - self.start() - - def consume_comment(self): - self.pos += 1 - while self.getc() not in '\r\n': - self.pos += 1 - self.consume_empty_line() - - def consume_from(self): - col_offset = self.pos - self.line_start_pos - line = self.current_lineno - self.pos += 1 - if self.getc() == 'r' and self.getc(+1) == 'o' and self.getc(+2) == 'm': - self.docstring_consumed = True - self.pos += 3 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+10] != '__future__': - raise DoneException - self.pos += 10 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+6] != 'import': - raise DoneException - self.pos += 6 - self.consume_whitespace() - old_got = self.got_features - try: - if self.getc() == '(': - self.pos += 1 - self.consume_whitespace() - self.set_flag(self.get_name()) - # Set flag corresponding to name - self.get_more(paren_list=True) - else: - self.set_flag(self.get_name()) - self.get_more() - finally: - if self.got_features > old_got: - self.col_offset = col_offset - self.lineno = line - self.consume_empty_line() - - def consume_mandatory_whitespace(self): - if self.getc() not in whitespace + '\\': - raise DoneException - self.consume_whitespace() - - def consume_whitespace(self, newline_ok=False): - while 1: - c = self.getc() - if c in whitespace: - self.pos += 1 - continue - elif c == '\\' or newline_ok: - slash = c == '\\' - if slash: - self.pos += 1 - c = self.getc() - if c == '\n': - self.pos += 1 - self.atbol() - continue - elif c == '\r': - self.pos += 1 - if self.getc() == '\n': - self.pos += 1 - self.atbol() - elif slash: - raise DoneException - else: - return - else: - return - - def get_name(self): - if self.getc() not in letters: - raise DoneException - p = self.pos - try: - while self.getc() in alphanumerics: - self.pos += 1 - except DoneException: - # If there's any name at all, we want to call self.set_flag(). - # Something else while get the DoneException again. - if self.pos == p: - raise - end = self.pos - else: - end = self.pos - self.consume_whitespace() - return self.s[p:end] - - def get_more(self, paren_list=False): - if paren_list and self.getc() == ')': - self.pos += 1 - return - if (self.getc() == 'a' and - self.getc(+1) == 's' and - self.getc(+2) in whitespace): - self.get_name() - self.get_name() - self.get_more(paren_list=paren_list) - return - elif self.getc() != ',': - return - else: - self.pos += 1 - self.consume_whitespace(paren_list) - if paren_list and self.getc() == ')': - self.pos += 1 - return # Handles trailing comma inside parenthesis - self.set_flag(self.get_name()) - self.get_more(paren_list=paren_list) - - def set_flag(self, feature): - self.got_features += 1 - try: - self.flags |= self.future_flags.compiler_features[feature] - except KeyError: - pass - -from codeop import PyCF_DONT_IMPLY_DEDENT -from pypy.interpreter.error import OperationError - from pypy.tool import stdlib___future__ as future class FutureFlags(object): @@ -327,6 +23,81 @@ flag_names.append(name) return flag_names + def get_compiler_feature(self, name): + return self.compiler_features.get(name, 0) + futureFlags_2_4 = FutureFlags((2, 4, 4, 'final', 0)) futureFlags_2_5 = FutureFlags((2, 5, 0, 'final', 0)) futureFlags_2_7 = FutureFlags((2, 7, 0, 'final', 0)) + + +class TokenIterator: + def __init__(self, tokens): + self.tokens = tokens + self.index = 0 + self.next() + + def next(self): + index = self.index + self.index = index + 1 + self.tok = self.tokens[index] + + def skip(self, n): + if self.tok[0] == n: + self.next() + return True + else: + return False + + def skip_name(self, name): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME and self.tok[1] == name: + self.next() + return True + else: + return False + + def next_feature_name(self): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME: + name = self.tok[1] + self.next() + if self.skip_name("as"): + self.skip(pygram.tokens.NAME) + return name + else: + return '' + + def skip_newlines(self): + from pypy.interpreter.pyparser import pygram + while self.skip(pygram.tokens.NEWLINE): + pass + + +def add_future_flags(future_flags, tokens): + from pypy.interpreter.pyparser import pygram + it = TokenIterator(tokens) + result = 0 + # + # The only things that can precede a future statement are another + # future statement and a doc string (only one). This is a very + # permissive parsing of the given list of tokens; it relies on + # the real parsing done afterwards to give errors. + it.skip_newlines() + it.skip_name("r") or it.skip_name("u") or it.skip_name("ru") + if it.skip(pygram.tokens.STRING): + it.skip_newlines() + + while (it.skip_name("from") and + it.skip_name("__future__") and + it.skip_name("import")): + it.skip(pygram.tokens.LPAR) # optionally + result |= future_flags.get_compiler_feature(it.next_feature_name()) + while it.skip(pygram.tokens.COMMA): + result |= future_flags.get_compiler_feature(it.next_feature_name()) + it.skip(pygram.tokens.RPAR) # optionally + it.skip(pygram.tokens.SEMI) # optionally + it.skip_newlines() + + position = (it.tok[2], it.tok[3]) + return result, position diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py --- a/pypy/interpreter/pyparser/pyparse.py +++ b/pypy/interpreter/pyparser/pyparse.py @@ -135,17 +135,8 @@ raise error.SyntaxError(space.str_w(w_message)) raise - f_flags, future_info = future.get_futures(self.future_flags, textsrc) - compile_info.last_future_import = future_info - compile_info.flags |= f_flags - flags = compile_info.flags - if flags & consts.CO_FUTURE_PRINT_FUNCTION: - self.grammar = pygram.python_grammar_no_print - else: - self.grammar = pygram.python_grammar - # The tokenizer is very picky about how it wants its input. source_lines = textsrc.splitlines(True) if source_lines and not source_lines[-1].endswith("\n"): @@ -157,7 +148,21 @@ tp = 0 try: try: + # Note: we no longer pass the CO_FUTURE_* to the tokenizer, + # which is expected to work independently of them. It's + # certainly the case for all futures in Python <= 2.7. tokens = pytokenizer.generate_tokens(source_lines, flags) + + newflags, last_future_import = ( + future.add_future_flags(self.future_flags, tokens)) + compile_info.last_future_import = last_future_import + compile_info.flags |= newflags + + if compile_info.flags & consts.CO_FUTURE_PRINT_FUNCTION: + self.grammar = pygram.python_grammar_no_print + else: + self.grammar = pygram.python_grammar + for tp, value, lineno, column, line in tokens: if self.add_token(tp, value, lineno, column, line): break diff --git a/pypy/interpreter/pyparser/test/test_futureautomaton.py b/pypy/interpreter/pyparser/test/test_future.py rename from pypy/interpreter/pyparser/test/test_futureautomaton.py rename to pypy/interpreter/pyparser/test/test_future.py --- a/pypy/interpreter/pyparser/test/test_futureautomaton.py +++ b/pypy/interpreter/pyparser/test/test_future.py @@ -1,29 +1,26 @@ import py -import pypy.interpreter.pyparser.future as future +from pypy.interpreter.pyparser import future, pytokenizer from pypy.tool import stdlib___future__ as fut -def run(s): - f = future.FutureAutomaton(future.futureFlags_2_7, s) - try: - f.start() - except future.DoneException: - pass - return f +def run(s, expected_last_future=None): + source_lines = s.splitlines(True) + tokens = pytokenizer.generate_tokens(source_lines, 0) + expected_last_future = expected_last_future or tokens[-1][2:4] + # + flags, last_future_import = future.add_future_flags( + future.futureFlags_2_7, tokens) + assert last_future_import == expected_last_future + return flags def test_docstring(): s = '"Docstring\\" "\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_comment(): s = '# A comment about nothing ;\n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_tripledocstring(): s = '''""" This is a @@ -31,9 +28,7 @@ breaks in it. It even has a \n""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_escapedquote_in_tripledocstring(): s = '''""" This is a @@ -41,233 +36,176 @@ breaks in it. \\"""It even has an escaped quote!""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_empty_line(): s = ' \t \f \n \n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_from(): s = 'from __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms(): s = 'from __future__ import division, generators, with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_from_as(): s = 'from __future__ import division as b\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_as(): s = 'from __future__ import division as b, generators as c\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_from_paren(): s = 'from __future__ import (division)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_paren(): s = 'from __future__ import (division, generators)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_froms_paren_as(): s = 'from __future__ import (division as b, generators,)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_paren_with_newline(): s = 'from __future__ import (division,\nabsolute_import)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) + +def test_paren_with_newline_2(): + s = 'from __future__ import (\ndivision,\nabsolute_import)\n' + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) def test_multiline(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,)\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_windows_style_lineendings(): s = '"abc" #def\r\n #ghi\r\nfrom __future__ import (division as b, generators,)\r\nfrom __future__ import with_statement\r\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_mac_style_lineendings(): s = '"abc" #def\r #ghi\rfrom __future__ import (division as b, generators,)\rfrom __future__ import with_statement\r' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_semicolon(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 3 - assert f.col_offset == 55 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) + +def test_semicolon_2(): + s = 'from __future__ import division; from foo import bar' + f = run(s, expected_last_future=(1, 39)) + assert f == fut.CO_FUTURE_DIVISION def test_full_chain(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert pos == (3, 55) + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_intervening_code(): s = 'from __future__ import (division as b, generators,)\nfrom sys import modules\nfrom __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags & fut.CO_FUTURE_WITH_STATEMENT == 0 - assert pos == (1, 0) + f = run(s, expected_last_future=(2, 5)) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_GENERATOR_ALLOWED) def test_nonexisting(): s = 'from __future__ import non_existing_feature\n' f = run(s) - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == 0 + +def test_nonexisting_2(): + s = 'from __future__ import non_existing_feature, with_statement\n' + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_from_import_abs_import(): s = 'from __future__ import absolute_import\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_ABSOLUTE_IMPORT - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_ABSOLUTE_IMPORT def test_raw_doc(): s = 'r"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_unicode_doc(): s = 'u"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_raw_unicode_doc(): s = 'ru"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_line(): s = "\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_lines(): s = "\\\n \t\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 3 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_lots_of_continuation_lines(): s = "\\\n\\\n\\\n\\\n\\\n\\\n\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT -# This looks like a bug in cpython parser -# and would require extensive modifications -# to future.py in order to emulate the same behaviour def test_continuation_lines_raise(): - py.test.skip("probably a CPython bug") s = " \\\n \t\\\nfrom __future__ import with_statement\n" - try: - f = run(s) - except IndentationError, e: - assert e.args == 'unexpected indent' - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == -1 - assert f.col_offset == 0 - else: - raise AssertionError('IndentationError not raised') - assert f.lineno == 2 - assert f.col_offset == 0 + f = run(s, expected_last_future=(1, 0)) + assert f == 0 # because of the INDENT def test_continuation_lines_in_docstring_single_quoted(): s = '"\\\n\\\n\\\n\\\n\\\n\\\n"\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_continuation_lines_in_docstring_triple_quoted(): s = '"""\\\n\\\n\\\n\\\n\\\n\\\n"""\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION + +def test_blank_lines(): + s = ('\n\t\n\nfrom __future__ import with_statement' + ' \n \n \nfrom __future__ import division') + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT | fut.CO_FUTURE_DIVISION + +def test_dummy_semicolons(): + s = ('from __future__ import division;\n' + 'from __future__ import with_statement;') + f = run(s) + assert f == fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_WITH_STATEMENT diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py b/pypy/interpreter/pyparser/test/test_pyparse.py --- a/pypy/interpreter/pyparser/test/test_pyparse.py +++ b/pypy/interpreter/pyparser/test/test_pyparse.py @@ -148,3 +148,6 @@ self.parse('0b1101') self.parse('0b0l') py.test.raises(SyntaxError, self.parse, "0b112") + + def test_print_function(self): + self.parse("from __future__ import print_function\nx = print\n") diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -303,6 +303,9 @@ 'from __future__ import nested_scopes, generators', 'from __future__ import (nested_scopes,\ngenerators)', 'from __future__ import (nested_scopes,\ngenerators,)', + 'from __future__ import (\nnested_scopes,\ngenerators)', + 'from __future__ import(\n\tnested_scopes,\n\tgenerators)', + 'from __future__ import(\n\t\nnested_scopes)', 'from sys import stdin, stderr, stdout', 'from sys import (stdin, stderr,\nstdout)', 'from sys import (stdin, stderr,\nstdout,)', From noreply at buildbot.pypy.org Fri May 24 10:45:56 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 10:45:56 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: merge default Message-ID: <20130524084556.A06DB1C3336@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64534:0bb98defe2bc Date: 2013-05-24 03:43 -0500 http://bitbucket.org/pypy/pypy/changeset/0bb98defe2bc/ Log: merge default diff too long, truncating to 2000 out of 5143 lines 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,5 +4,5 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "0.6" -__version_info__ = (0, 6) +__version__ = "0.7" +__version_info__ = (0, 7) 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 @@ -73,15 +73,15 @@ if name.startswith('RTLD_'): setattr(self, name, getattr(backend, name)) # - BVoidP = self._get_cached_btype(model.voidp_type) + self.BVoidP = self._get_cached_btype(model.voidp_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(BVoidP, 0) + FFI.NULL = self.cast(self.BVoidP, 0) FFI.CData, FFI.CType = backend._get_types() else: # ctypes backend: attach these constants to the instance - self.NULL = self.cast(BVoidP, 0) + self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() def cdef(self, csource, override=False): @@ -346,6 +346,12 @@ self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.append(']') + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + def _make_ffi_library(ffi, libname, flags): import os @@ -372,8 +378,8 @@ BType = ffi._get_cached_btype(tp) try: value = backendlib.load_function(BType, name) - except KeyError: - raise AttributeError(name) + except KeyError as e: + raise AttributeError('%s: %s' % (name, e)) library.__dict__[name] = value return # diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -16,6 +16,7 @@ class CTypesData(object): __metaclass__ = CTypesType __slots__ = ['__weakref__'] + __name__ = '' def __init__(self, *args): raise TypeError("cannot instantiate %r" % (self.__class__,)) @@ -491,6 +492,8 @@ elif BItem in (getbtype(model.PrimitiveType('signed char')), getbtype(model.PrimitiveType('unsigned char'))): kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' else: kind = 'generic' # @@ -546,13 +549,13 @@ def __setitem__(self, index, value): self._as_ctype_ptr[index] = BItem._to_ctypes(value) - if kind == 'charp': + if kind == 'charp' or kind == 'voidp': @classmethod - def _arg_to_ctypes(cls, value): - if isinstance(value, bytes): - return ctypes.c_char_p(value) + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) else: - return super(CTypesPtr, cls)._arg_to_ctypes(value) + return super(CTypesPtr, cls)._arg_to_ctypes(*value) if kind == 'charp' or kind == 'bytep': def _to_string(self, maxlen): diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -15,6 +15,20 @@ def patch_extension_kwds(self, kwds): pass + def find_module(self, module_name, path, so_suffix): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] != so_suffix: + return None + return filename + def collect_types(self): self._typesdict = {} self._generate("collecttype") @@ -427,9 +441,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -1,4 +1,4 @@ -import sys +import sys, os import types from . import model, ffiplatform @@ -20,6 +20,16 @@ # up in kwds['export_symbols']. kwds.setdefault('export_symbols', self.export_symbols) + def find_module(self, module_name, path, so_suffix): + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + return None + def collect_types(self): pass # not needed in the generic engine @@ -216,9 +226,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -102,21 +102,10 @@ path = pkg.__path__ else: path = None - try: - f, filename, descr = imp.find_module(self.get_module_name(), - path) - except ImportError: + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffix()) + if filename is None: return - if f is not None: - f.close() - if filename.lower().endswith('.py'): - # on PyPy, if there are both .py and .pypy-19.so files in - # the same directory, the .py file is returned. That's the - # case after a setuptools installation. We never want to - # load the .py file here... - filename = filename[:-3] + _get_so_suffix() - if not os.path.isfile(filename): - return self.modulefilename = filename self._vengine.collect_types() self._has_module = True diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -65,7 +65,8 @@ del working_modules["termios"] del working_modules["_minimal_curses"] - del working_modules["cppyy"] # not tested on win32 + if "cppyy" in working_modules: + del working_modules["cppyy"] # not tested on win32 # The _locale module is needed by site.py on Windows default_modules["_locale"] = None @@ -78,7 +79,8 @@ del working_modules["_minimal_curses"] del working_modules["termios"] del working_modules["_multiprocessing"] # depends on rctime - del working_modules["cppyy"] # depends on ctypes + if "cppyy" in working_modules: + del working_modules["cppyy"] # depends on ctypes module_dependencies = { @@ -215,10 +217,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), 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 @@ -28,3 +28,9 @@ .. branch: arm-stacklet Stacklet support for ARM, enables _continuation support + +.. branch: remove-tuple-smm +Remove multi-methods on tuple + +.. branch: remove-iter-smm +Remove multi-methods on iterators diff --git a/pypy/interpreter/pyparser/future.py b/pypy/interpreter/pyparser/future.py --- a/pypy/interpreter/pyparser/future.py +++ b/pypy/interpreter/pyparser/future.py @@ -1,307 +1,3 @@ -""" -This automaton is designed to be invoked on a Python source string -before the real parser starts working, in order to find all legal -'from __future__ import blah'. As soon as something is encountered that -would prevent more future imports, the analysis is aborted. -The resulting legal futures are avaliable in self.flags after the -pass has ended. - -Invocation is through get_futures(src), which returns a field of flags, one per -found correct future import. - -The flags can then be used to set up the parser. -All error detection is left to the parser. - -The reason we are not using the regular lexer/parser toolchain is that -we do not want the overhead of generating tokens for entire files just -to find information that resides in the first few lines of the file. -Neither do we require sane error messages, as this job is handled by -the parser. - -To make the parsing fast, especially when the module is translated to C, -the code has been written in a very serial fashion, using an almost -assembler like style. A further speedup could be achieved by replacing -the "in" comparisons with explicit numeric comparisons. -""" - -from pypy.interpreter.astcompiler.consts import CO_GENERATOR_ALLOWED, \ - CO_FUTURE_DIVISION, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_ABSOLUTE_IMPORT - -def get_futures(future_flags, source): - futures = FutureAutomaton(future_flags, source) - try: - futures.start() - except DoneException, e: - pass - return futures.flags, (futures.lineno, futures.col_offset) - -class DoneException(Exception): - pass - -whitespace = ' \t\f' -whitespace_or_newline = whitespace + '\n\r' -letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz_' -alphanumerics = letters + '1234567890' - -class FutureAutomaton(object): - """ - A future statement must appear near the top of the module. - The only lines that can appear before a future statement are: - - * the module docstring (if any), - * comments, - * blank lines, and - * other future statements. - - The features recognized by Python 2.5 are "generators", - "division", "nested_scopes" and "with_statement", "absolute_import". - "generators", "division" and "nested_scopes" are redundant - in 2.5 because they are always enabled. - - This module parses the input until it encounters something that is - not recognized as a valid future statement or something that may - precede a future statement. - """ - - def __init__(self, future_flags, string): - self.future_flags = future_flags - self.s = string - self.pos = 0 - self.current_lineno = 1 - self.lineno = -1 - self.line_start_pos = 0 - self.col_offset = 0 - self.docstring_consumed = False - self.flags = 0 - self.got_features = 0 - - def getc(self, offset=0): - try: - return self.s[self.pos + offset] - except IndexError: - raise DoneException - - def start(self): - c = self.getc() - if c in ("'", '"', "r", "u") and not self.docstring_consumed: - self.consume_docstring() - elif c == '\\' or c in whitespace_or_newline: - self.consume_empty_line() - elif c == '#': - self.consume_comment() - elif c == 'f': - self.consume_from() - else: - return - - def atbol(self): - self.current_lineno += 1 - self.line_start_pos = self.pos - - def consume_docstring(self): - self.docstring_consumed = True - if self.getc() == "r": - self.pos += 1 - if self.getc() == "u": - self.pos += 1 - endchar = self.getc() - if (self.getc() == self.getc(+1) and - self.getc() == self.getc(+2)): - self.pos += 3 - while 1: # Deal with a triple quoted docstring - c = self.getc() - if c == '\\': - self.pos += 1 - self._skip_next_char_from_docstring() - elif c != endchar: - self._skip_next_char_from_docstring() - else: - self.pos += 1 - if (self.getc() == endchar and - self.getc(+1) == endchar): - self.pos += 2 - self.consume_empty_line() - break - - else: # Deal with a single quoted docstring - self.pos += 1 - while 1: - c = self.getc() - self.pos += 1 - if c == endchar: - self.consume_empty_line() - return - elif c == '\\': - self._skip_next_char_from_docstring() - elif c in '\r\n': - # Syntax error - return - - def _skip_next_char_from_docstring(self): - c = self.getc() - self.pos += 1 - if c == '\n': - self.atbol() - elif c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - - def consume_continuation(self): - c = self.getc() - if c in '\n\r': - self.pos += 1 - self.atbol() - - def consume_empty_line(self): - """ - Called when the remainder of the line can only contain whitespace - and comments. - """ - while self.getc() in whitespace: - self.pos += 1 - if self.getc() == '#': - self.consume_comment() - elif self.getc() == ';': - self.pos += 1 - self.consume_whitespace() - self.start() - elif self.getc() in '\\': - self.pos += 1 - self.consume_continuation() - self.start() - elif self.getc() in '\r\n': - c = self.getc() - self.pos += 1 - if c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - else: - self.atbol() - self.start() - - def consume_comment(self): - self.pos += 1 - while self.getc() not in '\r\n': - self.pos += 1 - self.consume_empty_line() - - def consume_from(self): - col_offset = self.pos - self.line_start_pos - line = self.current_lineno - self.pos += 1 - if self.getc() == 'r' and self.getc(+1) == 'o' and self.getc(+2) == 'm': - self.docstring_consumed = True - self.pos += 3 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+10] != '__future__': - raise DoneException - self.pos += 10 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+6] != 'import': - raise DoneException - self.pos += 6 - self.consume_whitespace() - old_got = self.got_features - try: - if self.getc() == '(': - self.pos += 1 - self.consume_whitespace() - self.set_flag(self.get_name()) - # Set flag corresponding to name - self.get_more(paren_list=True) - else: - self.set_flag(self.get_name()) - self.get_more() - finally: - if self.got_features > old_got: - self.col_offset = col_offset - self.lineno = line - self.consume_empty_line() - - def consume_mandatory_whitespace(self): - if self.getc() not in whitespace + '\\': - raise DoneException - self.consume_whitespace() - - def consume_whitespace(self, newline_ok=False): - while 1: - c = self.getc() - if c in whitespace: - self.pos += 1 - continue - elif c == '\\' or newline_ok: - slash = c == '\\' - if slash: - self.pos += 1 - c = self.getc() - if c == '\n': - self.pos += 1 - self.atbol() - continue - elif c == '\r': - self.pos += 1 - if self.getc() == '\n': - self.pos += 1 - self.atbol() - elif slash: - raise DoneException - else: - return - else: - return - - def get_name(self): - if self.getc() not in letters: - raise DoneException - p = self.pos - try: - while self.getc() in alphanumerics: - self.pos += 1 - except DoneException: - # If there's any name at all, we want to call self.set_flag(). - # Something else while get the DoneException again. - if self.pos == p: - raise - end = self.pos - else: - end = self.pos - self.consume_whitespace() - return self.s[p:end] - - def get_more(self, paren_list=False): - if paren_list and self.getc() == ')': - self.pos += 1 - return - if (self.getc() == 'a' and - self.getc(+1) == 's' and - self.getc(+2) in whitespace): - self.get_name() - self.get_name() - self.get_more(paren_list=paren_list) - return - elif self.getc() != ',': - return - else: - self.pos += 1 - self.consume_whitespace(paren_list) - if paren_list and self.getc() == ')': - self.pos += 1 - return # Handles trailing comma inside parenthesis - self.set_flag(self.get_name()) - self.get_more(paren_list=paren_list) - - def set_flag(self, feature): - self.got_features += 1 - try: - self.flags |= self.future_flags.compiler_features[feature] - except KeyError: - pass - -from codeop import PyCF_DONT_IMPLY_DEDENT -from pypy.interpreter.error import OperationError - from pypy.tool import stdlib___future__ as future class FutureFlags(object): @@ -327,6 +23,81 @@ flag_names.append(name) return flag_names + def get_compiler_feature(self, name): + return self.compiler_features.get(name, 0) + futureFlags_2_4 = FutureFlags((2, 4, 4, 'final', 0)) futureFlags_2_5 = FutureFlags((2, 5, 0, 'final', 0)) futureFlags_2_7 = FutureFlags((2, 7, 0, 'final', 0)) + + +class TokenIterator: + def __init__(self, tokens): + self.tokens = tokens + self.index = 0 + self.next() + + def next(self): + index = self.index + self.index = index + 1 + self.tok = self.tokens[index] + + def skip(self, n): + if self.tok[0] == n: + self.next() + return True + else: + return False + + def skip_name(self, name): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME and self.tok[1] == name: + self.next() + return True + else: + return False + + def next_feature_name(self): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME: + name = self.tok[1] + self.next() + if self.skip_name("as"): + self.skip(pygram.tokens.NAME) + return name + else: + return '' + + def skip_newlines(self): + from pypy.interpreter.pyparser import pygram + while self.skip(pygram.tokens.NEWLINE): + pass + + +def add_future_flags(future_flags, tokens): + from pypy.interpreter.pyparser import pygram + it = TokenIterator(tokens) + result = 0 + # + # The only things that can precede a future statement are another + # future statement and a doc string (only one). This is a very + # permissive parsing of the given list of tokens; it relies on + # the real parsing done afterwards to give errors. + it.skip_newlines() + it.skip_name("r") or it.skip_name("u") or it.skip_name("ru") + if it.skip(pygram.tokens.STRING): + it.skip_newlines() + + while (it.skip_name("from") and + it.skip_name("__future__") and + it.skip_name("import")): + it.skip(pygram.tokens.LPAR) # optionally + result |= future_flags.get_compiler_feature(it.next_feature_name()) + while it.skip(pygram.tokens.COMMA): + result |= future_flags.get_compiler_feature(it.next_feature_name()) + it.skip(pygram.tokens.RPAR) # optionally + it.skip(pygram.tokens.SEMI) # optionally + it.skip_newlines() + + position = (it.tok[2], it.tok[3]) + return result, position diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py --- a/pypy/interpreter/pyparser/pyparse.py +++ b/pypy/interpreter/pyparser/pyparse.py @@ -135,17 +135,8 @@ raise error.SyntaxError(space.str_w(w_message)) raise - f_flags, future_info = future.get_futures(self.future_flags, textsrc) - compile_info.last_future_import = future_info - compile_info.flags |= f_flags - flags = compile_info.flags - if flags & consts.CO_FUTURE_PRINT_FUNCTION: - self.grammar = pygram.python_grammar_no_print - else: - self.grammar = pygram.python_grammar - # The tokenizer is very picky about how it wants its input. source_lines = textsrc.splitlines(True) if source_lines and not source_lines[-1].endswith("\n"): @@ -157,7 +148,21 @@ tp = 0 try: try: + # Note: we no longer pass the CO_FUTURE_* to the tokenizer, + # which is expected to work independently of them. It's + # certainly the case for all futures in Python <= 2.7. tokens = pytokenizer.generate_tokens(source_lines, flags) + + newflags, last_future_import = ( + future.add_future_flags(self.future_flags, tokens)) + compile_info.last_future_import = last_future_import + compile_info.flags |= newflags + + if compile_info.flags & consts.CO_FUTURE_PRINT_FUNCTION: + self.grammar = pygram.python_grammar_no_print + else: + self.grammar = pygram.python_grammar + for tp, value, lineno, column, line in tokens: if self.add_token(tp, value, lineno, column, line): break diff --git a/pypy/interpreter/pyparser/test/test_futureautomaton.py b/pypy/interpreter/pyparser/test/test_future.py rename from pypy/interpreter/pyparser/test/test_futureautomaton.py rename to pypy/interpreter/pyparser/test/test_future.py --- a/pypy/interpreter/pyparser/test/test_futureautomaton.py +++ b/pypy/interpreter/pyparser/test/test_future.py @@ -1,29 +1,26 @@ import py -import pypy.interpreter.pyparser.future as future +from pypy.interpreter.pyparser import future, pytokenizer from pypy.tool import stdlib___future__ as fut -def run(s): - f = future.FutureAutomaton(future.futureFlags_2_7, s) - try: - f.start() - except future.DoneException: - pass - return f +def run(s, expected_last_future=None): + source_lines = s.splitlines(True) + tokens = pytokenizer.generate_tokens(source_lines, 0) + expected_last_future = expected_last_future or tokens[-1][2:4] + # + flags, last_future_import = future.add_future_flags( + future.futureFlags_2_7, tokens) + assert last_future_import == expected_last_future + return flags def test_docstring(): s = '"Docstring\\" "\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_comment(): s = '# A comment about nothing ;\n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_tripledocstring(): s = '''""" This is a @@ -31,9 +28,7 @@ breaks in it. It even has a \n""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_escapedquote_in_tripledocstring(): s = '''""" This is a @@ -41,233 +36,176 @@ breaks in it. \\"""It even has an escaped quote!""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_empty_line(): s = ' \t \f \n \n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_from(): s = 'from __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms(): s = 'from __future__ import division, generators, with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_from_as(): s = 'from __future__ import division as b\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_as(): s = 'from __future__ import division as b, generators as c\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_from_paren(): s = 'from __future__ import (division)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_paren(): s = 'from __future__ import (division, generators)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_froms_paren_as(): s = 'from __future__ import (division as b, generators,)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_paren_with_newline(): s = 'from __future__ import (division,\nabsolute_import)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) + +def test_paren_with_newline_2(): + s = 'from __future__ import (\ndivision,\nabsolute_import)\n' + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) def test_multiline(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,)\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_windows_style_lineendings(): s = '"abc" #def\r\n #ghi\r\nfrom __future__ import (division as b, generators,)\r\nfrom __future__ import with_statement\r\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_mac_style_lineendings(): s = '"abc" #def\r #ghi\rfrom __future__ import (division as b, generators,)\rfrom __future__ import with_statement\r' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_semicolon(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 3 - assert f.col_offset == 55 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) + +def test_semicolon_2(): + s = 'from __future__ import division; from foo import bar' + f = run(s, expected_last_future=(1, 39)) + assert f == fut.CO_FUTURE_DIVISION def test_full_chain(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert pos == (3, 55) + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_intervening_code(): s = 'from __future__ import (division as b, generators,)\nfrom sys import modules\nfrom __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags & fut.CO_FUTURE_WITH_STATEMENT == 0 - assert pos == (1, 0) + f = run(s, expected_last_future=(2, 5)) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_GENERATOR_ALLOWED) def test_nonexisting(): s = 'from __future__ import non_existing_feature\n' f = run(s) - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == 0 + +def test_nonexisting_2(): + s = 'from __future__ import non_existing_feature, with_statement\n' + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_from_import_abs_import(): s = 'from __future__ import absolute_import\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_ABSOLUTE_IMPORT - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_ABSOLUTE_IMPORT def test_raw_doc(): s = 'r"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_unicode_doc(): s = 'u"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_raw_unicode_doc(): s = 'ru"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_line(): s = "\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_lines(): s = "\\\n \t\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 3 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_lots_of_continuation_lines(): s = "\\\n\\\n\\\n\\\n\\\n\\\n\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT -# This looks like a bug in cpython parser -# and would require extensive modifications -# to future.py in order to emulate the same behaviour def test_continuation_lines_raise(): - py.test.skip("probably a CPython bug") s = " \\\n \t\\\nfrom __future__ import with_statement\n" - try: - f = run(s) - except IndentationError, e: - assert e.args == 'unexpected indent' - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == -1 - assert f.col_offset == 0 - else: - raise AssertionError('IndentationError not raised') - assert f.lineno == 2 - assert f.col_offset == 0 + f = run(s, expected_last_future=(1, 0)) + assert f == 0 # because of the INDENT def test_continuation_lines_in_docstring_single_quoted(): s = '"\\\n\\\n\\\n\\\n\\\n\\\n"\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_continuation_lines_in_docstring_triple_quoted(): s = '"""\\\n\\\n\\\n\\\n\\\n\\\n"""\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION + +def test_blank_lines(): + s = ('\n\t\n\nfrom __future__ import with_statement' + ' \n \n \nfrom __future__ import division') + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT | fut.CO_FUTURE_DIVISION + +def test_dummy_semicolons(): + s = ('from __future__ import division;\n' + 'from __future__ import with_statement;') + f = run(s) + assert f == fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_WITH_STATEMENT diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py b/pypy/interpreter/pyparser/test/test_pyparse.py --- a/pypy/interpreter/pyparser/test/test_pyparse.py +++ b/pypy/interpreter/pyparser/test/test_pyparse.py @@ -148,3 +148,6 @@ self.parse('0b1101') self.parse('0b0l') py.test.raises(SyntaxError, self.parse, "0b112") + + def test_print_function(self): + self.parse("from __future__ import print_function\nx = print\n") diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -303,6 +303,9 @@ 'from __future__ import nested_scopes, generators', 'from __future__ import (nested_scopes,\ngenerators)', 'from __future__ import (nested_scopes,\ngenerators,)', + 'from __future__ import (\nnested_scopes,\ngenerators)', + 'from __future__ import(\n\tnested_scopes,\n\tgenerators)', + 'from __future__ import(\n\t\nnested_scopes)', 'from sys import stdin, stderr, stdout', 'from sys import (stdin, stderr,\nstdout)', 'from sys import (stdin, stderr,\nstdout,)', 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 @@ -7,7 +7,7 @@ appleveldefs = { } interpleveldefs = { - '__version__': 'space.wrap("0.6")', + '__version__': 'space.wrap("0.7")', 'load_library': 'libraryobj.load_library', @@ -30,6 +30,8 @@ 'typeoffsetof': 'func.typeoffsetof', 'rawaddressof': 'func.rawaddressof', 'getcname': 'func.getcname', + 'newp_handle': 'handle.newp_handle', + 'from_handle': 'handle.from_handle', '_get_types': 'func._get_types', 'string': 'func.string', diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py --- a/pypy/module/_cffi_backend/cdataobj.py +++ b/pypy/module/_cffi_backend/cdataobj.py @@ -394,6 +394,19 @@ return self.length +class W_CDataHandle(W_CData): + _attrs_ = ['w_keepalive'] + _immutable_fields_ = ['w_keepalive'] + + def __init__(self, space, cdata, ctype, w_keepalive): + W_CData.__init__(self, space, cdata, ctype) + self.w_keepalive = w_keepalive + + def _repr_extra(self): + w_repr = self.space.repr(self.w_keepalive) + return "handle to %s" % (self.space.str_w(w_repr),) + + W_CData.typedef = TypeDef( 'CData', __module__ = '_cffi_backend', 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 @@ -172,8 +172,8 @@ class W_CTypePointer(W_CTypePtrBase): - _attrs_ = ['is_file', 'cache_array_type'] - _immutable_fields_ = ['is_file', 'cache_array_type?'] + _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr'] + _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr'] kind = "pointer" cache_array_type = None @@ -186,6 +186,7 @@ extra = " *" self.is_file = (ctitem.name == "struct _IO_FILE" or ctitem.name == "struct $FILE") + self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid) W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/handle.py @@ -0,0 +1,93 @@ +import weakref +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import unwrap_spec +from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj +from pypy.module._weakref.interp__weakref import dead_ref +from rpython.rtyper.lltypesystem import lltype, rffi + + +def reduced_value(s): + while True: + divide = s & 1 + s >>= 1 + if not divide: + return s + +# ____________________________________________________________ + + +class CffiHandles: + def __init__(self, space): + self.handles = [] + self.look_distance = 0 + + def reserve_next_handle_index(self): + # The reservation ordering done here is tweaked for pypy's + # memory allocator. We look from index 'look_distance'. + # Look_distance increases from 0. But we also look at + # "look_distance/2" or "/4" or "/8", etc. If we find that one + # of these secondary locations is free, we assume it's because + # there was recently a minor collection; so we reset + # look_distance to 0 and start again from the lowest locations. + length = len(self.handles) + for d in range(self.look_distance, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + s = reduced_value(d) + if self.handles[s]() is None: + break + # restart from the beginning + for d in range(0, length): + if self.handles[d]() is None: + self.look_distance = d + 1 + return d + # full! extend, but don't use '!=' here + self.handles = self.handles + [dead_ref] * (length // 3 + 5) + self.look_distance = length + 1 + return length + + def store_handle(self, index, content): + self.handles[index] = weakref.ref(content) + + def fetch_handle(self, index): + if 0 <= index < len(self.handles): + return self.handles[index]() + return None + +def get(space): + return space.fromcache(CffiHandles) + +# ____________________________________________________________ + + at unwrap_spec(w_ctype=ctypeobj.W_CType) +def newp_handle(space, w_ctype, w_x): + if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or + not w_ctype.is_void_ptr): + raise operationerrfmt(space.w_TypeError, + "needs 'void *', got '%s'", w_ctype.name) + index = get(space).reserve_next_handle_index() + _cdata = rffi.cast(rffi.CCHARP, index + 1) + new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x) + get(space).store_handle(index, new_cdataobj) + return new_cdataobj + + at 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): + raise operationerrfmt(space.w_TypeError, + "expected a 'cdata' object with a 'void *' out " + "of new_handle(), got '%s'", ctype.name) + index = rffi.cast(lltype.Signed, w_cdata._cdata) + original_cdataobj = get(space).fetch_handle(index - 1) + # + if isinstance(original_cdataobj, cdataobj.W_CDataHandle): + return original_cdataobj.w_keepalive + else: + if index == 0: + msg = "cannot use from_handle() on NULL pointer" + else: + msg = "'void *' value does not correspond to any object" + raise OperationError(space.w_RuntimeError, space.wrap(msg)) 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 @@ -2732,6 +2732,32 @@ assert x != cast(BIntP, 12344) assert hash(x) == hash(cast(BIntP, 12345)) +def test_new_handle(): + import _weakref + BVoidP = new_pointer_type(new_void_type()) + BCharP = new_pointer_type(new_primitive_type("char")) + class mylist(list): + pass + o = mylist([2, 3, 4]) + x = newp_handle(BVoidP, o) + assert repr(x) == "" + assert x + assert from_handle(x) is o + assert from_handle(cast(BCharP, x)) is o + wr = _weakref.ref(o) + del o + import gc; gc.collect() + assert wr() is not None + assert from_handle(x) == list((2, 3, 4)) + assert from_handle(cast(BCharP, x)) == list((2, 3, 4)) + del x + for i in range(3): + if wr() is not None: + import gc; gc.collect() + assert wr() is None + py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) + + def test_version(): # this test is here mostly for PyPy - assert __version__ == "0.6" + assert __version__ == "0.7" diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py new file mode 100644 --- /dev/null +++ b/pypy/module/_cffi_backend/test/test_handle.py @@ -0,0 +1,59 @@ +import random +from pypy.module._cffi_backend.handle import CffiHandles, reduced_value + + +def test_reduced_value(): + assert reduced_value(0) == 0 + assert reduced_value(1) == 0 + assert reduced_value(2) == 1 + assert reduced_value(3) == 0 + assert reduced_value(4) == 2 + assert reduced_value(5) == 1 + assert reduced_value(6) == 3 + assert reduced_value(7) == 0 + assert reduced_value(8) == 4 + assert reduced_value(9) == 2 + assert reduced_value(10) == 5 + assert reduced_value(11) == 1 + + +class PseudoWeakRef(object): + _content = 42 + + def __call__(self): + return self._content + + +def test_cffi_handles_1(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + assert len(ch.handles) < 13500 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr + +def test_cffi_handles_2(): + ch = CffiHandles(None) + expected_content = {} + for i in range(10000): + index = ch.reserve_next_handle_index() + assert 0 <= index < len(ch.handles) + assert ch.handles[index]() is None + pwr = PseudoWeakRef() + expected_content[index] = pwr + ch.handles[index] = pwr + # + if len(expected_content) > 20: + r = random.choice(list(expected_content)) + pwr = expected_content.pop(r) + pwr._content = None + # + assert len(ch.handles) < 100 + for index, pwr in expected_content.items(): + assert ch.handles[index] is pwr diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py --- a/pypy/module/cpyext/setobject.py +++ b/pypy/module/cpyext/setobject.py @@ -6,7 +6,6 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.setobject import W_SetObject, newset -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PySet_Check, PySet_CheckExact = build_type_checkers("Set") diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py --- a/pypy/module/micronumpy/arrayimpl/concrete.py +++ b/pypy/module/micronumpy/arrayimpl/concrete.py @@ -11,7 +11,6 @@ from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rawstorage import free_raw_storage, raw_storage_getitem,\ raw_storage_setitem, RAW_STORAGE -from pypy.module.micronumpy.arrayimpl.sort import argsort_array from rpython.rlib.debug import make_sure_not_resized @@ -70,6 +69,7 @@ new_backstrides = [0] * ndims for nd in range(ndims): new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) else: @@ -324,6 +324,7 @@ orig_array) def argsort(self, space, w_axis): + from pypy.module.micronumpy.arrayimpl.sort import argsort_array return argsort_array(self, space, w_axis) def base(self): @@ -356,13 +357,13 @@ self.strides = strides self.backstrides = backstrides self.shape = shape + if dtype is None: + dtype = parent.dtype if isinstance(parent, SliceArray): parent = parent.parent # one level only self.parent = parent self.storage = parent.storage self.order = parent.order - if dtype is None: - dtype = parent.dtype self.dtype = dtype self.size = support.product(shape) * self.dtype.itemtype.get_element_size() self.start = start diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py --- a/pypy/module/micronumpy/arrayimpl/scalar.py +++ b/pypy/module/micronumpy/arrayimpl/scalar.py @@ -2,6 +2,7 @@ from pypy.module.micronumpy.arrayimpl import base from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy import support +from pypy.module.micronumpy.interp_boxes import W_GenericBox from pypy.interpreter.error import OperationError class ScalarIterator(base.BaseArrayIterator): @@ -48,6 +49,7 @@ return self.value def set_scalar_value(self, w_val): + assert isinstance(w_val, W_GenericBox) self.value = w_val.convert_to(self.dtype) def copy(self, space): @@ -73,7 +75,7 @@ dtype = self.dtype.float_type or self.dtype if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) if self.dtype.is_complex_type(): @@ -102,7 +104,7 @@ dtype = self.dtype.float_type if len(w_arr.get_shape()) > 0: raise OperationError(space.w_ValueError, space.wrap( - "could not broadcast input array from shape " + + "could not broadcast input array from shape " + "(%s) into shape ()" % ( ','.join([str(x) for x in w_arr.get_shape()],)))) self.value = self.dtype.itemtype.composite( diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -27,10 +27,10 @@ from pypy.module.micronumpy.arrayimpl import concrete, scalar if not shape: - impl = scalar.Scalar(dtype) + impl = scalar.Scalar(dtype.base) else: - strides, backstrides = calc_strides(shape, dtype, order) - impl = concrete.ConcreteArray(shape, dtype, order, strides, + strides, backstrides = calc_strides(shape, dtype.base, order) + impl = concrete.ConcreteArray(shape, dtype.base, order, strides, backstrides) return W_NDimArray(impl) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -268,14 +268,30 @@ class W_VoidBox(W_FlexibleBox): - @unwrap_spec(item=str) - def descr_getitem(self, space, item): + def descr_getitem(self, space, w_item): + from pypy.module.micronumpy.types import VoidType + if space.isinstance_w(w_item, space.w_str): + item = space.str_w(w_item) + elif space.isinstance_w(w_item, space.w_int): + #Called by iterator protocol + indx = space.int_w(w_item) + try: + item = self.dtype.fieldnames[indx] + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("Iterated over too many fields %d" % indx)) + else: + raise OperationError(space.w_IndexError, space.wrap( + "Can only access fields of record with int or str")) try: ofs, dtype = self.dtype.fields[item] except KeyError: raise OperationError(space.w_IndexError, space.wrap("Field %s does not exist" % item)) - read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) + if isinstance(dtype.itemtype, VoidType): + read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype) + else: + read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype) if isinstance (read_val, W_StringBox): # StringType returns a str return space.wrap(dtype.itemtype.to_str(read_val)) @@ -373,7 +389,7 @@ W_LongDoubleBox = W_Float64Box W_CLongDoubleBox = W_Complex64Box - + W_GenericBox.typedef = TypeDef("generic", __module__ = "numpypy", diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -46,11 +46,11 @@ class W_Dtype(W_Root): - _immutable_fields_ = ["itemtype", "num", "kind"] + _immutable_fields_ = ["itemtype", "num", "kind", "shape"] def __init__(self, itemtype, num, kind, name, char, w_box_type, alternate_constructors=[], aliases=[], - fields=None, fieldnames=None, native=True): + fields=None, fieldnames=None, native=True, shape=[], subdtype=None): self.itemtype = itemtype self.num = num self.kind = kind @@ -63,6 +63,12 @@ self.fieldnames = fieldnames self.native = native self.float_type = None + self.shape = list(shape) + self.subdtype = subdtype + if not subdtype: + self.base = self + else: + self.base = subdtype.base @specialize.argtype(1) def box(self, value): @@ -78,7 +84,8 @@ return self.itemtype.coerce(space, self, w_item) def getitem(self, arr, i): - return self.itemtype.read(arr, i, 0) + item = self.itemtype.read(arr, i, 0) + return item def getitem_bool(self, arr, i): return self.itemtype.read_bool(arr, i, 0) @@ -111,8 +118,15 @@ def descr_get_alignment(self, space): return space.wrap(self.itemtype.alignment) + def descr_get_base(self, space): + return space.wrap(self.base) + + def descr_get_subdtype(self, space): + return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)]) + def descr_get_shape(self, space): - return space.newtuple([]) + w_shape = [space.wrap(dim) for dim in self.shape] + return space.newtuple(w_shape) def eq(self, space, w_other): w_other = space.call_function(space.gettypefor(W_Dtype), w_other) @@ -137,6 +151,7 @@ if w_fields == space.w_None: self.fields = None else: + self.fields = {} ofs_and_items = [] size = 0 for key in space.listview(w_fields): @@ -279,15 +294,22 @@ ofs_and_items = [] fieldnames = [] for w_elem in lst_w: - w_fldname, w_flddesc = space.fixedview(w_elem, 2) - subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc) + size = 1 + w_shape = space.newtuple([]) + if space.len_w(w_elem) == 3: + w_fldname, w_flddesc, w_shape = space.fixedview(w_elem) + if not base.issequence_w(space, w_shape): + w_shape = space.newtuple([w_shape,]) + else: + w_fldname, w_flddesc = space.fixedview(w_elem) + subdtype = descr__new__(space, space.gettypefor(W_Dtype), w_flddesc, w_shape=w_shape) fldname = space.str_w(w_fldname) if fldname in fields: raise OperationError(space.w_ValueError, space.wrap("two fields with the same name")) assert isinstance(subdtype, W_Dtype) fields[fldname] = (offset, subdtype) ofs_and_items.append((offset, subdtype.itemtype)) - offset += subdtype.itemtype.get_element_size() + offset += subdtype.itemtype.get_element_size() * size fieldnames.append(fldname) itemtype = types.RecordType(ofs_and_items, offset) return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(8 * itemtype.get_element_size()), @@ -317,8 +339,9 @@ elif char == 'V': num = 20 basename = 'void' - w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - return dtype_from_list(space, space.newlist([])) + itemtype = types.VoidType(size) + return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(size), + "V", space.gettypefor(interp_boxes.W_VoidBox)) else: assert char == 'U' basename = 'unicode' @@ -333,10 +356,24 @@ raise OperationError(space.w_NotImplementedError, space.wrap( "dtype from spec")) -def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None): +def descr__new__(space, w_subtype, w_dtype, w_align=None, w_copy=None, w_shape=None): # w_align and w_copy are necessary for pickling cache = get_dtype_cache(space) + if w_shape is not None and (space.isinstance_w(w_shape, space.w_int) or space.len_w(w_shape) > 0): + subdtype = descr__new__(space, w_subtype, w_dtype, w_align, w_copy) + assert isinstance(subdtype, W_Dtype) + size = 1 + if space.isinstance_w(w_shape, space.w_int): + w_shape = space.newtuple([w_shape]) + shape = [] + for w_dim in space.fixedview(w_shape): + dim = space.int_w(w_dim) + shape.append(dim) + size *= dim + return W_Dtype(types.VoidType(subdtype.itemtype.get_element_size() * size), 20, VOIDLTR, "void" + str(8 * subdtype.itemtype.get_element_size() * size), + "V", space.gettypefor(interp_boxes.W_VoidBox), shape=shape, subdtype=subdtype) + if space.is_none(w_dtype): return cache.w_float64dtype elif space.isinstance_w(w_dtype, w_subtype): @@ -355,6 +392,8 @@ "data type %s not understood" % name)) elif space.isinstance_w(w_dtype, space.w_list): return dtype_from_list(space, w_dtype) + elif space.isinstance_w(w_dtype, space.w_tuple): + return descr__new__(space, w_subtype, space.getitem(w_dtype, space.wrap(0)), w_align, w_copy, w_shape=space.getitem(w_dtype, space.wrap(1))) elif space.isinstance_w(w_dtype, space.w_dict): return dtype_from_dict(space, w_dtype) for dtype in cache.builtin_dtypes: @@ -391,6 +430,8 @@ name = interp_attrproperty('name', cls=W_Dtype), fields = GetSetProperty(W_Dtype.descr_get_fields), names = GetSetProperty(W_Dtype.descr_get_names), + subdtype = GetSetProperty(W_Dtype.descr_get_subdtype), + base = GetSetProperty(W_Dtype.descr_get_base), ) W_Dtype.typedef.acceptable_as_base_class = False diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -21,7 +21,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation -def _find_shape(space, w_size): +def _find_shape(space, w_size, dtype): if space.is_none(w_size): return [] if space.isinstance_w(w_size, space.w_int): @@ -29,6 +29,7 @@ shape = [] for w_item in space.fixedview(w_size): shape.append(space.int_w(w_item)) + shape += dtype.shape return shape[:] class __extend__(W_NDimArray): @@ -829,7 +830,7 @@ space.wrap("unsupported param")) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype) return W_NDimArray.from_shape(shape, dtype) @@ -842,10 +843,10 @@ """ from rpython.rtyper.lltypesystem import rffi from rpython.rlib.rawstorage import RAW_STORAGE_PTR - shape = _find_shape(space, w_shape) storage = rffi.cast(RAW_STORAGE_PTR, addr) dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)) + shape = _find_shape(space, w_shape, dtype) return W_NDimArray.from_shape_and_storage(shape, storage, dtype) W_NDimArray.typedef = TypeDef( @@ -1029,7 +1030,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order)) @@ -1039,7 +1040,7 @@ dtype = space.interp_w(interp_dtype.W_Dtype, space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype) ) - shape = _find_shape(space, w_shape) + shape = _find_shape(space, w_shape, dtype) if not shape: return W_NDimArray.new_scalar(space, dtype, space.wrap(0)) arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order) diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py --- a/pypy/module/micronumpy/iter.py +++ b/pypy/module/micronumpy/iter.py @@ -32,13 +32,13 @@ shape dimension which is back 25 and forward 1, which is x.strides[1] * (x.shape[1] - 1) + x.strides[0] -so if we precalculate the overflow backstride as +so if we precalculate the overflow backstride as [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))] we can go faster. All the calculations happen in next() next_skip_x() tries to do the iteration for a number of steps at once, -but then we cannot gaurentee that we only overflow one single shape +but then we cannot gaurentee that we only overflow one single shape dimension, perhaps we could overflow times in one big step. """ @@ -170,7 +170,8 @@ self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item def getitem_bool(self): return self.dtype.getitem_bool(self.array, self.offset) @@ -288,12 +289,13 @@ self.dim = dim self.array = array self.dtype = array.dtype - + def setitem(self, elem): self.dtype.setitem(self.array, self.offset, elem) def getitem(self): - return self.dtype.getitem(self.array, self.offset) + item = self.dtype.getitem(self.array, self.offset) + return item @jit.unroll_safe def next(self): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,23 +275,12 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype - def test_pickle_record(self): - from numpypy import array, dtype - from cPickle import loads, dumps - - d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) - assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) - - new_d = loads(dumps(d)) - - assert new_d.__reduce__() == d.__reduce__() - class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): import numpypy as numpy @@ -726,7 +715,7 @@ x = int8(42).ravel() assert x.dtype == int8 assert (x == array(42)).all() - + class AppTestStrUnicodeDtypes(BaseNumpyAppTest): @@ -769,6 +758,7 @@ assert isinstance(unicode_(3), unicode) class AppTestRecordDtypes(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): from numpypy import dtype, void @@ -781,6 +771,7 @@ assert d.num == 20 assert d.itemsize == 20 assert d.kind == 'V' + assert d.base == d assert d.type is void assert d.char == 'V' assert d.names == ("x", "y", "z", "value") @@ -793,6 +784,51 @@ d = dtype({'names': ['a', 'b', 'c'], }) + def test_create_subarrays(self): + from numpypy import dtype + d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + assert d.itemsize == 32 + assert d.name == "void256" + keys = d.fields.keys() + assert "x" in keys + assert "y" in keys + assert d["x"].shape == (2,) + assert d["x"].itemsize == 16 + e = dtype([("x", "float", 2), ("y", "int", 2)]) + assert e.fields.keys() == keys + assert e['x'].shape == (2,) + + dt = dtype((float, 10)) + assert dt.shape == (10,) + assert dt.kind == 'V' + assert dt.fields == None + assert dt.subdtype == (dtype(float), (10,)) + assert dt.base == dtype(float) + + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() + + def test_pickle_record_subarrays(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32", (3,)), ("y", "int32", (2,)), ("z", "int32", (4,)), ("value", float, (5,))]) + new_d = loads(dumps(d)) + + keys = d.fields.keys() + keys.sort() + assert keys == ["value", "x", "y", "z"] + + assert new_d.itemsize == d.itemsize == 76 + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -18,10 +18,12 @@ def get_element_size(): return 1 + def __init__(self): + self.base = self + def get_size(self): return 1 - def create_slice(a, chunks): return Chunks(chunks).apply(W_NDimArray(a)).implementation @@ -2699,6 +2701,56 @@ assert a[0]['y'] == 2 assert a[1]['y'] == 1 + def test_subarrays(self): + from numpypy import dtype, array, zeros + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert (a[0]["x"] == [1, 2, 3]).all() + assert (a[0]["y"] == [0.5, 1.5, 2.5, 3.5, 4.5]).all() + assert (a[1]["x"] == [4, 5, 6]).all() + assert (a[1]["y"] == [5.5, 6.5, 7.5, 8.5, 9.5]).all() + + a[0]["x"][0] = 200 + assert a[0]["x"][0] == 200 + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + d = dtype((float, (10, 10))) + a = zeros((3,3), dtype=d) + assert a[0, 0].shape == (10, 10) + assert a.shape == (3, 3, 10, 10) + a[0, 0] = 500 + assert (a[0, 0, 0] == 500).all() + assert a[0, 0, 0].shape == (10,) + + def test_multidim_subarray(self): + from numpypy import dtype, array + + d = dtype([("x", "int", (2, 3))]) + a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) + + assert a[0]["x"].dtype == dtype("int64") + assert a[0]["x"][0].dtype == dtype("int64") + + assert (a[0]["x"][0] == [1, 2, 3]).all() + assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all() + + def test_list_record(self): + from numpypy import dtype, array + + d = dtype([("x", "int", 3), ("y", "float", 5)]) + a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d) + + assert len(list(a[0])) == 2 class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -3,7 +3,9 @@ from pypy.interpreter.error import OperationError from pypy.module.micronumpy import interp_boxes +from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.module.micronumpy.arrayimpl.concrete import SliceArray from pypy.objspace.std.floatobject import float2string from pypy.objspace.std.complexobject import str_format from rpython.rlib import rfloat, clibffi, rcomplex @@ -1076,7 +1078,7 @@ def to_builtin_type(self, space, box): real,imag = self.for_computation(self.unbox(box)) - return space.newcomplex(real, imag) + return space.newcomplex(real, imag) def read_bool(self, arr, i, offset): v = self.for_computation(self._read(arr.storage, i, offset)) @@ -1217,7 +1219,7 @@ @raw_binary_op def le(self, v1, v2): - return self._lt(v1, v2) or self._eq(v1, v2) + return self._lt(v1, v2) or self._eq(v1, v2) @raw_binary_op def gt(self, v1, v2): @@ -1225,7 +1227,7 @@ @raw_binary_op def ge(self, v1, v2): - return self._lt(v2, v1) or self._eq(v2, v1) + return self._lt(v2, v1) or self._eq(v2, v1) def _bool(self, v): return bool(v[0]) or bool(v[1]) @@ -1341,7 +1343,7 @@ return rcomplex.c_div((v[0], -v[1]), (a2, 0.)) except ZeroDivisionError: return rfloat.NAN, rfloat.NAN - + # No floor, ceil, trunc in numpy for complex #@simple_unary_op #def floor(self, v): @@ -1684,6 +1686,7 @@ return space.wrap(self.to_str(box)) def build_and_convert(self, space, mydtype, box): + assert isinstance(box, interp_boxes.W_GenericBox) if box.get_dtype(space).is_str_or_unicode(): arg = box.get_dtype(space).itemtype.to_str(box) else: @@ -1696,10 +1699,68 @@ for j in range(i + 1, self.size): arr.storage[j] = '\x00' return interp_boxes.W_StringBox(arr, 0, arr.dtype) - + class VoidType(BaseType, BaseStringType): T = lltype.Char + def _coerce(self, space, arr, ofs, dtype, w_items, shape): + items_w = space.fixedview(w_items) + for i in range(len(items_w)): + subdtype = dtype.subdtype + itemtype = subdtype.itemtype + if space.len_w(shape) <= 1: + w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) + itemtype.store(arr, 0, ofs, w_box) + ofs += itemtype.get_element_size() + else: + size = 1 + for dimension in shape[1:]: + size *= dimension + size *= itemtype.get_element_size() + for w_item in items_w: + self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) + ofs += size From noreply at buildbot.pypy.org Fri May 24 11:52:12 2013 From: noreply at buildbot.pypy.org (bivab) Date: Fri, 24 May 2013 11:52:12 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: make this check stricter for soft-float and move the function address to Message-ID: <20130524095212.670521C0F38@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64535:03316d2756f3 Date: 2013-05-24 11:50 +0200 http://bitbucket.org/pypy/pypy/changeset/03316d2756f3/ Log: make this check stricter for soft-float and move the function address to another register whenever it is stored in a register used for arguments, as it might get overwritten later by a float copied to such a register. diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py --- a/rpython/jit/backend/arm/callbuilder.py +++ b/rpython/jit/backend/arm/callbuilder.py @@ -213,7 +213,7 @@ # or on the stack, which we can not access later # If this happens to be the case we remap the register to r4 and use r4 # to call the function - if self.fnloc in non_float_regs or self.fnloc.is_stack(): + if self.fnloc in r.argument_regs or self.fnloc.is_stack(): non_float_locs.append(self.fnloc) non_float_regs.append(r.r4) self.fnloc = r.r4 From noreply at buildbot.pypy.org Fri May 24 13:37:30 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 24 May 2013 13:37:30 +0200 (CEST) Subject: [pypy-commit] pypy default: fix some tests in test_pypy_c Message-ID: <20130524113730.24A0E1C0DC9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64536:13938246ac64 Date: 2013-05-24 13:36 +0200 http://bitbucket.org/pypy/pypy/changeset/13938246ac64/ Log: fix some tests in test_pypy_c diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,7 +105,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -142,7 +141,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -339,7 +339,6 @@ loop, = log.loops_by_filename(self.filepath) # the int strategy is used here assert loop.match_by_id('append', """ - guard_not_invalidated(descr=...) i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) # Will be killed by the backend @@ -487,7 +486,6 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) - guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -587,6 +585,7 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' + guard_not_invalidated(descr=...) i1 = force_token() ''') diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -85,7 +85,7 @@ # exported_state is clear by optimizeopt when the short preamble is # constrcucted. if that did not happen the label should not show up # in a trace that will be used - assert descr.exported_state is None + assert descr.exported_state is None if not we_are_translated(): op._descr_wref = weakref.ref(op._descr) op.cleardescr() # clear reference to prevent the history.Stats @@ -819,7 +819,7 @@ # The history contains new operations to attach as the code for the # failure of 'resumekey.guard_op'. - # + # # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. new_trace = create_empty_loop(metainterp) From noreply at buildbot.pypy.org Fri May 24 16:53:14 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 24 May 2013 16:53:14 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Add a test for pickling scalars Message-ID: <20130524145314.984201C094F@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64537:ccb9a74db059 Date: 2013-05-24 16:42 +0200 http://bitbucket.org/pypy/pypy/changeset/ccb9a74db059/ Log: Add a test for pickling scalars diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -0,0 +1,11 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +class AppTestScalar(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) + + def test_pickle(self): + from numpypy import dtype, int32, float64, complex128 + from numpypy.core.multiarray import scalar + assert int32(1337).__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) + assert float64(13.37).__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) + assert complex128(13 + 37.j).__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) From noreply at buildbot.pypy.org Fri May 24 17:10:42 2013 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 24 May 2013 17:10:42 +0200 (CEST) Subject: [pypy-commit] pypy numpypy-nditer: wip - finding shape for iterators including external_loop flag Message-ID: <20130524151042.BD0131C094F@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: numpypy-nditer Changeset: r64538:3005bc67833e Date: 2013-05-18 20:48 +0300 http://bitbucket.org/pypy/pypy/changeset/3005bc67833e/ Log: wip - finding shape for iterators including external_loop flag diff --git a/pypy/module/micronumpy/interp_nditer.py b/pypy/module/micronumpy/interp_nditer.py --- a/pypy/module/micronumpy/interp_nditer.py +++ b/pypy/module/micronumpy/interp_nditer.py @@ -3,7 +3,8 @@ from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.error import OperationError from pypy.module.micronumpy.base import W_NDimArray, convert_to_array -from pypy.module.micronumpy.strides import calculate_broadcast_strides +from pypy.module.micronumpy.strides import (calculate_broadcast_strides, + shape_agreement_multiple) from pypy.module.micronumpy.iter import MultiDimViewIterator from pypy.module.micronumpy import support from pypy.module.micronumpy.arrayimpl.concrete import SliceArray @@ -141,7 +142,7 @@ 'Iterator flag EXTERNAL_LOOP cannot be used if an index or ' 'multi-index is being tracked')) -def get_iter(space, order, imp, backward): +def get_iter(space, order, imp, shape): if order == 'K' or (order == 'C' and imp.order == 'C'): backward = False elif order =='F' and imp.order == 'C': @@ -154,14 +155,12 @@ # flip the strides. Is this always true for multidimension? strides = [s for s in imp.strides[::-1]] backstrides = [s for s in imp.backstrides[::-1]] - shape = [s for s in imp.shape[::-1]] + shape = [s for s in shape[::-1]] else: strides = imp.strides backstrides = imp.backstrides - shape = imp.shape - shape1d = [support.product(imp.shape),] - r = calculate_broadcast_strides(strides, backstrides, shape, - shape1d, backward) + r = calculate_broadcast_strides(strides, backstrides, imp.shape, + shape, backward) return MultiDimViewIterator(imp, imp.dtype, imp.start, r[0], r[1], shape) @@ -190,10 +189,13 @@ self.op_flags = parse_op_arg(space, 'op_flags', w_op_flags, len(self.seq), parse_op_flag) self.iters=[] + self.shape = iter_shape = shape_agreement_multiple(space, self.seq) + if self.external_loop: + xxx find longest contiguous shape + iter_shape = iter_shape[1:] for i in range(len(self.seq)): - # XXX the shape of the iter depends on all the seq.shapes together self.iters.append(get_iter(space, self.order, - self.seq[i].implementation, self.op_flags[i])) + self.seq[i].implementation, iter_shape)) def descr_iter(self, space): return space.wrap(self) From noreply at buildbot.pypy.org Fri May 24 17:10:44 2013 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 24 May 2013 17:10:44 +0200 (CEST) Subject: [pypy-commit] pypy default: try to make packaging windows more robust but more prone to packaging nonsense Message-ID: <20130524151044.11B4B1C094F@cobra.cs.uni-duesseldorf.de> Author: Matti Picus Branch: Changeset: r64539:950a858b3b98 Date: 2013-05-24 18:05 +0300 http://bitbucket.org/pypy/pypy/changeset/950a858b3b98/ Log: try to make packaging windows more robust but more prone to packaging nonsense 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 @@ -73,6 +73,11 @@ rename_pypy_c += '.exe' binaries = [(pypy_c, rename_pypy_c)] # + builddir = udir.ensure("build", dir=True) + pypydir = builddir.ensure(name, dir=True) + includedir = basedir.join('include') + pypydir.ensure('include', dir=True) + if sys.platform == 'win32': #Don't include a mscvrXX.dll, users should get their own. #Instructions are provided on the website. @@ -85,12 +90,22 @@ p = pypy_c.dirpath().join(extra) if not p.check(): p = py.path.local.sysfind(extra) - assert p, "%s not found" % (extra,) + if not p: + print "%s not found, expect trouble if this is a shared build" % (extra,) + continue print "Picking %s" % p binaries.append((p, p.basename)) - # - builddir = udir.ensure("build", dir=True) - pypydir = builddir.ensure(name, dir=True) + if pypy_c.dirpath().join("libpypy-c.lib").check(): + shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), + str(pypydir.join('include/python27.lib'))) + print "Picking %s as %s" % (pypy_c.dirpath().join("libpypy-c.lib"), + pypydir.join('include/python27.lib')) + else: + pass + # XXX users will complain that they cannot compile cpyext + # modules for windows, has the lib moved or are there no + # exported functions in the dll so no import library is created? + # Careful: to copy lib_pypy, copying just the svn-tracked files # would not be enough: there are also ctypes_config_cache/_*_cache.py. shutil.copytree(str(basedir.join('lib-python').join(STDLIB_VER)), @@ -102,15 +117,10 @@ '*.c', '*.o')) for file in ['LICENSE', 'README.rst']: shutil.copy(str(basedir.join(file)), str(pypydir)) - pypydir.ensure('include', dir=True) - if sys.platform == 'win32': - shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), - str(pypydir.join('include/python27.lib'))) - # we want to put there all *.h and *.inl from trunk/include - # and from pypy/_interfaces - includedir = basedir.join('include') headers = includedir.listdir('*.h') + includedir.listdir('*.inl') for n in headers: + # we want to put there all *.h and *.inl from trunk/include + # and from pypy/_interfaces shutil.copy(str(n), str(pypydir.join('include'))) # spdir = pypydir.ensure('site-packages', dir=True) From noreply at buildbot.pypy.org Fri May 24 17:12:28 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 24 May 2013 17:12:28 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Test more Message-ID: <20130524151228.D0CB91C0F38@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64540:b52f6e59e41a Date: 2013-05-24 16:57 +0200 http://bitbucket.org/pypy/pypy/changeset/b52f6e59e41a/ Log: Test more diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -13,6 +13,7 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', '_reconstruct' : 'interp_numarray._reconstruct', + 'scalar' : 'interp_numarray.scalar', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,6 +1051,9 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) +def scalar(space, w_dtype): + pass + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py --- a/pypy/module/micronumpy/test/test_scalar.py +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -6,6 +6,15 @@ def test_pickle(self): from numpypy import dtype, int32, float64, complex128 from numpypy.core.multiarray import scalar - assert int32(1337).__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) - assert float64(13.37).__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) - assert complex128(13 + 37.j).__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) + from cPickle import loads, dumps + i = int32(1337) + f = float64(13.37) + c = complex128(13 + 37.j) + + assert i.__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) + assert f.__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) + assert c.__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) + + assert loads(dumps(i)) == i + assert loads(dumps(f)) == f + assert loads(dumps(c)) == c From noreply at buildbot.pypy.org Fri May 24 17:12:30 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 24 May 2013 17:12:30 +0200 (CEST) Subject: [pypy-commit] pypy default: Remove dead code Message-ID: <20130524151230.1F9F71C0F38@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: Changeset: r64541:b98e6b4ac4ef Date: 2013-05-24 17:10 +0200 http://bitbucket.org/pypy/pypy/changeset/b98e6b4ac4ef/ Log: Remove dead code diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,7 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1704,25 +1704,6 @@ T = lltype.Char def _coerce(self, space, arr, ofs, dtype, w_items, shape): - items_w = space.fixedview(w_items) - for i in range(len(items_w)): - subdtype = dtype.subdtype - itemtype = subdtype.itemtype - if space.len_w(shape) <= 1: - w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) - itemtype.store(arr, 0, ofs, w_box) - ofs += itemtype.get_element_size() - else: - size = 1 - for dimension in shape[1:]: - size *= dimension - size *= itemtype.get_element_size() - for w_item in items_w: - self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) - ofs += size - return arr - - def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match items_w = space.fixedview(w_items) subdtype = dtype.subdtype From noreply at buildbot.pypy.org Fri May 24 17:12:31 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 24 May 2013 17:12:31 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge default Message-ID: <20130524151231.66A981C0F38@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: Changeset: r64542:4668b8d8a921 Date: 2013-05-24 17:10 +0200 http://bitbucket.org/pypy/pypy/changeset/4668b8d8a921/ Log: Merge default From noreply at buildbot.pypy.org Fri May 24 18:31:39 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 24 May 2013 18:31:39 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed the bugs in FileOpen: Message-ID: <20130524163139.819D01C23F4@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r416:44b7cd5560d8 Date: 2013-05-24 13:58 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/44b7cd5560d8/ Log: fixed the bugs in FileOpen: - removed truncate flag - the flag-combination create & rdwr automatically mean that the file is zeroed out, therefore use this combination only when the file is actually missing diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -38,11 +38,15 @@ @FilePlugin.expose_primitive(unwrap_spec=[object, str, object]) def primitiveFileOpen(interp, s_frame, w_rcvr, file_path, w_writeable_flag): space = interp.space + file_missing = not os.path.exists(file_path) if w_writeable_flag is space.w_true: - mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC + if file_missing: + mode = os.O_RDWR | os.O_CREAT + else: + mode = os.O_RDWR else: mode = os.O_RDONLY - if not os.path.exists(file_path): + if file_missing: return space.w_nil try: file_descriptor = os.open(file_path, mode, 0666) From noreply at buildbot.pypy.org Fri May 24 18:31:38 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 24 May 2013 18:31:38 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added short access to bytes/words-objects (primitives 143, 144) Message-ID: <20130524163138.6787C1C0F38@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r415:8646558cfea0 Date: 2013-05-24 13:56 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/8646558cfea0/ Log: added short access to bytes/words-objects (primitives 143, 144) diff --git a/spyvm/model.py b/spyvm/model.py --- a/spyvm/model.py +++ b/spyvm/model.py @@ -728,6 +728,26 @@ assert len(character) == 1 self.bytes[n0] = character + def short_at0(self, space, index0): + from rpython.rlib.rarithmetic import intmask + byte_index0 = index0 * 2 + byte0 = ord(self.getchar(byte_index0)) + byte1 = ord(self.getchar(byte_index0 + 1)) << 8 + if byte1 & 0x8000 != 0: + byte1 = intmask(0xffff0000 | byte1) + return space.wrap_int(byte1 | byte0) + + def short_atput0(self, space, index0, w_value): + from rpython.rlib.rarithmetic import int_between + i_value = space.unwrap_int(w_value) + if not int_between(-32768, i_value, 0x8000): + raise error.PrimitiveFailedError + byte_index0 = index0 * 2 + byte0 = i_value & 0xff + byte1 = (i_value & 0xff00) >> 8 + self.setchar(byte_index0, chr(byte0)) + self.setchar(byte_index0 + 1, chr(byte1)) + def size(self): return len(self.bytes) @@ -797,6 +817,29 @@ def setword(self, n, word): self.words[n] = r_uint(word) + def short_at0(self, space, index0): + word = self.getword(index0 / 2) + if index0 % 2 == 0: + short = word & 0xffff + else: + short = (word >> 16) & 0xffff + if short & 0x8000 != 0: + short = 0xffff0000 | short + return space.wrap_int(intmask(short)) + + def short_atput0(self, space, index0, w_value): + from rpython.rlib.rarithmetic import int_between + i_value = space.unwrap_int(w_value) + if not int_between(-32768, i_value, 0x8000): + raise error.PrimitiveFailedError + word_index0 = index0 / 2 + word = self.getword(word_index0) + if index0 % 2 == 0: + word = (word & 0xffff0000) | (i_value & 0xffff) + else: + word = (i_value << 16) | (word & 0xffff) + self.setword(word_index0, word) + def size(self): return len(self.words) diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -975,12 +975,27 @@ #____________________________________________________________________________ # Misc Primitives (138 - 149) VM_PATH = 142 +SHORT_AT = 143 +SHORT_AT_PUT = 144 CLONE = 148 @expose_primitive(VM_PATH, unwrap_spec=[object]) def func(interp, s_frame, w_receiver): return interp.space.wrap_string(os.path.join(os.getcwd(), '')) + at expose_primitive(SHORT_AT, unwrap_spec=[object, index1_0]) +def func(interp, s_frame, w_receiver, n0): + if not isinstance(w_receiver, (model.W_BytesObject, model.W_WordsObject)): + raise PrimitiveFailedError + return w_receiver.short_at0(interp.space, n0) + + at expose_primitive(SHORT_AT_PUT, unwrap_spec=[object, index1_0, object]) +def func(interp, s_frame, w_receiver, n0, w_value): + if not isinstance(w_receiver, (model.W_BytesObject, model.W_WordsObject)): + raise PrimitiveFailedError + return w_receiver.short_atput0(interp.space, n0) + + @expose_primitive(CLONE, unwrap_spec=[object]) def func(interp, s_frame, w_arg): return w_arg.clone(interp.space) diff --git a/spyvm/test/test_model.py b/spyvm/test/test_model.py --- a/spyvm/test/test_model.py +++ b/spyvm/test/test_model.py @@ -288,6 +288,42 @@ assert target.at0(space, i) == source.at0(space, i) assert hex(r_uint(target.value)) == hex(r_uint(source.value)) +def test_BytesObject_short_at(): + target = model.W_BytesObject(space, None, 4) + target.setchar(0, chr(0x00)) + target.setchar(1, chr(0x01)) + target.setchar(2, chr(0x10)) + target.setchar(3, chr(0x81)) + assert target.short_at0(space, 0).value == 0x0100 + assert target.short_at0(space, 1).value == intmask(0xffff8110) + +def test_BytesObject_short_atput(): + target = model.W_BytesObject(space, None, 4) + target.short_atput0(space, 0, space.wrap_int(0x0100)) + target.short_atput0(space, 1, space.wrap_int(intmask(0xffff8110))) + assert target.getchar(0) == chr(0x00) + assert target.getchar(1) == chr(0x01) + assert target.getchar(2) == chr(0x10) + assert target.getchar(3) == chr(0x81) + +def test_WordsObject_short_at(): + target = model.W_WordsObject(space, None, 2) + target.setword(0, r_uint(0x00018000)) + target.setword(1, r_uint(0x80010111)) + assert target.short_at0(space, 0).value == intmask(0xffff8000) + assert target.short_at0(space, 1).value == intmask(0x0001) + assert target.short_at0(space, 2).value == intmask(0x0111) + assert target.short_at0(space, 3).value == intmask(0xffff8001) + +def test_WordsObject_short_atput(): + target = model.W_WordsObject(space, None, 2) + target.short_atput0(space, 0, space.wrap_int(0x0100)) + target.short_atput0(space, 1, space.wrap_int(-1)) + target.short_atput0(space, 2, space.wrap_int(intmask(0xffff8000))) + target.short_atput0(space, 3, space.wrap_int(0x7fff)) + assert target.getword(0) == 0xffff0100 + assert target.getword(1) == 0x7fff8000 + @py.test.mark.skipif("socket.gethostname() == 'precise32'") def test_display_bitmap(): # XXX: Patch SDLDisplay -> get_pixelbuffer() to circumvent From noreply at buildbot.pypy.org Fri May 24 18:31:40 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 24 May 2013 18:31:40 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changes needed to make the vm translateable: Message-ID: <20130524163140.B04741C3266@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r417:ca22950ac473 Date: 2013-05-24 18:21 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/ca22950ac473/ Log: changes needed to make the vm translateable: - added intmask call when creating Smallintegers, thus asserting the type for the translator - added some more such calls - restructured primitiveFileStdioHandles to allow calls to module sys to be in global scope... diff --git a/spyvm/model.py b/spyvm/model.py --- a/spyvm/model.py +++ b/spyvm/model.py @@ -147,7 +147,7 @@ _immutable_fields_ = ["value"] def __init__(self, value): - self.value = value + self.value = intmask(value) def getclass(self, space): return space.w_SmallInteger @@ -244,7 +244,7 @@ _attrs_ = ["value", "_exposed_size"] def __init__(self, value, size=4): - self.value = value + self.value = intmask(value) self._exposed_size = size def fillin(self, space, g_self): @@ -267,7 +267,6 @@ return "W_LargePositiveInteger1Word(%d)" % r_uint(self.value) def lshift(self, space, shift): - from rpython.rlib.rarithmetic import intmask, r_uint # shift > 0, therefore the highest bit of upperbound is not set, # i.e. upperbound is positive upperbound = intmask(r_uint(-1) >> shift) @@ -729,12 +728,11 @@ self.bytes[n0] = character def short_at0(self, space, index0): - from rpython.rlib.rarithmetic import intmask byte_index0 = index0 * 2 byte0 = ord(self.getchar(byte_index0)) byte1 = ord(self.getchar(byte_index0 + 1)) << 8 if byte1 & 0x8000 != 0: - byte1 = intmask(0xffff0000 | byte1) + byte1 = intmask(-65536 | byte1) # -65536 = 0xffff0000 return space.wrap_int(byte1 | byte0) def short_atput0(self, space, index0, w_value): @@ -818,13 +816,13 @@ self.words[n] = r_uint(word) def short_at0(self, space, index0): - word = self.getword(index0 / 2) + word = intmask(self.getword(index0 / 2)) if index0 % 2 == 0: short = word & 0xffff else: short = (word >> 16) & 0xffff if short & 0x8000 != 0: - short = 0xffff0000 | short + short = -65536 | short # -65536 = 0xffff0000 return space.wrap_int(intmask(short)) def short_atput0(self, space, index0, w_value): @@ -833,12 +831,13 @@ if not int_between(-32768, i_value, 0x8000): raise error.PrimitiveFailedError word_index0 = index0 / 2 - word = self.getword(word_index0) + word = intmask(self.getword(word_index0)) if index0 % 2 == 0: - word = (word & 0xffff0000) | (i_value & 0xffff) + word = (word & -65536) | (i_value & 0xffff) # -65536 = 0xffff0000 else: word = (i_value << 16) | (word & 0xffff) - self.setword(word_index0, word) + value = r_uint(word) + self.setword(word_index0, value) def size(self): return len(self.words) diff --git a/spyvm/objspace.py b/spyvm/objspace.py --- a/spyvm/objspace.py +++ b/spyvm/objspace.py @@ -246,10 +246,10 @@ def unwrap_int(self, w_value): if isinstance(w_value, model.W_SmallInteger): - return w_value.value + return intmask(w_value.value) elif isinstance(w_value, model.W_LargePositiveInteger1Word): if w_value.value >= 0: - return w_value.value + return intmask(w_value.value) else: raise UnwrappingError("The value is negative when interpreted as 32bit value.") raise UnwrappingError("expected a W_SmallInteger or W_LargePositiveInteger1Word, got %s" % (w_value,)) diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -1,4 +1,8 @@ -import os, stat +import os, stat, sys + +from rpython.rlib import jit +from rpython.rlib.listsort import TimSort + from spyvm import model, error from spyvm.plugins.plugin import Plugin from spyvm.primitives import PrimitiveFailedError, index1_0 @@ -7,6 +11,10 @@ FilePlugin = Plugin() os.stat_float_times(False) +std_fds = [sys.stdin.fileno(), + sys.stdout.fileno(), + sys.stderr.fileno()] + @FilePlugin.expose_primitive(unwrap_spec=[object]) def primitiveDirectoryDelimitor(interp, s_frame, w_rcvr): return interp.space.wrap_char(os.path.sep) @@ -22,18 +30,24 @@ space = interp.space if index >= len(contents): return space.w_nil - py_name = sorted(contents)[index] + + # should probably be sorted... + contents + py_name = contents[index] try: file_path = os.path.join(full_path, py_name) except OSError: raise PrimitiveFailedError file_info = os.stat(file_path) - name = space.wrap_string(py_name) - creationTime = smalltalk_timestamp(space, file_info.st_ctime) - modificationTime = smalltalk_timestamp(space, file_info.st_mtime) - dirFlag = space.w_true if stat.S_IFDIR & file_info.st_mode else space.w_false - fileSize = space.wrap_int(file_info.st_size) - return space.wrap_list([name, creationTime, modificationTime, dirFlag, fileSize]) + + w_name = space.wrap_string(py_name) + w_creationTime = smalltalk_timestamp(space, file_info.st_ctime) + w_modificationTime = smalltalk_timestamp(space, file_info.st_mtime) + w_dirFlag = space.w_true if stat.S_IFDIR & file_info.st_mode else space.w_false + w_fileSize = space.wrap_int(file_info.st_size) + + return space.wrap_list([w_name, w_creationTime, w_modificationTime, + w_dirFlag, w_fileSize]) @FilePlugin.expose_primitive(unwrap_spec=[object, str, object]) def primitiveFileOpen(interp, s_frame, w_rcvr, file_path, w_writeable_flag): @@ -56,6 +70,7 @@ @FilePlugin.expose_primitive(unwrap_spec=[object, int]) def primitiveFileClose(interp, s_frame, w_rcvr, fd): + from rpython.rlib.rarithmetic import intmask try: os.close(fd) except OSError: @@ -64,15 +79,47 @@ @FilePlugin.expose_primitive(unwrap_spec=[object, int]) def primitiveFileAtEnd(interp, s_frame, w_rcvr, fd): - py_file = os.fdopen(fd) - stat = os.fstat(fd) - if py_file.tell() >= stat.st_size: + file_info = os.fstat(fd) + if os.lseek(fd, 0, os.SEEK_CUR) >= file_info.st_size: return interp.space.w_true else: return interp.space.w_false + at FilePlugin.expose_primitive(unwrap_spec=[object, int, object, index1_0, int]) +def primitiveFileRead(interp, s_frame, w_rcvr, fd, target, start, count): + if not isinstance(target, model.W_BytesObject): + raise PrimitiveFailedError + try: + contents = os.read(fd, count) + except OSError: + raise PrimitiveFailedError + space = interp.space + len_read = len(contents) + if target.size() < start + len_read: + raise PrimitiveFailedError + for i in range(len_read): + target.setchar(start + i, contents[i]) + return space.wrap_int(len_read) + + at FilePlugin.expose_primitive(unwrap_spec=[object, int]) +def primitiveFileSize(interp, s_frame, w_rcvr, fd): + try: + file_info = os.fstat(fd) + except OSError: + raise PrimitiveFailedError + return interp.space.wrap_int(file_info.st_size) + + at FilePlugin.expose_primitive(unwrap_spec=[object]) +def primitiveFileStdioHandles(interp, s_frame, w_rcvr): + # This primitive may give an error-code... + # return an array with stdin, stdout, stderr + space = interp.space + return space.wrap_list([space.wrap_int(fd) for fd in std_fds]) + + at jit.elidable def smalltalk_timestamp(space, sec_since_epoch): import time from spyvm.primitives import secs_between_1901_and_1970 - sec_since_1901 = sec_since_epoch + secs_between_1901_and_1970 + from rpython.rlib.rarithmetic import r_uint + sec_since_1901 = r_uint(sec_since_epoch + secs_between_1901_and_1970) return space.wrap_uint(sec_since_1901) diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -985,15 +985,17 @@ @expose_primitive(SHORT_AT, unwrap_spec=[object, index1_0]) def func(interp, s_frame, w_receiver, n0): - if not isinstance(w_receiver, (model.W_BytesObject, model.W_WordsObject)): + if not (isinstance(w_receiver, model.W_BytesObject) + or isinstance(w_receiver, model.W_WordsObject)): raise PrimitiveFailedError return w_receiver.short_at0(interp.space, n0) @expose_primitive(SHORT_AT_PUT, unwrap_spec=[object, index1_0, object]) def func(interp, s_frame, w_receiver, n0, w_value): - if not isinstance(w_receiver, (model.W_BytesObject, model.W_WordsObject)): + if not (isinstance(w_receiver, model.W_BytesObject) + or isinstance(w_receiver, model.W_WordsObject)): raise PrimitiveFailedError - return w_receiver.short_atput0(interp.space, n0) + return w_receiver.short_atput0(interp.space, n0, w_value) @expose_primitive(CLONE, unwrap_spec=[object]) From noreply at buildbot.pypy.org Fri May 24 19:08:24 2013 From: noreply at buildbot.pypy.org (wlav) Date: Fri, 24 May 2013 19:08:24 +0200 (CEST) Subject: [pypy-commit] pypy default: clarify the need of finding the dictionary library through the normal dynload lookup Message-ID: <20130524170824.EB2771C23F4@cobra.cs.uni-duesseldorf.de> Author: Wim Lavrijsen Branch: Changeset: r64543:28384941048c Date: 2013-05-24 10:08 -0700 http://bitbucket.org/pypy/pypy/changeset/28384941048c/ Log: clarify the need of finding the dictionary library through the normal dynload lookup diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -163,6 +163,9 @@ $ genreflex MyClass.h $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex +Next, make sure that the library can be found through the dynamic lookup path +(the ``LD_LIBRARY_PATH`` environment variable on Linux, ``PATH`` on Windows), +for example by adding ".". Now you're ready to use the bindings. Since the bindings are designed to look pythonistic, it should be straightforward:: From noreply at buildbot.pypy.org Fri May 24 19:22:29 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 24 May 2013 19:22:29 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Merge default Message-ID: <20130524172229.1363B1C094F@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64544:23c18ab3f91b Date: 2013-05-24 19:03 +0200 http://bitbucket.org/pypy/pypy/changeset/23c18ab3f91b/ Log: Merge default diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -48,6 +48,15 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.value) + def descr_reduce(self, space): + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + return space.newtuple([scalar, space.wrap(self._get_dtype())]) + class ComplexBox(object): _mixin_ = True From noreply at buildbot.pypy.org Fri May 24 19:22:30 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 24 May 2013 19:22:30 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Progress for scalar pickling Message-ID: <20130524172230.72EE31C094F@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64545:9dd081fd321d Date: 2013-05-24 19:21 +0200 http://bitbucket.org/pypy/pypy/changeset/9dd081fd321d/ Log: Progress for scalar pickling diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -11,6 +11,7 @@ from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from pypy.interpreter.mixedmodule import MixedModule MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else () MIXIN_64 = (int_typedef,) if LONG_BIT == 64 else () @@ -55,7 +56,7 @@ assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") - return space.newtuple([scalar, space.wrap(self._get_dtype())]) + return space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space))])]) class ComplexBox(object): _mixin_ = True @@ -73,6 +74,14 @@ def convert_imag_to(self, dtype): return dtype.box(self.imag) + def descr_reduce(self, space): + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + return space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space))])]) class W_GenericBox(W_Root): _attrs_ = () @@ -465,6 +474,7 @@ __module__ = "numpypy", __new__ = interp2app(W_BoolBox.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_BoolBox.descr_reduce), ) W_NumberBox.typedef = TypeDef("number", W_GenericBox.typedef, @@ -487,42 +497,49 @@ __module__ = "numpypy", __new__ = interp2app(W_Int8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int8Box.descr_reduce), ) W_UInt8Box.typedef = TypeDef("uint8", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt8Box.descr_reduce), ) W_Int16Box.typedef = TypeDef("int16", W_SignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Int16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int16Box.descr_reduce), ) W_UInt16Box.typedef = TypeDef("uint16", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt16Box.descr_reduce), ) W_Int32Box.typedef = TypeDef("int32", (W_SignedIntegerBox.typedef,) + MIXIN_32, __module__ = "numpypy", __new__ = interp2app(W_Int32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int32Box.descr_reduce), ) W_UInt32Box.typedef = TypeDef("uint32", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt32Box.descr_reduce), ) W_Int64Box.typedef = TypeDef("int64", (W_SignedIntegerBox.typedef,) + MIXIN_64, __module__ = "numpypy", __new__ = interp2app(W_Int64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int64Box.descr_reduce), ) if LONG_BIT == 32: @@ -536,6 +553,7 @@ __module__ = "numpypy", __new__ = interp2app(W_UInt64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt64Box.descr_reduce), ) W_InexactBox.typedef = TypeDef("inexact", W_NumberBox.typedef, @@ -550,23 +568,27 @@ __module__ = "numpypy", __new__ = interp2app(W_Float16Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float16Box.descr_reduce), ) W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Float32Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float32Box.descr_reduce), ) W_Float64Box.typedef = TypeDef("float64", (W_FloatingBox.typedef, float_typedef), __module__ = "numpypy", __new__ = interp2app(W_Float64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float64Box.descr_reduce), ) if ENABLED_LONG_DOUBLE and long_double_size == 12: W_Float96Box.typedef = TypeDef("float96", (W_FloatingBox.typedef), __module__ = "numpypy", + __reduce__ = interp2app(W_Float96Box.descr_reduce), __new__ = interp2app(W_Float96Box.descr__new__.im_func), ) @@ -574,6 +596,7 @@ W_Complex192Box.typedef = TypeDef("complex192", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex192Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex192Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -583,11 +606,13 @@ __module__ = "numpypy", __new__ = interp2app(W_Float128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float128Box.descr_reduce), ) W_Complex256Box.typedef = TypeDef("complex256", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex256Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex256Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -625,6 +650,7 @@ W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex128Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -632,6 +658,7 @@ W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex64Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox .descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) From noreply at buildbot.pypy.org Fri May 24 21:04:18 2013 From: noreply at buildbot.pypy.org (fijal) Date: Fri, 24 May 2013 21:04:18 +0200 (CEST) Subject: [pypy-commit] pypy default: thread safetry fixes Message-ID: <20130524190418.ADA431C23F4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64546:cb648df8a5fc Date: 2013-05-24 21:03 +0200 http://bitbucket.org/pypy/pypy/changeset/cb648df8a5fc/ Log: thread safetry fixes diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,14 +124,21 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - if space.config.objspace.usemodules.thread: - os_thread.setup_threads(space) - rffi.aroundstate.before() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - if space.config.objspace.usemodules.thread: - rthread.gc_thread_start() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + os_thread.bootstrapper.acquire(space, None, None) + rthread.gc_thread_start() + os_thread.bootstrapper.nbthreads += 1 + os_thread.bootstrapper.release() + rffi.aroundstate.before() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), From noreply at buildbot.pypy.org Fri May 24 21:12:14 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 24 May 2013 21:12:14 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: Write this code in a way that handles all conditions correctly. Now to see translate and see if metainterp really marks stuff well enough. Message-ID: <20130524191214.D56AC1C0F38@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64547:3bca17abd500 Date: 2013-05-24 14:38 -0400 http://bitbucket.org/pypy/pypy/changeset/3bca17abd500/ Log: Write this code in a way that handles all conditions correctly. Now to see translate and see if metainterp really marks stuff well enough. diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -25,23 +25,35 @@ if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) - return getframe(space, depth) + return getframe_unroll(space, depth) @jit.look_inside_iff(lambda space, depth: jit.isconstant(depth)) -def getframe(space, depth): +def getframe_unroll(space, depth): ec = space.getexecutioncontext() f = ec.gettopframe_nohidden() + while jit.isvirtual(f): + if f is None: + raise OperationError(space.w_ValueError, + space.wrap("call stack is not deep enough")) + if depth == 0: + f.mark_as_escaped() + return space.wrap(f) + depth -= 1 + f = ec.getnextframe_nohidden(f) + return getframe_fallback(space, ec, depth, f) + + +def getframe_fallback(space, ec, depth, f): while True: if f is None: raise OperationError(space.w_ValueError, space.wrap("call stack is not deep enough")) if depth == 0: - break + f.mark_as_escaped() + return space.wrap(f) depth -= 1 f = ec.getnextframe_nohidden(f) - f.mark_as_escaped() - return space.wrap(f) @unwrap_spec(new_limit="c_int") From noreply at buildbot.pypy.org Fri May 24 21:12:16 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 24 May 2013 21:12:16 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: Now it's also possible to access the top JIT'd frame "for free" Message-ID: <20130524191216.4322F1C0F38@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64548:6d3b4aaf4678 Date: 2013-05-24 14:41 -0400 http://bitbucket.org/pypy/pypy/changeset/6d3b4aaf4678/ Log: Now it's also possible to access the top JIT'd frame "for free" diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -41,6 +41,16 @@ return space.wrap(f) depth -= 1 f = ec.getnextframe_nohidden(f) + + if f is None: + raise OperationError(space.w_ValueError, + space.wrap("call stack is not deep enough")) + if depth == 0: + f.mark_as_escaped() + return space.wrap(f) + depth -= 1 + f = ec.getnextframe_nohidden(f) + return getframe_fallback(space, ec, depth, f) From noreply at buildbot.pypy.org Fri May 24 21:26:24 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 24 May 2013 21:26:24 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: kill some dead code and whatnot Message-ID: <20130524192624.B41601C0F38@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64549:d2fdac35984e Date: 2013-05-24 15:19 -0400 http://bitbucket.org/pypy/pypy/changeset/d2fdac35984e/ Log: kill some dead code and whatnot diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -156,7 +156,7 @@ iteritems = self._fields.iteritems() if not we_are_translated(): #random order is fine, except for tests iteritems = list(iteritems) - iteritems.sort(key = lambda (x,y): x.sort_key()) + iteritems.sort(key=lambda (x, y): x.sort_key()) for ofs, value in iteritems: if value.is_null(): continue @@ -353,7 +353,7 @@ # random order is fine, except for tests if not we_are_translated(): iteritems = list(iteritems) - iteritems.sort(key = lambda (x, y): x.sort_key()) + iteritems.sort(key=lambda (x, y): x.sort_key()) for descr, value in iteritems: subbox = value.force_box(optforce) op = ResOperation(rop.SETINTERIORFIELD_GC, @@ -426,7 +426,7 @@ if not we_are_translated(): op.name = 'FORCE ' + self.source_op.name optforce.emit_operation(self.source_op) - self.box = box = self.source_op.result + self.box = self.source_op.result for i in range(len(self.buffer.offsets)): # get a pointer to self.box+offset offset = self.buffer.offsets[i] @@ -533,8 +533,6 @@ self.emit_operation(op) def optimize_VIRTUAL_REF(self, op): - indexbox = op.getarg(1) - # # get some constants vrefinfo = self.optimizer.metainterp_sd.virtualref_info c_cls = vrefinfo.jit_virtual_ref_const_class @@ -570,7 +568,7 @@ objbox = op.getarg(1) if not CONST_NULL.same_constant(objbox): seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, - descr = vrefinfo.descr_forced)) + descr=vrefinfo.descr_forced)) # - set 'virtual_token' to TOKEN_NONE (== NULL) args = [op.getarg(0), CONST_NULL] From noreply at buildbot.pypy.org Fri May 24 21:26:26 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 24 May 2013 21:26:26 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: The result of virtual_ref operation is new. Message-ID: <20130524192626.32B791C0F38@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64550:92aef69ad20f Date: 2013-05-24 15:25 -0400 http://bitbucket.org/pypy/pypy/changeset/92aef69ad20f/ Log: The result of virtual_ref operation is new. diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1158,6 +1158,7 @@ obj = box.getref_base() vref = vrefinfo.virtual_ref_during_tracing(obj) resbox = history.BoxPtr(vref) + self.metainterp.heapcache.new(resbox) cindex = history.ConstInt(len(metainterp.virtualref_boxes) // 2) metainterp.history.record(rop.VIRTUAL_REF, [box, cindex], resbox) # Note: we allocate a JIT_VIRTUAL_REF here From noreply at buildbot.pypy.org Sat May 25 01:52:54 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 25 May 2013 01:52:54 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: add %N to return .getname(space) Message-ID: <20130524235254.23EAB1C3266@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64552:109b2c860963 Date: 2013-05-24 16:50 -0700 http://bitbucket.org/pypy/pypy/changeset/109b2c860963/ Log: add %N to return .getname(space) diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -306,7 +306,7 @@ _fmtcache = {} _fmtcache2 = {} -_FMTS = tuple('sdT') +_FMTS = tuple('sdNT') def decompose_valuefmt(valuefmt): """Returns a tuple of string parts extracted from valuefmt, @@ -363,9 +363,11 @@ string = self.xstrings[i] value = getattr(self, attr) lst[i+i] = string - if fmt == 'T': + if fmt in 'NT': space = self.w_type.space - lst[i+i+1] = space.type(value).getname(space) + if fmt == 'T': + value = space.type(value) + lst[i+i+1] = value.getname(space) else: lst[i+i+1] = str(value) lst[-1] = self.xstrings[-1] @@ -385,7 +387,14 @@ def operationerrfmt(w_type, valuefmt, *args): """Equivalent to OperationError(w_type, space.wrap(valuefmt % args)). More efficient in the (common) case where the value is not actually - needed.""" + needed. + + Also supports the following extra format characters: + + %N - The result of arg.getname(space) + %T - The result of space.type(arg).getname(space) + + """ OpErrFmt, strings = get_operationerr_class(valuefmt) return OpErrFmt(w_type, strings, *args) operationerrfmt._annspecialcase_ = 'specialize:arg(1)' diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -40,6 +40,16 @@ space.wrap('foo'), 'foo') assert operr._compute_value() == "'str' object has no attribute 'foo'" +def test_operationerrfmt_N(space): + operr = operationerrfmt(space.w_AttributeError, + "'%N' object has no attribute '%s'", + space.type(space.wrap('foo')), 'foo') + assert operr._compute_value() == "'str' object has no attribute 'foo'" + operr = operationerrfmt(space.w_AttributeError, + "'%N' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value() == "'?' object has no attribute 'foo'" + def test_operationerrfmt_empty(): py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") From noreply at buildbot.pypy.org Sat May 25 01:52:52 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 25 May 2013 01:52:52 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: branch for adding a couple helper format specifiers to operationerrfmt: Message-ID: <20130524235252.BF4501C23F4@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64551:dcbcd0a7c467 Date: 2013-05-24 16:48 -0700 http://bitbucket.org/pypy/pypy/changeset/dcbcd0a7c467/ Log: branch for adding a couple helper format specifiers to operationerrfmt: o add %T to return the type name. operationerrfmt has to get space w/ an awful hack (but the hack is already necessary for py3k) o operationerrfmt now requires a type object for its first arg to make this simpler diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -1,4 +1,5 @@ import cStringIO +import itertools import os import sys import traceback @@ -305,6 +306,7 @@ _fmtcache = {} _fmtcache2 = {} +_FMTS = tuple('sdT') def decompose_valuefmt(valuefmt): """Returns a tuple of string parts extracted from valuefmt, @@ -313,7 +315,7 @@ parts = valuefmt.split('%') i = 1 while i < len(parts): - if parts[i].startswith('s') or parts[i].startswith('d'): + if parts[i].startswith(_FMTS): formats.append(parts[i][0]) parts[i] = parts[i][1:] i += 1 @@ -321,10 +323,21 @@ parts[i-1] += '%' + parts[i+1] del parts[i:i+2] else: - raise ValueError("invalid format string (only %s or %d supported)") + fmts = '%%%s or %%%s' % (', %'.join(_FMTS[:-1]), _FMTS[-1]) + raise ValueError("invalid format string (only %s supported)" % + fmts) assert len(formats) > 0, "unsupported: no % command found" return tuple(parts), tuple(formats) +def _is_type(w_obj): + from pypy.objspace.std.typeobject import W_TypeObject + # HACK: isinstance(w_obj, W_TypeObject) won't translate under the + # fake objspace, but w_obj.__class__ is W_TypeObject does and short + # circuits to a False constant there, causing the isinstance to be + # ignored =[ + return (w_obj is not None and w_obj.__class__ is W_TypeObject and + isinstance(w_obj, W_TypeObject)) + def get_operrcls2(valuefmt): strings, formats = decompose_valuefmt(valuefmt) assert len(strings) == len(formats) + 1 @@ -333,24 +346,28 @@ except KeyError: from rpython.rlib.unroll import unrolling_iterable attrs = ['x%d' % i for i in range(len(formats))] - entries = unrolling_iterable(enumerate(attrs)) + entries = unrolling_iterable(zip(itertools.count(), formats, attrs)) class OpErrFmt(OperationError): def __init__(self, w_type, strings, *args): self.setup(w_type) assert len(args) == len(strings) - 1 self.xstrings = strings - for i, attr in entries: + for i, _, attr in entries: setattr(self, attr, args[i]) - assert w_type is not None + assert _is_type(w_type) def _compute_value(self): lst = [None] * (len(formats) + len(formats) + 1) - for i, attr in entries: + for i, fmt, attr in entries: string = self.xstrings[i] value = getattr(self, attr) lst[i+i] = string - lst[i+i+1] = str(value) + if fmt == 'T': + space = self.w_type.space + lst[i+i+1] = space.type(value).getname(space) + else: + lst[i+i+1] = str(value) lst[-1] = self.xstrings[-1] return ''.join(lst) # diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -12,27 +12,34 @@ assert (decompose_valuefmt("%s%d%%%s") == (("", "", "%", ""), ('s', 'd', 's'))) -def test_get_operrcls2(): +def test_get_operrcls2(space): cls, strings = get_operrcls2('abc %s def %d') assert strings == ("abc ", " def ", "") assert issubclass(cls, OperationError) - inst = cls("w_type", strings, "hello", 42) + inst = cls(space.w_OSError, strings, "hello", 42) assert inst._compute_value() == "abc hello def 42" cls2, strings2 = get_operrcls2('a %s b %d c') assert cls2 is cls # caching assert strings2 == ("a ", " b ", " c") -def test_operationerrfmt(): - operr = operationerrfmt("w_type", "abc %s def %d", "foo", 42) +def test_operationerrfmt(space): + w_exc = space.w_IOError + operr = operationerrfmt(w_exc, "abc %s def %d", "foo", 42) assert isinstance(operr, OperationError) - assert operr.w_type == "w_type" + assert operr.w_type == w_exc assert operr._w_value is None assert operr._compute_value() == "abc foo def 42" - operr2 = operationerrfmt("w_type2", "a %s b %d c", "bar", 43) + operr2 = operationerrfmt(w_exc, "a %s b %d c", "bar", 43) assert operr2.__class__ is operr.__class__ - operr3 = operationerrfmt("w_type2", "a %s b %s c", "bar", "4b") + operr3 = operationerrfmt(w_exc, "a %s b %s c", "bar", "4b") assert operr3.__class__ is not operr.__class__ +def test_operationerrfmt_T(space): + operr = operationerrfmt(space.w_AttributeError, + "'%T' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value() == "'str' object has no attribute 'foo'" + def test_operationerrfmt_empty(): py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") From noreply at buildbot.pypy.org Sat May 25 01:56:05 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 25 May 2013 01:56:05 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130524235605.DB0721C23F4@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64553:31c7f1d4c308 Date: 2013-05-24 16:55 -0700 http://bitbucket.org/pypy/pypy/changeset/31c7f1d4c308/ Log: merge default diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -163,6 +163,9 @@ $ genreflex MyClass.h $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex +Next, make sure that the library can be found through the dynamic lookup path +(the ``LD_LIBRARY_PATH`` environment variable on Linux, ``PATH`` on Windows), +for example by adding ".". Now you're ready to use the bindings. Since the bindings are designed to look pythonistic, it should be straightforward:: diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -128,14 +128,21 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - if space.config.objspace.usemodules.thread: - os_thread.setup_threads(space) - rffi.aroundstate.before() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - if space.config.objspace.usemodules.thread: - rthread.gc_thread_start() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + os_thread.bootstrapper.acquire(space, None, None) + rthread.gc_thread_start() + os_thread.bootstrapper.nbthreads += 1 + os_thread.bootstrapper.release() + rffi.aroundstate.before() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), diff --git a/pypy/interpreter/pyparser/future.py b/pypy/interpreter/pyparser/future.py --- a/pypy/interpreter/pyparser/future.py +++ b/pypy/interpreter/pyparser/future.py @@ -1,308 +1,3 @@ -""" -This automaton is designed to be invoked on a Python source string -before the real parser starts working, in order to find all legal -'from __future__ import blah'. As soon as something is encountered that -would prevent more future imports, the analysis is aborted. -The resulting legal futures are avaliable in self.flags after the -pass has ended. - -Invocation is through get_futures(src), which returns a field of flags, one per -found correct future import. - -The flags can then be used to set up the parser. -All error detection is left to the parser. - -The reason we are not using the regular lexer/parser toolchain is that -we do not want the overhead of generating tokens for entire files just -to find information that resides in the first few lines of the file. -Neither do we require sane error messages, as this job is handled by -the parser. - -To make the parsing fast, especially when the module is translated to C, -the code has been written in a very serial fashion, using an almost -assembler like style. A further speedup could be achieved by replacing -the "in" comparisons with explicit numeric comparisons. -""" - -from pypy.interpreter.astcompiler.consts import ( - CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION, CO_FUTURE_WITH_STATEMENT, - CO_FUTURE_ABSOLUTE_IMPORT, CO_FUTURE_BARRY_AS_BDFL) - -def get_futures(future_flags, source): - futures = FutureAutomaton(future_flags, source) - try: - futures.start() - except DoneException, e: - pass - return futures.flags, (futures.lineno, futures.col_offset) - -class DoneException(Exception): - pass - -whitespace = ' \t\f' -whitespace_or_newline = whitespace + '\n\r' -letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz_' -alphanumerics = letters + '1234567890' - -class FutureAutomaton(object): - """ - A future statement must appear near the top of the module. - The only lines that can appear before a future statement are: - - * the module docstring (if any), - * comments, - * blank lines, and - * other future statements. - - The features recognized by Python 2.5 are "generators", - "division", "nested_scopes" and "with_statement", "absolute_import". - "generators", "division" and "nested_scopes" are redundant - in 2.5 because they are always enabled. - - This module parses the input until it encounters something that is - not recognized as a valid future statement or something that may - precede a future statement. - """ - - def __init__(self, future_flags, string): - self.future_flags = future_flags - self.s = string - self.pos = 0 - self.current_lineno = 1 - self.lineno = -1 - self.line_start_pos = 0 - self.col_offset = 0 - self.docstring_consumed = False - self.flags = 0 - self.got_features = 0 - - def getc(self, offset=0): - try: - return self.s[self.pos + offset] - except IndexError: - raise DoneException - - def start(self): - c = self.getc() - if c in ("'", '"', "r", "u") and not self.docstring_consumed: - self.consume_docstring() - elif c == '\\' or c in whitespace_or_newline: - self.consume_empty_line() - elif c == '#': - self.consume_comment() - elif c == 'f': - self.consume_from() - else: - return - - def atbol(self): - self.current_lineno += 1 - self.line_start_pos = self.pos - - def consume_docstring(self): - self.docstring_consumed = True - if self.getc() == "r": - self.pos += 1 - if self.getc() == "u": - self.pos += 1 - endchar = self.getc() - if (self.getc() == self.getc(+1) and - self.getc() == self.getc(+2)): - self.pos += 3 - while 1: # Deal with a triple quoted docstring - c = self.getc() - if c == '\\': - self.pos += 1 - self._skip_next_char_from_docstring() - elif c != endchar: - self._skip_next_char_from_docstring() - else: - self.pos += 1 - if (self.getc() == endchar and - self.getc(+1) == endchar): - self.pos += 2 - self.consume_empty_line() - break - - else: # Deal with a single quoted docstring - self.pos += 1 - while 1: - c = self.getc() - self.pos += 1 - if c == endchar: - self.consume_empty_line() - return - elif c == '\\': - self._skip_next_char_from_docstring() - elif c in '\r\n': - # Syntax error - return - - def _skip_next_char_from_docstring(self): - c = self.getc() - self.pos += 1 - if c == '\n': - self.atbol() - elif c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - - def consume_continuation(self): - c = self.getc() - if c in '\n\r': - self.pos += 1 - self.atbol() - - def consume_empty_line(self): - """ - Called when the remainder of the line can only contain whitespace - and comments. - """ - while self.getc() in whitespace: - self.pos += 1 - if self.getc() == '#': - self.consume_comment() - elif self.getc() == ';': - self.pos += 1 - self.consume_whitespace() - self.start() - elif self.getc() in '\\': - self.pos += 1 - self.consume_continuation() - self.start() - elif self.getc() in '\r\n': - c = self.getc() - self.pos += 1 - if c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - else: - self.atbol() - self.start() - - def consume_comment(self): - self.pos += 1 - while self.getc() not in '\r\n': - self.pos += 1 - self.consume_empty_line() - - def consume_from(self): - col_offset = self.pos - self.line_start_pos - line = self.current_lineno - self.pos += 1 - if self.getc() == 'r' and self.getc(+1) == 'o' and self.getc(+2) == 'm': - self.docstring_consumed = True - self.pos += 3 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+10] != '__future__': - raise DoneException - self.pos += 10 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+6] != 'import': - raise DoneException - self.pos += 6 - self.consume_whitespace() - old_got = self.got_features - try: - if self.getc() == '(': - self.pos += 1 - self.consume_whitespace() - self.set_flag(self.get_name()) - # Set flag corresponding to name - self.get_more(paren_list=True) - else: - self.set_flag(self.get_name()) - self.get_more() - finally: - if self.got_features > old_got: - self.col_offset = col_offset - self.lineno = line - self.consume_empty_line() - - def consume_mandatory_whitespace(self): - if self.getc() not in whitespace + '\\': - raise DoneException - self.consume_whitespace() - - def consume_whitespace(self, newline_ok=False): - while 1: - c = self.getc() - if c in whitespace: - self.pos += 1 - continue - elif c == '\\' or newline_ok: - slash = c == '\\' - if slash: - self.pos += 1 - c = self.getc() - if c == '\n': - self.pos += 1 - self.atbol() - continue - elif c == '\r': - self.pos += 1 - if self.getc() == '\n': - self.pos += 1 - self.atbol() - elif slash: - raise DoneException - else: - return - else: - return - - def get_name(self): - if self.getc() not in letters: - raise DoneException - p = self.pos - try: - while self.getc() in alphanumerics: - self.pos += 1 - except DoneException: - # If there's any name at all, we want to call self.set_flag(). - # Something else while get the DoneException again. - if self.pos == p: - raise - end = self.pos - else: - end = self.pos - self.consume_whitespace() - return self.s[p:end] - - def get_more(self, paren_list=False): - if paren_list and self.getc() == ')': - self.pos += 1 - return - if (self.getc() == 'a' and - self.getc(+1) == 's' and - self.getc(+2) in whitespace): - self.get_name() - self.get_name() - self.get_more(paren_list=paren_list) - return - elif self.getc() != ',': - return - else: - self.pos += 1 - self.consume_whitespace(paren_list) - if paren_list and self.getc() == ')': - self.pos += 1 - return # Handles trailing comma inside parenthesis - self.set_flag(self.get_name()) - self.get_more(paren_list=paren_list) - - def set_flag(self, feature): - self.got_features += 1 - try: - self.flags |= self.future_flags.compiler_features[feature] - except KeyError: - pass - -from codeop import PyCF_DONT_IMPLY_DEDENT -from pypy.interpreter.error import OperationError - from pypy.tool import stdlib___future__ as future class FutureFlags(object): @@ -328,7 +23,82 @@ flag_names.append(name) return flag_names + def get_compiler_feature(self, name): + return self.compiler_features.get(name, 0) + futureFlags_2_4 = FutureFlags((2, 4, 4, 'final', 0)) futureFlags_2_5 = FutureFlags((2, 5, 0, 'final', 0)) futureFlags_2_7 = FutureFlags((2, 7, 0, 'final', 0)) futureFlags_3_2 = FutureFlags((3, 2, 0, 'final', 0)) + + +class TokenIterator: + def __init__(self, tokens): + self.tokens = tokens + self.index = 0 + self.next() + + def next(self): + index = self.index + self.index = index + 1 + self.tok = self.tokens[index] + + def skip(self, n): + if self.tok[0] == n: + self.next() + return True + else: + return False + + def skip_name(self, name): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME and self.tok[1] == name: + self.next() + return True + else: + return False + + def next_feature_name(self): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME: + name = self.tok[1] + self.next() + if self.skip_name("as"): + self.skip(pygram.tokens.NAME) + return name + else: + return '' + + def skip_newlines(self): + from pypy.interpreter.pyparser import pygram + while self.skip(pygram.tokens.NEWLINE): + pass + + +def add_future_flags(future_flags, tokens): + from pypy.interpreter.pyparser import pygram + it = TokenIterator(tokens) + result = 0 + # + # The only things that can precede a future statement are another + # future statement and a doc string (only one). This is a very + # permissive parsing of the given list of tokens; it relies on + # the real parsing done afterwards to give errors. + it.skip_newlines() + it.skip_name("r") or it.skip_name("u") or it.skip_name("ru") + if it.skip(pygram.tokens.STRING): + it.skip_newlines() + + while (it.skip_name("from") and + it.skip_name("__future__") and + it.skip_name("import")): + it.skip(pygram.tokens.LPAR) # optionally + result |= future_flags.get_compiler_feature(it.next_feature_name()) + while it.skip(pygram.tokens.COMMA): + result |= future_flags.get_compiler_feature(it.next_feature_name()) + it.skip(pygram.tokens.RPAR) # optionally + it.skip(pygram.tokens.SEMI) # optionally + it.skip_newlines() + + position = (it.tok[2], it.tok[3]) + return result, position diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py --- a/pypy/interpreter/pyparser/pyparse.py +++ b/pypy/interpreter/pyparser/pyparse.py @@ -139,14 +139,8 @@ raise error.SyntaxError(space.str_w(w_message)) raise - f_flags, future_info = future.get_futures(self.future_flags, textsrc) - compile_info.last_future_import = future_info - compile_info.flags |= f_flags - flags = compile_info.flags - self.grammar = pygram.python_grammar - # The tokenizer is very picky about how it wants its input. source_lines = textsrc.splitlines(True) if source_lines and not source_lines[-1].endswith("\n"): @@ -158,7 +152,17 @@ tp = 0 try: try: + # Note: we no longer pass the CO_FUTURE_* to the tokenizer, + # which is expected to work independently of them. It's + # certainly the case for all futures in Python <= 2.7. tokens = pytokenizer.generate_tokens(source_lines, flags) + + newflags, last_future_import = ( + future.add_future_flags(self.future_flags, tokens)) + compile_info.last_future_import = last_future_import + compile_info.flags |= newflags + self.grammar = pygram.python_grammar + for tp, value, lineno, column, line in tokens: if self.add_token(tp, value, lineno, column, line): break diff --git a/pypy/interpreter/pyparser/test/test_futureautomaton.py b/pypy/interpreter/pyparser/test/test_future.py rename from pypy/interpreter/pyparser/test/test_futureautomaton.py rename to pypy/interpreter/pyparser/test/test_future.py --- a/pypy/interpreter/pyparser/test/test_futureautomaton.py +++ b/pypy/interpreter/pyparser/test/test_future.py @@ -1,29 +1,26 @@ import py -import pypy.interpreter.pyparser.future as future +from pypy.interpreter.pyparser import future, pytokenizer from pypy.tool import stdlib___future__ as fut -def run(s): - f = future.FutureAutomaton(future.futureFlags_2_7, s) - try: - f.start() - except future.DoneException: - pass - return f +def run(s, expected_last_future=None): + source_lines = s.splitlines(True) + tokens = pytokenizer.generate_tokens(source_lines, 0) + expected_last_future = expected_last_future or tokens[-1][2:4] + # + flags, last_future_import = future.add_future_flags( + future.futureFlags_2_7, tokens) + assert last_future_import == expected_last_future + return flags def test_docstring(): s = '"Docstring\\" "\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_comment(): s = '# A comment about nothing ;\n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_tripledocstring(): s = '''""" This is a @@ -31,9 +28,7 @@ breaks in it. It even has a \n""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_escapedquote_in_tripledocstring(): s = '''""" This is a @@ -41,233 +36,176 @@ breaks in it. \\"""It even has an escaped quote!""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_empty_line(): s = ' \t \f \n \n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_from(): s = 'from __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms(): s = 'from __future__ import division, generators, with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_from_as(): s = 'from __future__ import division as b\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_as(): s = 'from __future__ import division as b, generators as c\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_from_paren(): s = 'from __future__ import (division)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_paren(): s = 'from __future__ import (division, generators)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_froms_paren_as(): s = 'from __future__ import (division as b, generators,)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_paren_with_newline(): s = 'from __future__ import (division,\nabsolute_import)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) + +def test_paren_with_newline_2(): + s = 'from __future__ import (\ndivision,\nabsolute_import)\n' + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) def test_multiline(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,)\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_windows_style_lineendings(): s = '"abc" #def\r\n #ghi\r\nfrom __future__ import (division as b, generators,)\r\nfrom __future__ import with_statement\r\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_mac_style_lineendings(): s = '"abc" #def\r #ghi\rfrom __future__ import (division as b, generators,)\rfrom __future__ import with_statement\r' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_semicolon(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 3 - assert f.col_offset == 55 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) + +def test_semicolon_2(): + s = 'from __future__ import division; from foo import bar' + f = run(s, expected_last_future=(1, 39)) + assert f == fut.CO_FUTURE_DIVISION def test_full_chain(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert pos == (3, 55) + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_intervening_code(): s = 'from __future__ import (division as b, generators,)\nfrom sys import modules\nfrom __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags & fut.CO_FUTURE_WITH_STATEMENT == 0 - assert pos == (1, 0) + f = run(s, expected_last_future=(2, 5)) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_GENERATOR_ALLOWED) def test_nonexisting(): s = 'from __future__ import non_existing_feature\n' f = run(s) - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == 0 + +def test_nonexisting_2(): + s = 'from __future__ import non_existing_feature, with_statement\n' + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_from_import_abs_import(): s = 'from __future__ import absolute_import\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_ABSOLUTE_IMPORT - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_ABSOLUTE_IMPORT def test_raw_doc(): s = 'r"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_unicode_doc(): s = 'u"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_raw_unicode_doc(): s = 'ru"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_line(): s = "\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_lines(): s = "\\\n \t\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 3 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_lots_of_continuation_lines(): s = "\\\n\\\n\\\n\\\n\\\n\\\n\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT -# This looks like a bug in cpython parser -# and would require extensive modifications -# to future.py in order to emulate the same behaviour def test_continuation_lines_raise(): - py.test.skip("probably a CPython bug") s = " \\\n \t\\\nfrom __future__ import with_statement\n" - try: - f = run(s) - except IndentationError, e: - assert e.args == 'unexpected indent' - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == -1 - assert f.col_offset == 0 - else: - raise AssertionError('IndentationError not raised') - assert f.lineno == 2 - assert f.col_offset == 0 + f = run(s, expected_last_future=(1, 0)) + assert f == 0 # because of the INDENT def test_continuation_lines_in_docstring_single_quoted(): s = '"\\\n\\\n\\\n\\\n\\\n\\\n"\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_continuation_lines_in_docstring_triple_quoted(): s = '"""\\\n\\\n\\\n\\\n\\\n\\\n"""\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION + +def test_blank_lines(): + s = ('\n\t\n\nfrom __future__ import with_statement' + ' \n \n \nfrom __future__ import division') + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT | fut.CO_FUTURE_DIVISION + +def test_dummy_semicolons(): + s = ('from __future__ import division;\n' + 'from __future__ import with_statement;') + f = run(s) + assert f == fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_WITH_STATEMENT diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py b/pypy/interpreter/pyparser/test/test_pyparse.py --- a/pypy/interpreter/pyparser/test/test_pyparse.py +++ b/pypy/interpreter/pyparser/test/test_pyparse.py @@ -136,6 +136,9 @@ py.test.raises(SyntaxError, self.parse, '0b0l') py.test.raises(SyntaxError, self.parse, "0b112") + def test_print_function(self): + self.parse("from __future__ import print_function\nx = print\n") + def test_py3k_reject_old_binary_literal(self): py.test.raises(SyntaxError, self.parse, '0777') @@ -195,4 +198,3 @@ exc = py.test.raises(SyntaxError, self.parse, input).value assert exc.msg == ("'ascii' codec can't decode byte 0xc3 " "in position 16: ordinal not in range(128)") - diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -304,6 +304,9 @@ 'from __future__ import nested_scopes, generators', 'from __future__ import (nested_scopes,\ngenerators)', 'from __future__ import (nested_scopes,\ngenerators,)', + 'from __future__ import (\nnested_scopes,\ngenerators)', + 'from __future__ import(\n\tnested_scopes,\n\tgenerators)', + 'from __future__ import(\n\t\nnested_scopes)', 'from sys import stdin, stderr, stdout', 'from sys import (stdin, stderr,\nstdout)', 'from sys import (stdin, stderr,\nstdout,)', diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -274,7 +274,7 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1704,25 +1704,6 @@ T = lltype.Char def _coerce(self, space, arr, ofs, dtype, w_items, shape): - items_w = space.fixedview(w_items) - for i in range(len(items_w)): - subdtype = dtype.subdtype - itemtype = subdtype.itemtype - if space.len_w(shape) <= 1: - w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) - itemtype.store(arr, 0, ofs, w_box) - ofs += itemtype.get_element_size() - else: - size = 1 - for dimension in shape[1:]: - size *= dimension - size *= itemtype.get_element_size() - for w_item in items_w: - self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) - ofs += size - return arr - - def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match items_w = space.fixedview(w_items) subdtype = dtype.subdtype diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,7 +105,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -142,7 +141,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -339,7 +339,6 @@ loop, = log.loops_by_filename(self.filepath) # the int strategy is used here assert loop.match_by_id('append', """ - guard_not_invalidated(descr=...) i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) # Will be killed by the backend @@ -487,7 +486,6 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) - guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -587,6 +585,7 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' + guard_not_invalidated(descr=...) i1 = force_token() ''') 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 @@ -73,6 +73,11 @@ rename_pypy_c += '.exe' binaries = [(pypy_c, rename_pypy_c)] # + builddir = udir.ensure("build", dir=True) + pypydir = builddir.ensure(name, dir=True) + includedir = basedir.join('include') + pypydir.ensure('include', dir=True) + if sys.platform == 'win32': #Don't include a mscvrXX.dll, users should get their own. #Instructions are provided on the website. @@ -85,12 +90,22 @@ p = pypy_c.dirpath().join(extra) if not p.check(): p = py.path.local.sysfind(extra) - assert p, "%s not found" % (extra,) + if not p: + print "%s not found, expect trouble if this is a shared build" % (extra,) + continue print "Picking %s" % p binaries.append((p, p.basename)) - # - builddir = udir.ensure("build", dir=True) - pypydir = builddir.ensure(name, dir=True) + if pypy_c.dirpath().join("libpypy-c.lib").check(): + shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), + str(pypydir.join('include/python27.lib'))) + print "Picking %s as %s" % (pypy_c.dirpath().join("libpypy-c.lib"), + pypydir.join('include/python27.lib')) + else: + pass + # XXX users will complain that they cannot compile cpyext + # modules for windows, has the lib moved or are there no + # exported functions in the dll so no import library is created? + # Careful: to copy lib_pypy, copying just the svn-tracked files # would not be enough: there are also ctypes_config_cache/_*_cache.py. shutil.copytree(str(basedir.join('lib-python').join(STDLIB_VER)), @@ -102,15 +117,10 @@ '*.c', '*.o')) for file in ['LICENSE', 'README.rst']: shutil.copy(str(basedir.join(file)), str(pypydir)) - pypydir.ensure('include', dir=True) - if sys.platform == 'win32': - shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), - str(pypydir.join('include/python27.lib'))) - # we want to put there all *.h and *.inl from trunk/include - # and from pypy/_interfaces - includedir = basedir.join('include') headers = includedir.listdir('*.h') + includedir.listdir('*.inl') for n in headers: + # we want to put there all *.h and *.inl from trunk/include + # and from pypy/_interfaces shutil.copy(str(n), str(pypydir.join('include'))) # spdir = pypydir.ensure('site-packages', dir=True) diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -85,7 +85,7 @@ # exported_state is clear by optimizeopt when the short preamble is # constrcucted. if that did not happen the label should not show up # in a trace that will be used - assert descr.exported_state is None + assert descr.exported_state is None if not we_are_translated(): op._descr_wref = weakref.ref(op._descr) op.cleardescr() # clear reference to prevent the history.Stats @@ -819,7 +819,7 @@ # The history contains new operations to attach as the code for the # failure of 'resumekey.guard_op'. - # + # # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. new_trace = create_empty_loop(metainterp) From noreply at buildbot.pypy.org Sat May 25 09:52:35 2013 From: noreply at buildbot.pypy.org (bivab) Date: Sat, 25 May 2013 09:52:35 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: fix tests Message-ID: <20130525075235.6B9EB1C140A@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64554:ef580c242cfd Date: 2013-05-25 02:48 -0500 http://bitbucket.org/pypy/pypy/changeset/ef580c242cfd/ Log: fix tests diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -102,45 +102,37 @@ val = imm(100) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 100, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_stacklock(self): val = imm(65536) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 65536, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] - + ] self.mov(val, s, expected) def test_mov_imm_to_big_stacklock(self): val = imm(100) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 100, cond=AL), - mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 100, cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_big_stacklock(self): val = imm(65536) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 65536, cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_reg_to_reg(self): @@ -158,10 +150,10 @@ def test_mov_reg_to_big_stackloc(self): s = stack(8191) r6 = r(6) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r6.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r6, s, expected) def test_mov_stack_to_reg(self): @@ -174,10 +166,8 @@ s = stack(8191) r6 = r(6) expected = [ - mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 32940, cond=AL), - mi('LDR_rr', r6.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), + mi('gen_load_int', ip.value, 32940, cond=AL), + mi('LDR_rr', r6.value, fp.value, ip.value, cond=AL), ] self.mov(s, r6, expected) @@ -185,10 +175,9 @@ f = imm_float(3.5) reg = vfp(5) expected = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, f.value, cond=AL), mi('VLDR', 5, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(f, reg, expected) def test_mov_vfp_reg_to_vfp_reg(self): @@ -206,11 +195,11 @@ def test_mov_vfp_reg_to_large_stackloc(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_mov_stack_to_vfp_reg(self): @@ -222,11 +211,11 @@ def test_mov_big_stackloc_to_vfp_reg(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_unsopported_cases(self): @@ -265,8 +254,6 @@ py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), vfp(2))') py.test.raises(AssertionError, - 'self.asm.regalloc_mov(stack(1), lr)') - py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm(2))') py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm_float(2))') @@ -312,12 +299,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('LDR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=WORD, cond=AL), mi('LDR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(s, r1, r2, e) def test_from_imm_float(self): @@ -325,11 +311,10 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, i.value, cond=AL), mi('LDR_ri', r1.value, ip.value, cond=AL), mi('LDR_ri', r2.value, ip.value, imm=4, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(i, r1, r2, e) def test_unsupported(self): @@ -369,12 +354,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=4, cond=AL), mi('STR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r1, r2, s, e) def unsupported(self): @@ -408,10 +392,9 @@ def test_push_imm_float(self): f = imm_float(7) - e = [mi('PUSH', [ip.value], cond=AL), + e = [ mi('gen_load_int', ip.value, 7, cond=AL), mi('VLDR', vfp_ip.value, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL) ] self.push(f, e) @@ -426,10 +409,8 @@ def test_push_big_stack(self): s = stack(1025) e = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('LDR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), mi('PUSH', [ip.value], cond=AL) ] self.push(s, e) @@ -450,11 +431,9 @@ def test_push_large_stackfloat(self): sf = stack_float(100) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, sf.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VLDR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL), ] self.push(sf, e) @@ -486,10 +465,8 @@ s = stack(1200) e = [ mi('POP', [ip.value], cond=AL), - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('STR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL) ] self.pop(s, e) @@ -505,11 +482,10 @@ s = stack_float(1200) e = [ mi('VPOP', [vfp_ip.value], cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.pop(s, e) def test_unsupported(self): From noreply at buildbot.pypy.org Sat May 25 16:25:48 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 25 May 2013 16:25:48 +0200 (CEST) Subject: [pypy-commit] stm default: Add a README.txt Message-ID: <20130525142548.BA54E1C0203@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1:39a48e810e11 Date: 2013-05-25 16:25 +0200 http://bitbucket.org/pypy/stm/changeset/39a48e810e11/ Log: Add a README.txt diff --git a/README.txt b/README.txt new file mode 100644 --- /dev/null +++ b/README.txt @@ -0,0 +1,12 @@ + +STM-GC +====== + +Welcome! + +This is meant to be a general library that can be used in C programs. + +The library interface is in "c3/stmgc.h". + +A demo program can be found in "c3/demo1.c". +It can be built with "make debug-demo1" or "make build-demo1". From noreply at buildbot.pypy.org Sat May 25 16:28:05 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 25 May 2013 16:28:05 +0200 (CEST) Subject: [pypy-commit] stm default: Add a line Message-ID: <20130525142805.BA5921C0203@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r2:01aa0e678a8d Date: 2013-05-25 16:27 +0200 http://bitbucket.org/pypy/stm/changeset/01aa0e678a8d/ Log: Add a line diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -4,7 +4,8 @@ Welcome! -This is meant to be a general library that can be used in C programs. +This is a C library that combines a GC with STM capabilities. +It is meant to be a general library that can be used in C programs. The library interface is in "c3/stmgc.h". From noreply at buildbot.pypy.org Sat May 25 16:36:34 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 25 May 2013 16:36:34 +0200 (CEST) Subject: [pypy-commit] stm default: Add a comment Message-ID: <20130525143634.18B7E1C1464@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r3:c546d6e73be7 Date: 2013-05-25 16:36 +0200 http://bitbucket.org/pypy/stm/changeset/c546d6e73be7/ Log: Add a comment diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -11,3 +11,8 @@ A demo program can be found in "c3/demo1.c". It can be built with "make debug-demo1" or "make build-demo1". + +The plan is to use this C code directly with PyPy, and not write +manually the many calls to the shadow stack and the barrier functions. +But the manual way is possible too, say when writing a small interpreter +directly in C. From noreply at buildbot.pypy.org Sat May 25 17:02:09 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 25 May 2013 17:02:09 +0200 (CEST) Subject: [pypy-commit] stm default: Fix the warnings given by 'make build-demo1'. Message-ID: <20130525150209.990A61C12FE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r4:6333ea8539f3 Date: 2013-05-25 17:02 +0200 http://bitbucket.org/pypy/stm/changeset/6333ea8539f3/ Log: Fix the warnings given by 'make build-demo1'. diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -321,6 +321,7 @@ case K_PRIVATE: W = R; break; case K_PROTECTED: W = LocalizeProtected(d, R); break; case K_PUBLIC: W = LocalizePublic(d, R); break; + default: abort(); } if (W->h_tid & GCFLAG_WRITE_BARRIER) diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -17,6 +17,7 @@ enum protection_class_t stmgc_classify(struct tx_descriptor *d, gcptr obj) { + /* note that this function never returns K_OLD_PRIVATE. */ if (obj->h_revision == stm_local_revision) return K_PRIVATE; if (stmgc_is_young(d, obj)) @@ -25,8 +26,6 @@ return K_PUBLIC; } -#define K_OLD_PRIVATE 7 - static enum protection_class_t dclassify(gcptr obj) { /* for assertions only; moreover this function returns K_PRIVATE @@ -753,6 +752,7 @@ int stmgc_nursery_hiding(int hide) { +#ifdef _GC_DEBUG struct tx_descriptor *d = thread_descriptor; if (hide) { @@ -779,7 +779,7 @@ } } G2L_LOOP_END; - +#endif return 1; } diff --git a/c3/nursery.h b/c3/nursery.h --- a/c3/nursery.h +++ b/c3/nursery.h @@ -29,7 +29,8 @@ struct tx_descriptor; /* from et.h */ -enum protection_class_t { K_PRIVATE, K_PROTECTED, K_PUBLIC }; +enum protection_class_t { K_PRIVATE, K_PROTECTED, K_PUBLIC, + K_OLD_PRIVATE /* <-only for dclassify() */ }; gcptr stmgc_duplicate(gcptr, revision_t); void stmgc_start_transaction(struct tx_descriptor *); diff --git a/c3/stmsync.c b/c3/stmsync.c --- a/c3/stmsync.c +++ b/c3/stmsync.c @@ -110,9 +110,7 @@ /************************************************************/ -/* sync_required is either 0 or (unsigned)-1 */ -#define SYNC_REQUIRED ((unsigned long)-1) -static unsigned long sync_required = 0; +static revision_t sync_required = 0; void stm_perform_transaction(gcptr arg, int (*callback)(gcptr, int)) { /* must save roots around this call */ @@ -267,7 +265,7 @@ which prevents any other thread from running in a transaction. Warning, may block waiting for rwlock_in_transaction while another thread runs a major GC itself! */ - ACCESS_ONCE(sync_required) = SYNC_REQUIRED; + ACCESS_ONCE(sync_required) = 1; stm_stop_sharedlock(); start_exclusivelock(); ACCESS_ONCE(sync_required) = 0; From noreply at buildbot.pypy.org Sat May 25 18:01:25 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 25 May 2013 18:01:25 +0200 (CEST) Subject: [pypy-commit] stm default: Add GCFLAG_OLD. It's very easy to maintain it, and it simplifies things. Message-ID: <20130525160125.541011C1464@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r5:b62e0a5f9940 Date: 2013-05-25 18:01 +0200 http://bitbucket.org/pypy/stm/changeset/b62e0a5f9940/ Log: Add GCFLAG_OLD. It's very easy to maintain it, and it simplifies things. diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -81,7 +81,7 @@ { old_to_young: v &= ~2; - if (UNLIKELY(!stmgc_is_young(d, (gcptr)v))) + if (UNLIKELY(!stmgc_is_young_in(d, (gcptr)v))) { stmgc_public_to_foreign_protected(R); goto retry; @@ -183,7 +183,7 @@ if (v & 2) { v &= ~2; - if (!stmgc_is_young(thread_descriptor, (gcptr)v)) + if (!is_young((gcptr)v)) { stmgc_follow_foreign(R); goto retry; @@ -317,7 +317,7 @@ /* XXX optimize me based on common patterns */ R = HeadOfRevisionChainList(d, P); - switch (stmgc_classify(d, R)) { + switch (stmgc_classify(R)) { case K_PRIVATE: W = R; break; case K_PROTECTED: W = LocalizeProtected(d, R); break; case K_PUBLIC: W = LocalizePublic(d, R); break; @@ -358,8 +358,8 @@ abort();//XXX if (R->h_tid & GCFLAG_NURSERY_MOVED) { - assert(stmgc_is_young(d, R)); - assert(!stmgc_is_young(d, (gcptr)v)); + assert(is_young(R)); + assert(!is_young((gcptr)v)); R = (gcptr)v; goto retry; } @@ -651,6 +651,15 @@ L->h_tid &= ~GCFLAG_PRIVATE_COPY; L->h_revision = new_revision; + if (is_young(L)) + { + item->val = (gcptr)(((revision_t)L) | 2); +#ifdef DUMP_EXTRA + fprintf(stderr, "PUBLIC-TO-PROTECTED:\n"); + /*mark*/ +#endif + } + } G2L_LOOP_END; smp_wmb(); /* a memory barrier: make sure the new L->h_revisions are visible @@ -659,31 +668,19 @@ G2L_LOOP_FORWARD(d->public_to_private, item) { gcptr R = item->addr; - gcptr L = item->val; - revision_t v = (revision_t)L; + revision_t v = (revision_t)item->val; assert(!(R->h_tid & GCFLAG_PRIVATE_COPY)); assert(R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE); assert(!(R->h_tid & GCFLAG_NURSERY_MOVED)); - assert(!stmgc_is_young(d, R)); + assert(!is_young(R)); assert(R->h_revision != localrev); - if (stmgc_is_young(d, L)) - { - v |= 2; #ifdef DUMP_EXTRA - fprintf(stderr, "%p->h_revision = %p (UpdateChainHeads2) " - "<=== PUBLIC-TO-PROTECTED\n", R, (gcptr)v); - /*mark*/ + fprintf(stderr, "%p->h_revision = %p (UpdateChainHeads2)\n", + R, (gcptr)v); + /*mark*/ #endif - } - else - { -#ifdef DUMP_EXTRA - fprintf(stderr, "%p->h_revision = %p (UpdateChainHeads2)\n", R, L); - /*mark*/ -#endif - } ACCESS_ONCE(R->h_revision) = v; if (R->h_tid & GCFLAG_PREBUILT_ORIGINAL) diff --git a/c3/et.h b/c3/et.h --- a/c3/et.h +++ b/c3/et.h @@ -52,6 +52,8 @@ * set again at the next minor collection. * * GCFLAG_NURSERY_MOVED is used temporarily during minor collections. + * + * GCFLAG_OLD is set on old objects. */ #define GCFLAG_PRIVATE_COPY (STM_FIRST_GCFLAG << 0) #define GCFLAG_VISITED (STM_FIRST_GCFLAG << 1) @@ -59,10 +61,12 @@ #define GCFLAG_PREBUILT_ORIGINAL (STM_FIRST_GCFLAG << 3) #define GCFLAG_WRITE_BARRIER (STM_FIRST_GCFLAG << 4) #define GCFLAG_NURSERY_MOVED (STM_FIRST_GCFLAG << 5) +#define GCFLAG_OLD (STM_FIRST_GCFLAG << 6) /* this value must be reflected in PREBUILT_FLAGS in stmgc.h */ #define GCFLAG_PREBUILT (GCFLAG_VISITED | \ - GCFLAG_PREBUILT_ORIGINAL) + GCFLAG_PREBUILT_ORIGINAL | \ + GCFLAG_OLD) #define GC_FLAG_NAMES { "PRIVATE_COPY", \ "VISITED", \ @@ -70,6 +74,7 @@ "PREBUILT_ORIGINAL", \ "WRITE_BARRIER", \ "NURSERY_MOVED", \ + "OLD", \ NULL } /************************************************************/ diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -119,7 +119,7 @@ struct tx_descriptor *d; for (d = tx_head; d; d = d->tx_next) { - if (stmgc_is_young(d, L)) + if (stmgc_is_young_in(d, L)) goto found; } assert(0); /* L is not a young pointer anywhere! */ @@ -396,8 +396,8 @@ G2L_LOOP_FORWARD(d->public_to_private, item) { - assert(stmgc_classify(d, item->addr) == K_PUBLIC); - assert(stmgc_classify(d, item->val) == K_PRIVATE); + assert(stmgc_classify(item->addr) == K_PUBLIC); + assert(stmgc_classify(item->val) == K_PRIVATE); item->addr->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE; } G2L_LOOP_END; @@ -689,7 +689,8 @@ /* ^^^ write this line even if the following segfault */ switch (stm_dbgmem_is_active(obj, 1)) { case 1: - if (thread_descriptor && stmgc_is_young(thread_descriptor, obj)) { + if (thread_descriptor && + stmgc_is_young_in(thread_descriptor, obj)) { if (g2l_contains( &thread_descriptor->young_objects_outside_nursery, obj)) fprintf(stderr, " (young but outside nursery)"); @@ -738,7 +739,7 @@ other thread */ if (!(obj->h_revision & 2) || (thread_descriptor && - stmgc_is_young(thread_descriptor, p))) { + stmgc_is_young_in(thread_descriptor, p))) { gcptrlist_insert(&pending, p); } else { diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -9,18 +9,29 @@ return (d->nursery <= (char*)obj && ((char*)obj) < d->nursery_end); } -int stmgc_is_young(struct tx_descriptor *d, gcptr obj) +int stmgc_is_young_in(struct tx_descriptor *d, gcptr obj) { + /* Check if 'obj' is a young object for 'd'. (So if it's a young + object for another thread, returns False.) */ return is_in_nursery(d, obj) || g2l_contains(&d->young_objects_outside_nursery, obj); } -enum protection_class_t stmgc_classify(struct tx_descriptor *d, gcptr obj) +#ifdef _GC_DEBUG +int is_young(gcptr obj) +{ + int result = (obj->h_tid & GCFLAG_OLD) == 0; + assert(result == stmgc_is_young_in(thread_descriptor, obj)); + return result; +} +#endif + +enum protection_class_t stmgc_classify(gcptr obj) { /* note that this function never returns K_OLD_PRIVATE. */ if (obj->h_revision == stm_local_revision) return K_PRIVATE; - if (stmgc_is_young(d, obj)) + if (is_young(obj)) return K_PROTECTED; else return K_PUBLIC; @@ -42,16 +53,21 @@ G2L_FIND(d->young_objects_outside_nursery, obj, entry, goto not_found); - if (obj->h_tid & GCFLAG_VISITED) + if (obj->h_tid & GCFLAG_OLD) e = private ? K_OLD_PRIVATE : K_PUBLIC; else e = private ? K_PRIVATE : K_PROTECTED; } assert(stm_dbgmem_is_active(obj, 0)); + if (e == K_PRIVATE || e == K_PROTECTED) + assert((obj->h_tid & GCFLAG_OLD) == 0); + else + assert((obj->h_tid & GCFLAG_OLD) == GCFLAG_OLD); return e; not_found: assert(stm_dbgmem_is_active(obj, 1)); + assert(obj->h_tid & GCFLAG_OLD); return private ? K_OLD_PRIVATE : K_PUBLIC; } @@ -91,6 +107,7 @@ gcptr p = stmgcpage_malloc(size); memset(p, 0, size); p->h_revision = stm_local_revision; + p->h_tid = GCFLAG_OLD; return p; } @@ -145,7 +162,8 @@ localobj->h_tid &= ~(GCFLAG_VISITED | GCFLAG_PUBLIC_TO_PRIVATE | GCFLAG_PREBUILT_ORIGINAL | - GCFLAG_WRITE_BARRIER); + GCFLAG_WRITE_BARRIER | + GCFLAG_OLD); localobj->h_tid |= GCFLAG_PRIVATE_COPY; localobj->h_revision = stm_local_revision; return localobj; @@ -243,11 +261,13 @@ assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER)); assert(!(obj->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)); assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)); + assert(!(obj->h_tid & GCFLAG_OLD)); assert(obj->h_revision & 1); /* odd value so far */ size_t size = stmcb_size(obj); gcptr fresh_old_copy = stmgcpage_malloc(size); memcpy(fresh_old_copy, obj, size); + fresh_old_copy->h_tid |= GCFLAG_OLD; obj->h_tid |= GCFLAG_NURSERY_MOVED; obj->h_revision = (revision_t)fresh_old_copy; @@ -274,6 +294,11 @@ struct tx_descriptor *d = thread_descriptor; recdump1(reason, obj); + + /* Note: it's a good idea here to avoid reading any field of 'obj' + before we know it's a young object. This avoids a lot of cache + misses and cache pollution. + */ retry: if (!is_in_nursery(d, obj)) { /* 'obj' is not from the nursery (or 'obj == NULL') */ @@ -289,11 +314,11 @@ goto ignore_and_try_again_with_next; } /* was it already marked? */ - if (obj->h_tid & GCFLAG_VISITED) { + if (obj->h_tid & GCFLAG_OLD) { return; /* yes, and no '*root' to fix, as it doesn't move */ } - /* otherwise, add GCFLAG_VISITED, and continue below */ - obj->h_tid |= GCFLAG_VISITED; + /* otherwise, add GCFLAG_OLD, and continue below */ + obj->h_tid |= GCFLAG_OLD; fresh_old_copy = obj; } else { @@ -336,7 +361,7 @@ previous_obj = NULL; } obj = (gcptr)obj->h_revision; - assert(stmgc_classify(d, obj) != K_PRIVATE); + assert(stmgc_classify(obj) != K_PRIVATE); PATCH_ROOT_WITH(obj); goto retry; } @@ -345,12 +370,13 @@ static gcptr young_object_becomes_old(struct tx_descriptor *d, gcptr obj _REASON(char *reason)) { - assert(stmgc_is_young(d, obj)); + assert(stmgc_is_young_in(d, obj)); assert(!(obj->h_tid & GCFLAG_NURSERY_MOVED)); assert(!(obj->h_tid & GCFLAG_VISITED)); assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER)); assert(!(obj->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)); assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)); + assert(!(obj->h_tid & GCFLAG_OLD)); assert(obj->h_revision & 1); /* odd value so far */ visit_if_young(&obj _REASON(reason)); @@ -544,8 +570,10 @@ if (!is_in_nursery(d, obj)) { if (!g2l_contains(&d->young_objects_outside_nursery, obj) || - (obj->h_tid & GCFLAG_VISITED)) { - /* non-young or visited young objects are kept */ + (obj->h_tid & GCFLAG_OLD)) { + /* non-young or visited young objects are kept (the + first line of this check could be removed, but it is + better this way to avoid cache pollution) */ continue; } } @@ -605,7 +633,7 @@ return; struct tx_descriptor *d = thread_descriptor; - if (!stmgc_is_young(d, obj)) + if (!stmgc_is_young_in(d, obj)) return; /* xxx try to avoid duplicate stubs for the same object */ @@ -635,11 +663,7 @@ G2L_LOOP_FORWARD(d->young_objects_outside_nursery, item) { gcptr obj = item->addr; - if (obj->h_tid & GCFLAG_VISITED) { - /* survives */ - obj->h_tid &= ~GCFLAG_VISITED; - } - else { + if (!(obj->h_tid & GCFLAG_OLD)) { /* dies */ stmgcpage_free(obj); } @@ -670,16 +694,12 @@ /* now all surviving nursery objects have been moved out, and all surviving young-but-outside-the-nursery objects have been flagged - with GCFLAG_VISITED */ + with GCFLAG_OLD */ + finish_public_to_young(d); + if (g2l_any_entry(&d->young_objects_outside_nursery)) free_unvisited_young_objects_outside_nursery(d); - /* now all previously young objects won't be changed any more and are - considered old (this is why we have to do this after - free_unvisited_young_objects_outside_nursery(), which clears - the VISITED flags and clears 'd->young_objects_outside_nursery') */ - finish_public_to_young(d); - teardown_minor_collect(d); /* clear the nursery */ @@ -787,18 +807,121 @@ void stmgc_public_to_foreign_protected(gcptr R) { - abort(); //XXX + abort();//XXX +#if 0 + /* R is a public object, which contains in h_revision a pointer to a + protected object --- but it is protectd by another thread, + i.e. it likely lives in a foreign nursery. We have to copy the + object out ourselves. This is necessary: we can't simply wait + for the other thread to do a minor collection, because it might + be blocked in a system call or whatever. */ + struct tx_descriptor *my_d = thread_descriptor; + + /* repeat the checks in the caller, to avoid passing more than one + argument here */ + revision_t v = ACCESS_ONCE(R->h_revision); + assert(!(v & 1)); /* "is a pointer" */ + if (!(v & 2)) + return; /* changed already, retry */ + + gcptr L = (gcptr)(v & ~2); + + /* We need to look up which thread it belongs to and lock this + thread's minor collection lock. This also prevents several + threads from getting on each other's toes trying to extract + objects from the same nursery */ + struct tx_descriptor *source_d = stm_find_thread_containing_pointer(L); + assert(source_d != my_d); + + spinlock_acquire(source_d->collection_lock); + + /* now that we have the lock, check again that R->h_revision was not + modified in the meantime */ + if (ACCESS_ONCE(R->h_revision) != v) { + spinlock_release(source_d->collection_lock); + return; /* changed already, retry */ + } + + /* debugging support: "activate" the foreign nursery */ + int was_active = stm_dbgmem_is_active(source_d->nursery, 0); + if (!was_active) assert(stmgc_nursery_hiding(0)); + + /* walk to the head of the chain in the foreign nursery */ + while (1) { + ... + + if (!is_in_nursery(d, obj)) { + /* 'obj' is not from the nursery (or 'obj == NULL') */ + if (obj == NULL || !g2l_contains( + &d->young_objects_outside_nursery, obj)) { + return; /* then it's an old object or NULL, nothing to do */ + } + /* it's a young object outside the nursery */ + + /* is it a protected object with a more recent revision? + (this test fails automatically if it's a private object) */ + if (!(obj->h_revision & 1)) { + goto ignore_and_try_again_with_next; + } + /* was it already marked? */ + if (obj->h_tid & GCFLAG_VISITED) { + return; /* yes, and no '*root' to fix, as it doesn't move */ + } + /* otherwise, add GCFLAG_VISITED, and continue below */ + obj->h_tid |= GCFLAG_VISITED; + fresh_old_copy = obj; + } + else { + /* it's a nursery object. Is it: + A. an already-moved nursery object? + B. a protected object with a more recent revision? + C. common case: first visit to an object to copy outside + */ + if (!(obj->h_revision & 1)) { + + if (obj->h_tid & GCFLAG_NURSERY_MOVED) { + /* case A: just fix the ref. */ + PATCH_ROOT_WITH((gcptr)obj->h_revision); + return; + } + else { + /* case B */ + goto ignore_and_try_again_with_next; + } + } + /* case C */ + fresh_old_copy = copy_outside_nursery(d, obj _REASON("visit")); + + /* fix the original reference */ + PATCH_ROOT_WITH(fresh_old_copy); + } + + /* add 'fresh_old_copy' to the list of objects to trace */ + assert(!(fresh_old_copy->h_tid & GCFLAG_WRITE_BARRIER)); + gcptrlist_insert(&d->old_objects_to_trace, fresh_old_copy); + recdump1("MOVED TO", fresh_old_copy); + return; + + ignore_and_try_again_with_next: + if (previous_obj == NULL) { + previous_obj = obj; + } + else { + previous_obj->h_revision = obj->h_revision; /* compress chain */ + previous_obj = NULL; + } + obj = (gcptr)obj->h_revision; + assert(stmgc_classify(d, obj) != K_PRIVATE); + PATCH_ROOT_WITH(obj); + goto retry; + + ...; +#endif } #if 0 void stmgc_follow_foreign(gcptr R) { - /* R is a global old object, which contains in h_revision a pointer - to a global *young* object --- but it is young for another - thread, i.e. it likely lives in a foreign nursery. We have to - copy the object out ourselves. This is necessary: we can't - simply wait for the other thread to do a minor collection, - because it might be blocked in a system call or whatever. */ struct tx_descriptor *d = thread_descriptor; /* repeat the checks in the caller, to avoid passing more than one diff --git a/c3/nursery.h b/c3/nursery.h --- a/c3/nursery.h +++ b/c3/nursery.h @@ -42,9 +42,15 @@ void stmgc_minor_collect_no_abort(void); int stmgc_minor_collect_anything_to_do(struct tx_descriptor *); void stmgc_write_barrier(gcptr); -enum protection_class_t stmgc_classify(struct tx_descriptor *, gcptr); -int stmgc_is_young(struct tx_descriptor *, gcptr); +enum protection_class_t stmgc_classify(gcptr); +int stmgc_is_young_in(struct tx_descriptor *, gcptr); void stmgc_public_to_foreign_protected(gcptr); int stmgc_nursery_hiding(int); +#ifdef _GC_DEBUG +int is_young(gcptr); +#else +# define is_young(o) (((o)->h_tid & GCFLAG_OLD) == 0) #endif + +#endif diff --git a/c3/stmgc.h b/c3/stmgc.h --- a/c3/stmgc.h +++ b/c3/stmgc.h @@ -21,7 +21,7 @@ #define STM_SIZE_OF_USER_TID (sizeof(revision_t) / 2) /* in bytes */ #define STM_FIRST_GCFLAG (1L << (8 * STM_SIZE_OF_USER_TID)) #define STM_USER_TID_MASK (STM_FIRST_GCFLAG - 1) -#define PREBUILT_FLAGS (STM_FIRST_GCFLAG * (2 + 8)) +#define PREBUILT_FLAGS (STM_FIRST_GCFLAG * (2 + 8 + 64)) #define PREBUILT_REVISION 1 diff --git a/c3/stmsync.c b/c3/stmsync.c --- a/c3/stmsync.c +++ b/c3/stmsync.c @@ -104,7 +104,7 @@ { gcptr result = _stm_allocate_object_of_size_old(size); assert(tid == (tid & STM_USER_TID_MASK)); - result->h_tid = tid; + result->h_tid = tid | GCFLAG_OLD; return result; } diff --git a/c3/test/support.py b/c3/test/support.py --- a/c3/test/support.py +++ b/c3/test/support.py @@ -96,6 +96,7 @@ #define GCFLAG_PREBUILT_ORIGINAL ... #define GCFLAG_WRITE_BARRIER ... #define GCFLAG_NURSERY_MOVED ... + #define GCFLAG_OLD ... #define ABRT_MANUAL ... typedef struct { ...; } page_header_t; ''') @@ -372,7 +373,7 @@ def oalloc(size): "Allocate an 'old' object, i.e. outside any nursery" p = lib.stmgcpage_malloc(size) - p.h_tid = GCFLAG_WRITE_BARRIER + p.h_tid = GCFLAG_WRITE_BARRIER | GCFLAG_OLD p.h_revision = lib.get_local_revision() lib.settid(p, 42 + size) return p @@ -382,7 +383,7 @@ def oalloc_refs(nrefs): "Allocate an 'old' object, i.e. outside any nursery, with nrefs pointers" p = lib.stmgcpage_malloc(HDR + WORD * nrefs) - p.h_tid = GCFLAG_WRITE_BARRIER + p.h_tid = GCFLAG_WRITE_BARRIER | GCFLAG_OLD p.h_revision = lib.get_local_revision() lib.settid(p, 421 + nrefs) for i in range(nrefs): diff --git a/c3/test/test_gcpage.py b/c3/test/test_gcpage.py --- a/c3/test/test_gcpage.py +++ b/c3/test/test_gcpage.py @@ -162,6 +162,7 @@ def test_local_copy_from_global_obj(): p1 = oalloc(HDR) + assert p1.h_tid & GCFLAG_OLD assert lib.stm_write_barrier(p1) == p1 make_global(p1) p2n = lib.stm_write_barrier(p1) From noreply at buildbot.pypy.org Sat May 25 19:57:50 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 25 May 2013 19:57:50 +0200 (CEST) Subject: [pypy-commit] stm default: First draft of stealing. Message-ID: <20130525175750.DF3961C140A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r6:118aee6f0236 Date: 2013-05-25 19:57 +0200 http://bitbucket.org/pypy/stm/changeset/118aee6f0236/ Log: First draft of stealing. diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -751,8 +751,9 @@ (long)cur_time); revision_t localrev = stm_local_revision; - stm_local_revision = -(cur_time + 1); - assert(stm_local_revision & 1); + revision_t newrev = -(cur_time + 1); + assert(newrev & 1); + ACCESS_ONCE(stm_local_revision) = newrev; UpdateChainHeads(d, cur_time, localrev); diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -557,9 +557,9 @@ */ thread_descriptor = d; stm_local_revision = *d->local_revision_ref; - assert(stmgc_nursery_hiding(0)); + assert(stmgc_nursery_hiding(d, 0)); stmgc_minor_collect_no_abort(); - assert(stmgc_nursery_hiding(1)); + assert(stmgc_nursery_hiding(d, 1)); } } thread_descriptor = saved; diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -174,7 +174,6 @@ assert(!gcptrlist_size(&d->protected_with_private_copy)); assert(!g2l_any_entry(&d->public_to_private)); assert(!gcptrlist_size(&d->private_old_pointing_to_young)); - assert(!gcptrlist_size(&d->stolen_objects)); d->num_read_objects_known_old = 0; d->num_public_to_protected = gcptrlist_size(&d->public_to_young); } @@ -252,24 +251,20 @@ # define recdump1(msg, obj) /* removed */ #endif -static inline gcptr copy_outside_nursery(struct tx_descriptor *d, gcptr obj - _REASON(char *reason)) +static inline gcptr create_old_object_copy(struct tx_descriptor *d, gcptr obj + _REASON(char *reason)) { - assert(is_in_nursery(d, obj)); assert(!(obj->h_tid & GCFLAG_NURSERY_MOVED)); assert(!(obj->h_tid & GCFLAG_VISITED)); assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER)); assert(!(obj->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)); assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)); assert(!(obj->h_tid & GCFLAG_OLD)); - assert(obj->h_revision & 1); /* odd value so far */ size_t size = stmcb_size(obj); gcptr fresh_old_copy = stmgcpage_malloc(size); memcpy(fresh_old_copy, obj, size); fresh_old_copy->h_tid |= GCFLAG_OLD; - obj->h_tid |= GCFLAG_NURSERY_MOVED; - obj->h_revision = (revision_t)fresh_old_copy; #ifdef DUMP_EXTRA fprintf(stderr, "%s: %p is copied to %p\n", reason, obj, fresh_old_copy); @@ -340,7 +335,9 @@ } } /* case C */ - fresh_old_copy = copy_outside_nursery(d, obj _REASON("visit")); + fresh_old_copy = create_old_object_copy(d, obj _REASON("visit")); + obj->h_tid |= GCFLAG_NURSERY_MOVED; + obj->h_revision = (revision_t)fresh_old_copy; /* fix the original reference */ PATCH_ROOT_WITH(fresh_old_copy); @@ -770,11 +767,9 @@ gcptrlist_insert(&d->private_old_pointing_to_young, obj); } -int stmgc_nursery_hiding(int hide) +int stmgc_nursery_hiding(struct tx_descriptor *d, int hide) { #ifdef _GC_DEBUG - struct tx_descriptor *d = thread_descriptor; - if (hide) { stm_dbgmem_not_used(d->nursery, GC_NURSERY, 1); } @@ -805,10 +800,59 @@ /************************************************************/ +static gcptr extract_from_foreign_nursery(struct tx_descriptor *source_d, + gcptr L) +{ + /* "Stealing": this function follows a chain of protected objects + in the foreign nursery of the thread 'source_d'. It copies the + last one outside the nursery, and return it. */ + gcptr L2, N; + revision_t source_local_rev, v; + + source_local_rev = ACCESS_ONCE(*source_d->local_revision_ref); + v = ACCESS_ONCE(L->h_revision); + + /* check that L is a protected object */ + assert(!(L->h_tid & GCFLAG_OLD)); + assert(v != source_local_rev); + + /* walk to the head of the chain in the foreign nursery + */ + while (!(v & 1)) { /* "is a pointer" */ + L2 = (gcptr)v; + v = ACCESS_ONCE(L2->h_revision); + if (v == source_local_rev) { + /* L->h_revision is a pointer, but the target is a private + object. We ignore private objects, so we stay at L; but + have to fetch L's real revision off-line from the extra + word that follows L2 */ + size_t size = stmcb_size(L2); + v = *(revision_t *)(((char*)L2) + size); + assert(v & 1); /* "is not a pointer" */ + break; + } + else if (L2->h_tid & GCFLAG_OLD) { + /* we find a public object again: easy case, just return it */ + return L2; + } + else { + /* the chain continues with another protected object, go on */ + L = L2; + } + } + + /* L is now the protected object to move outside, with revision v. */ + N = create_old_object_copy(source_d, L _REASON("stolen copy")); + N->h_revision = v; + gcptrlist_insert2(&source_d->stolen_objects, L, N); + + smp_wmb(); + + return N; +} + void stmgc_public_to_foreign_protected(gcptr R) { - abort();//XXX -#if 0 /* R is a public object, which contains in h_revision a pointer to a protected object --- but it is protectd by another thread, i.e. it likely lives in a foreign nursery. We have to copy the @@ -836,155 +880,21 @@ spinlock_acquire(source_d->collection_lock); /* now that we have the lock, check again that R->h_revision was not - modified in the meantime */ - if (ACCESS_ONCE(R->h_revision) != v) { - spinlock_release(source_d->collection_lock); - return; /* changed already, retry */ + modified in the meantime. If it did change, we do nothing and will + retry. + */ + if (R->h_revision == v) { + /* debugging support: "activate" the foreign nursery */ + int was_active = stm_dbgmem_is_active(source_d->nursery, 0); + if (!was_active) assert(stmgc_nursery_hiding(source_d, 0)); + + gcptr N = extract_from_foreign_nursery(source_d, L); + ACCESS_ONCE(R->h_revision) = (revision_t)N; + fprintf(stderr, "STEALING: %p->h_revision changed from %p to %p\n", + R, L, N); + + /* debugging support: "deactivate" the foreign nursery again */ + if (!was_active) assert(stmgc_nursery_hiding(source_d, 1)); } - - /* debugging support: "activate" the foreign nursery */ - int was_active = stm_dbgmem_is_active(source_d->nursery, 0); - if (!was_active) assert(stmgc_nursery_hiding(0)); - - /* walk to the head of the chain in the foreign nursery */ - while (1) { - ... - - if (!is_in_nursery(d, obj)) { - /* 'obj' is not from the nursery (or 'obj == NULL') */ - if (obj == NULL || !g2l_contains( - &d->young_objects_outside_nursery, obj)) { - return; /* then it's an old object or NULL, nothing to do */ - } - /* it's a young object outside the nursery */ - - /* is it a protected object with a more recent revision? - (this test fails automatically if it's a private object) */ - if (!(obj->h_revision & 1)) { - goto ignore_and_try_again_with_next; - } - /* was it already marked? */ - if (obj->h_tid & GCFLAG_VISITED) { - return; /* yes, and no '*root' to fix, as it doesn't move */ - } - /* otherwise, add GCFLAG_VISITED, and continue below */ - obj->h_tid |= GCFLAG_VISITED; - fresh_old_copy = obj; - } - else { - /* it's a nursery object. Is it: - A. an already-moved nursery object? - B. a protected object with a more recent revision? - C. common case: first visit to an object to copy outside - */ - if (!(obj->h_revision & 1)) { - - if (obj->h_tid & GCFLAG_NURSERY_MOVED) { - /* case A: just fix the ref. */ - PATCH_ROOT_WITH((gcptr)obj->h_revision); - return; - } - else { - /* case B */ - goto ignore_and_try_again_with_next; - } - } - /* case C */ - fresh_old_copy = copy_outside_nursery(d, obj _REASON("visit")); - - /* fix the original reference */ - PATCH_ROOT_WITH(fresh_old_copy); - } - - /* add 'fresh_old_copy' to the list of objects to trace */ - assert(!(fresh_old_copy->h_tid & GCFLAG_WRITE_BARRIER)); - gcptrlist_insert(&d->old_objects_to_trace, fresh_old_copy); - recdump1("MOVED TO", fresh_old_copy); - return; - - ignore_and_try_again_with_next: - if (previous_obj == NULL) { - previous_obj = obj; - } - else { - previous_obj->h_revision = obj->h_revision; /* compress chain */ - previous_obj = NULL; - } - obj = (gcptr)obj->h_revision; - assert(stmgc_classify(d, obj) != K_PRIVATE); - PATCH_ROOT_WITH(obj); - goto retry; - - ...; -#endif + spinlock_release(source_d->collection_lock); } - -#if 0 -void stmgc_follow_foreign(gcptr R) -{ - struct tx_descriptor *d = thread_descriptor; - - /* repeat the checks in the caller, to avoid passing more than one - argument here */ - revision_t v = ACCESS_ONCE(R->h_revision); - assert(!(v & 1)); /* "is a pointer" */ - if (!(v & 2)) - return; /* changed already, retry */ - - gcptr L = (gcptr)(v & ~2); - - /* We need to look up which thread it belongs to and lock this - thread's minor collection lock. This also prevents several - threads from getting on each other's toes trying to extract - objects from the same nursery */ - struct tx_descriptor *source_d = stm_find_thread_containing_pointer(L); - - setup_minor_collect(source_d, 0); - - /* check again that R->h_revision was not modified in the meantime */ - if (ACCESS_ONCE(R->h_revision) != v) { - teardown_minor_collect(source_d); - return; /* changed already, retry */ - } - - /* temporarily take the identity of the other thread to run a very - partial minor collection */ - thread_descriptor = source_d; - assert(stmgc_is_young(source_d, L)); - - /* debugging support */ - int was_active = stm_dbgmem_is_active(source_d->nursery, 0); - if (!was_active) assert(stmgc_nursery_hiding(0)); - - /* force the object L out of the nursery, and follow references */ - - /*XXX <<>>*/ - /*XXX <<>>*/ - /*XXX <<>>*/ - - gcptr L2 = L; - assert(L->h_revision != *source_d->local_revision_ref); - visit_nursery(&L2 _REASON("FORCE OUT FROM OTHER THREAD")); - assert(!is_in_nursery(source_d, L2)); - if (L2 != L) - assert(L->h_tid & GCFLAG_NURSERY_MOVED); - else - assert(L->h_tid & GCFLAG_VISITED); - - visit_all_outside_objects(source_d); - - mark_visited_young_objects_outside_nursery_as_old(source_d); - - /* debugging support */ - if (!was_active) assert(stmgc_nursery_hiding(0)); - - teardown_minor_collect(source_d); - /* the smp_wmb() done above forces all writes from above to be - committed; then afterward we fix the field R->h_revision, making - it a pointer to the now-old object */ - R->h_revision = (revision_t)L2; - - /* done taking the identity of the other thread, take mine again */ - thread_descriptor = d; -} -#endif diff --git a/c3/nursery.h b/c3/nursery.h --- a/c3/nursery.h +++ b/c3/nursery.h @@ -45,7 +45,7 @@ enum protection_class_t stmgc_classify(gcptr); int stmgc_is_young_in(struct tx_descriptor *, gcptr); void stmgc_public_to_foreign_protected(gcptr); -int stmgc_nursery_hiding(int); +int stmgc_nursery_hiding(struct tx_descriptor *, int); #ifdef _GC_DEBUG int is_young(gcptr); diff --git a/c3/stmsync.c b/c3/stmsync.c --- a/c3/stmsync.c +++ b/c3/stmsync.c @@ -236,12 +236,12 @@ { int err = pthread_rwlock_rdlock(&rwlock_shared); assert(err == 0); - assert(stmgc_nursery_hiding(0)); + assert(stmgc_nursery_hiding(thread_descriptor, 0)); } void stm_stop_sharedlock(void) { - assert(stmgc_nursery_hiding(1)); + assert(stmgc_nursery_hiding(thread_descriptor, 1)); int err = pthread_rwlock_unlock(&rwlock_shared); assert(err == 0); } From noreply at buildbot.pypy.org Sat May 25 20:00:17 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 25 May 2013 20:00:17 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: roll back this change, it doesn't totally make sense (and didn't work anyways) Message-ID: <20130525180017.D90451C140A@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64555:3e28a59b15c5 Date: 2013-05-25 13:54 -0400 http://bitbucket.org/pypy/pypy/changeset/3e28a59b15c5/ Log: roll back this change, it doesn't totally make sense (and didn't work anyways) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -25,36 +25,13 @@ if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) - return getframe_unroll(space, depth) + return getframe(space, depth) @jit.look_inside_iff(lambda space, depth: jit.isconstant(depth)) -def getframe_unroll(space, depth): +def getframe(space, depth): ec = space.getexecutioncontext() f = ec.gettopframe_nohidden() - while jit.isvirtual(f): - if f is None: - raise OperationError(space.w_ValueError, - space.wrap("call stack is not deep enough")) - if depth == 0: - f.mark_as_escaped() - return space.wrap(f) - depth -= 1 - f = ec.getnextframe_nohidden(f) - - if f is None: - raise OperationError(space.w_ValueError, - space.wrap("call stack is not deep enough")) - if depth == 0: - f.mark_as_escaped() - return space.wrap(f) - depth -= 1 - f = ec.getnextframe_nohidden(f) - - return getframe_fallback(space, ec, depth, f) - - -def getframe_fallback(space, ec, depth, f): while True: if f is None: raise OperationError(space.w_ValueError, From noreply at buildbot.pypy.org Sat May 25 20:00:19 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 25 May 2013 20:00:19 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: Backported 5629bf4c6bba from CPython. Message-ID: <20130525180019.5179D1C140A@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64556:9de7b40c586f Date: 2013-05-25 13:59 -0400 http://bitbucket.org/pypy/pypy/changeset/9de7b40c586f/ Log: Backported 5629bf4c6bba from CPython. diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py --- a/lib-python/2.7/logging/__init__.py +++ b/lib-python/2.7/logging/__init__.py @@ -134,20 +134,22 @@ DEBUG = 10 NOTSET = 0 -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO : 'INFO', - DEBUG : 'DEBUG', - NOTSET : 'NOTSET', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARNING, - 'WARNING' : WARNING, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'NOTSET' : NOTSET, +_levelToName = { + CRITICAL: 'CRITICAL', + ERROR: 'ERROR', + WARNING: 'WARNING', + INFO: 'INFO', + DEBUG: 'DEBUG', + NOTSET: 'NOTSET', +} +_nameToLevel = { + 'CRITICAL': CRITICAL, + 'ERROR': ERROR, + 'WARN': WARNING, + 'WARNING': WARNING, + 'INFO': INFO, + 'DEBUG': DEBUG, + 'NOTSET': NOTSET, } def getLevelName(level): @@ -164,7 +166,7 @@ Otherwise, the string "Level %s" % level is returned. """ - return _levelNames.get(level, ("Level %s" % level)) + return _levelToName.get(level, ("Level %s" % level)) def addLevelName(level, levelName): """ @@ -174,8 +176,8 @@ """ _acquireLock() try: #unlikely to cause an exception, but you never know... - _levelNames[level] = levelName - _levelNames[levelName] = level + _levelToName[level] = levelName + _nameToLevel[levelName] = level finally: _releaseLock() @@ -183,9 +185,9 @@ if isinstance(level, int): rv = level elif str(level) == level: - if level not in _levelNames: + if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) - rv = _levelNames[level] + rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv diff --git a/lib-python/2.7/logging/config.py b/lib-python/2.7/logging/config.py --- a/lib-python/2.7/logging/config.py +++ b/lib-python/2.7/logging/config.py @@ -156,7 +156,7 @@ h = klass(*args) if "level" in opts: level = cp.get(sectname, "level") - h.setLevel(logging._levelNames[level]) + h.setLevel(level) if len(fmt): h.setFormatter(formatters[fmt]) if issubclass(klass, logging.handlers.MemoryHandler): @@ -187,7 +187,7 @@ opts = cp.options(sectname) if "level" in opts: level = cp.get(sectname, "level") - log.setLevel(logging._levelNames[level]) + log.setLevel(level) for h in root.handlers[:]: root.removeHandler(h) hlist = cp.get(sectname, "handlers") @@ -237,7 +237,7 @@ existing.remove(qn) if "level" in opts: level = cp.get(sectname, "level") - logger.setLevel(logging._levelNames[level]) + logger.setLevel(level) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate diff --git a/lib-python/2.7/test/test_logging.py b/lib-python/2.7/test/test_logging.py --- a/lib-python/2.7/test/test_logging.py +++ b/lib-python/2.7/test/test_logging.py @@ -65,7 +65,8 @@ self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] self.saved_loggers = logger_dict.copy() - self.saved_level_names = logging._levelNames.copy() + self.saved_name_to_level = logging._nameToLevel.copy() + self.saved_level_to_name = logging._levelToName.copy() finally: logging._releaseLock() @@ -97,8 +98,10 @@ self.root_logger.setLevel(self.original_logging_level) logging._acquireLock() try: - logging._levelNames.clear() - logging._levelNames.update(self.saved_level_names) + logging._levelToName.clear() + logging._levelToName.update(self.saved_level_to_name) + logging._nameToLevel.clear() + logging._nameToLevel.update(self.saved_name_to_level) logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list From noreply at buildbot.pypy.org Sat May 25 20:00:21 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sat, 25 May 2013 20:00:21 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged default in Message-ID: <20130525180021.5A6FE1C140A@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64557:691d6ceddaed Date: 2013-05-25 13:59 -0400 http://bitbucket.org/pypy/pypy/changeset/691d6ceddaed/ Log: merged default in 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,5 +4,5 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "0.6" -__version_info__ = (0, 6) +__version__ = "0.7" +__version_info__ = (0, 7) 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 @@ -73,15 +73,15 @@ if name.startswith('RTLD_'): setattr(self, name, getattr(backend, name)) # - BVoidP = self._get_cached_btype(model.voidp_type) + self.BVoidP = self._get_cached_btype(model.voidp_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(BVoidP, 0) + FFI.NULL = self.cast(self.BVoidP, 0) FFI.CData, FFI.CType = backend._get_types() else: # ctypes backend: attach these constants to the instance - self.NULL = self.cast(BVoidP, 0) + self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() def cdef(self, csource, override=False): @@ -346,6 +346,12 @@ self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.append(']') + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + def _make_ffi_library(ffi, libname, flags): import os @@ -372,8 +378,8 @@ BType = ffi._get_cached_btype(tp) try: value = backendlib.load_function(BType, name) - except KeyError: - raise AttributeError(name) + except KeyError as e: + raise AttributeError('%s: %s' % (name, e)) library.__dict__[name] = value return # diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -16,6 +16,7 @@ class CTypesData(object): __metaclass__ = CTypesType __slots__ = ['__weakref__'] + __name__ = '' def __init__(self, *args): raise TypeError("cannot instantiate %r" % (self.__class__,)) @@ -491,6 +492,8 @@ elif BItem in (getbtype(model.PrimitiveType('signed char')), getbtype(model.PrimitiveType('unsigned char'))): kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' else: kind = 'generic' # @@ -546,13 +549,13 @@ def __setitem__(self, index, value): self._as_ctype_ptr[index] = BItem._to_ctypes(value) - if kind == 'charp': + if kind == 'charp' or kind == 'voidp': @classmethod - def _arg_to_ctypes(cls, value): - if isinstance(value, bytes): - return ctypes.c_char_p(value) + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) else: - return super(CTypesPtr, cls)._arg_to_ctypes(value) + return super(CTypesPtr, cls)._arg_to_ctypes(*value) if kind == 'charp' or kind == 'bytep': def _to_string(self, maxlen): diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -15,6 +15,20 @@ def patch_extension_kwds(self, kwds): pass + def find_module(self, module_name, path, so_suffix): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] != so_suffix: + return None + return filename + def collect_types(self): self._typesdict = {} self._generate("collecttype") @@ -427,9 +441,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -1,4 +1,4 @@ -import sys +import sys, os import types from . import model, ffiplatform @@ -20,6 +20,16 @@ # up in kwds['export_symbols']. kwds.setdefault('export_symbols', self.export_symbols) + def find_module(self, module_name, path, so_suffix): + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + return None + def collect_types(self): pass # not needed in the generic engine @@ -216,9 +226,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -102,21 +102,10 @@ path = pkg.__path__ else: path = None - try: - f, filename, descr = imp.find_module(self.get_module_name(), - path) - except ImportError: + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffix()) + if filename is None: return - if f is not None: - f.close() - if filename.lower().endswith('.py'): - # on PyPy, if there are both .py and .pypy-19.so files in - # the same directory, the .py file is returned. That's the - # case after a setuptools installation. We never want to - # load the .py file here... - filename = filename[:-3] + _get_so_suffix() - if not os.path.isfile(filename): - return self.modulefilename = filename self._vengine.collect_types() self._has_module = True diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -65,7 +65,8 @@ del working_modules["termios"] del working_modules["_minimal_curses"] - del working_modules["cppyy"] # not tested on win32 + if "cppyy" in working_modules: + del working_modules["cppyy"] # not tested on win32 # The _locale module is needed by site.py on Windows default_modules["_locale"] = None @@ -78,7 +79,8 @@ del working_modules["_minimal_curses"] del working_modules["termios"] del working_modules["_multiprocessing"] # depends on rctime - del working_modules["cppyy"] # depends on ctypes + if "cppyy" in working_modules: + del working_modules["cppyy"] # depends on ctypes module_dependencies = { diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -163,6 +163,9 @@ $ genreflex MyClass.h $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex +Next, make sure that the library can be found through the dynamic lookup path +(the ``LD_LIBRARY_PATH`` environment variable on Linux, ``PATH`` on Windows), +for example by adding ".". Now you're ready to use the bindings. Since the bindings are designed to look pythonistic, it should be straightforward:: diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,14 +124,21 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - if space.config.objspace.usemodules.thread: - os_thread.setup_threads(space) - rffi.aroundstate.before() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - if space.config.objspace.usemodules.thread: - rthread.gc_thread_start() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + os_thread.bootstrapper.acquire(space, None, None) + rthread.gc_thread_start() + os_thread.bootstrapper.nbthreads += 1 + os_thread.bootstrapper.release() + rffi.aroundstate.before() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), diff --git a/pypy/interpreter/pyparser/future.py b/pypy/interpreter/pyparser/future.py --- a/pypy/interpreter/pyparser/future.py +++ b/pypy/interpreter/pyparser/future.py @@ -1,307 +1,3 @@ -""" -This automaton is designed to be invoked on a Python source string -before the real parser starts working, in order to find all legal -'from __future__ import blah'. As soon as something is encountered that -would prevent more future imports, the analysis is aborted. -The resulting legal futures are avaliable in self.flags after the -pass has ended. - -Invocation is through get_futures(src), which returns a field of flags, one per -found correct future import. - -The flags can then be used to set up the parser. -All error detection is left to the parser. - -The reason we are not using the regular lexer/parser toolchain is that -we do not want the overhead of generating tokens for entire files just -to find information that resides in the first few lines of the file. -Neither do we require sane error messages, as this job is handled by -the parser. - -To make the parsing fast, especially when the module is translated to C, -the code has been written in a very serial fashion, using an almost -assembler like style. A further speedup could be achieved by replacing -the "in" comparisons with explicit numeric comparisons. -""" - -from pypy.interpreter.astcompiler.consts import CO_GENERATOR_ALLOWED, \ - CO_FUTURE_DIVISION, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_ABSOLUTE_IMPORT - -def get_futures(future_flags, source): - futures = FutureAutomaton(future_flags, source) - try: - futures.start() - except DoneException, e: - pass - return futures.flags, (futures.lineno, futures.col_offset) - -class DoneException(Exception): - pass - -whitespace = ' \t\f' -whitespace_or_newline = whitespace + '\n\r' -letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz_' -alphanumerics = letters + '1234567890' - -class FutureAutomaton(object): - """ - A future statement must appear near the top of the module. - The only lines that can appear before a future statement are: - - * the module docstring (if any), - * comments, - * blank lines, and - * other future statements. - - The features recognized by Python 2.5 are "generators", - "division", "nested_scopes" and "with_statement", "absolute_import". - "generators", "division" and "nested_scopes" are redundant - in 2.5 because they are always enabled. - - This module parses the input until it encounters something that is - not recognized as a valid future statement or something that may - precede a future statement. - """ - - def __init__(self, future_flags, string): - self.future_flags = future_flags - self.s = string - self.pos = 0 - self.current_lineno = 1 - self.lineno = -1 - self.line_start_pos = 0 - self.col_offset = 0 - self.docstring_consumed = False - self.flags = 0 - self.got_features = 0 - - def getc(self, offset=0): - try: - return self.s[self.pos + offset] - except IndexError: - raise DoneException - - def start(self): - c = self.getc() - if c in ("'", '"', "r", "u") and not self.docstring_consumed: - self.consume_docstring() - elif c == '\\' or c in whitespace_or_newline: - self.consume_empty_line() - elif c == '#': - self.consume_comment() - elif c == 'f': - self.consume_from() - else: - return - - def atbol(self): - self.current_lineno += 1 - self.line_start_pos = self.pos - - def consume_docstring(self): - self.docstring_consumed = True - if self.getc() == "r": - self.pos += 1 - if self.getc() == "u": - self.pos += 1 - endchar = self.getc() - if (self.getc() == self.getc(+1) and - self.getc() == self.getc(+2)): - self.pos += 3 - while 1: # Deal with a triple quoted docstring - c = self.getc() - if c == '\\': - self.pos += 1 - self._skip_next_char_from_docstring() - elif c != endchar: - self._skip_next_char_from_docstring() - else: - self.pos += 1 - if (self.getc() == endchar and - self.getc(+1) == endchar): - self.pos += 2 - self.consume_empty_line() - break - - else: # Deal with a single quoted docstring - self.pos += 1 - while 1: - c = self.getc() - self.pos += 1 - if c == endchar: - self.consume_empty_line() - return - elif c == '\\': - self._skip_next_char_from_docstring() - elif c in '\r\n': - # Syntax error - return - - def _skip_next_char_from_docstring(self): - c = self.getc() - self.pos += 1 - if c == '\n': - self.atbol() - elif c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - - def consume_continuation(self): - c = self.getc() - if c in '\n\r': - self.pos += 1 - self.atbol() - - def consume_empty_line(self): - """ - Called when the remainder of the line can only contain whitespace - and comments. - """ - while self.getc() in whitespace: - self.pos += 1 - if self.getc() == '#': - self.consume_comment() - elif self.getc() == ';': - self.pos += 1 - self.consume_whitespace() - self.start() - elif self.getc() in '\\': - self.pos += 1 - self.consume_continuation() - self.start() - elif self.getc() in '\r\n': - c = self.getc() - self.pos += 1 - if c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - else: - self.atbol() - self.start() - - def consume_comment(self): - self.pos += 1 - while self.getc() not in '\r\n': - self.pos += 1 - self.consume_empty_line() - - def consume_from(self): - col_offset = self.pos - self.line_start_pos - line = self.current_lineno - self.pos += 1 - if self.getc() == 'r' and self.getc(+1) == 'o' and self.getc(+2) == 'm': - self.docstring_consumed = True - self.pos += 3 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+10] != '__future__': - raise DoneException - self.pos += 10 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+6] != 'import': - raise DoneException - self.pos += 6 - self.consume_whitespace() - old_got = self.got_features - try: - if self.getc() == '(': - self.pos += 1 - self.consume_whitespace() - self.set_flag(self.get_name()) - # Set flag corresponding to name - self.get_more(paren_list=True) - else: - self.set_flag(self.get_name()) - self.get_more() - finally: - if self.got_features > old_got: - self.col_offset = col_offset - self.lineno = line - self.consume_empty_line() - - def consume_mandatory_whitespace(self): - if self.getc() not in whitespace + '\\': - raise DoneException - self.consume_whitespace() - - def consume_whitespace(self, newline_ok=False): - while 1: - c = self.getc() - if c in whitespace: - self.pos += 1 - continue - elif c == '\\' or newline_ok: - slash = c == '\\' - if slash: - self.pos += 1 - c = self.getc() - if c == '\n': - self.pos += 1 - self.atbol() - continue - elif c == '\r': - self.pos += 1 - if self.getc() == '\n': - self.pos += 1 - self.atbol() - elif slash: - raise DoneException - else: - return - else: - return - - def get_name(self): - if self.getc() not in letters: - raise DoneException - p = self.pos - try: - while self.getc() in alphanumerics: - self.pos += 1 - except DoneException: - # If there's any name at all, we want to call self.set_flag(). - # Something else while get the DoneException again. - if self.pos == p: - raise - end = self.pos - else: - end = self.pos - self.consume_whitespace() - return self.s[p:end] - - def get_more(self, paren_list=False): - if paren_list and self.getc() == ')': - self.pos += 1 - return - if (self.getc() == 'a' and - self.getc(+1) == 's' and - self.getc(+2) in whitespace): - self.get_name() - self.get_name() - self.get_more(paren_list=paren_list) - return - elif self.getc() != ',': - return - else: - self.pos += 1 - self.consume_whitespace(paren_list) - if paren_list and self.getc() == ')': - self.pos += 1 - return # Handles trailing comma inside parenthesis - self.set_flag(self.get_name()) - self.get_more(paren_list=paren_list) - - def set_flag(self, feature): - self.got_features += 1 - try: - self.flags |= self.future_flags.compiler_features[feature] - except KeyError: - pass - -from codeop import PyCF_DONT_IMPLY_DEDENT -from pypy.interpreter.error import OperationError - from pypy.tool import stdlib___future__ as future class FutureFlags(object): @@ -327,6 +23,81 @@ flag_names.append(name) return flag_names + def get_compiler_feature(self, name): + return self.compiler_features.get(name, 0) + futureFlags_2_4 = FutureFlags((2, 4, 4, 'final', 0)) futureFlags_2_5 = FutureFlags((2, 5, 0, 'final', 0)) futureFlags_2_7 = FutureFlags((2, 7, 0, 'final', 0)) + + +class TokenIterator: + def __init__(self, tokens): + self.tokens = tokens + self.index = 0 + self.next() + + def next(self): + index = self.index + self.index = index + 1 + self.tok = self.tokens[index] + + def skip(self, n): + if self.tok[0] == n: + self.next() + return True + else: + return False + + def skip_name(self, name): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME and self.tok[1] == name: + self.next() + return True + else: + return False + + def next_feature_name(self): + from pypy.interpreter.pyparser import pygram + if self.tok[0] == pygram.tokens.NAME: + name = self.tok[1] + self.next() + if self.skip_name("as"): + self.skip(pygram.tokens.NAME) + return name + else: + return '' + + def skip_newlines(self): + from pypy.interpreter.pyparser import pygram + while self.skip(pygram.tokens.NEWLINE): + pass + + +def add_future_flags(future_flags, tokens): + from pypy.interpreter.pyparser import pygram + it = TokenIterator(tokens) + result = 0 + # + # The only things that can precede a future statement are another + # future statement and a doc string (only one). This is a very + # permissive parsing of the given list of tokens; it relies on + # the real parsing done afterwards to give errors. + it.skip_newlines() + it.skip_name("r") or it.skip_name("u") or it.skip_name("ru") + if it.skip(pygram.tokens.STRING): + it.skip_newlines() + + while (it.skip_name("from") and + it.skip_name("__future__") and + it.skip_name("import")): + it.skip(pygram.tokens.LPAR) # optionally + result |= future_flags.get_compiler_feature(it.next_feature_name()) + while it.skip(pygram.tokens.COMMA): + result |= future_flags.get_compiler_feature(it.next_feature_name()) + it.skip(pygram.tokens.RPAR) # optionally + it.skip(pygram.tokens.SEMI) # optionally + it.skip_newlines() + + position = (it.tok[2], it.tok[3]) + return result, position diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py --- a/pypy/interpreter/pyparser/pyparse.py +++ b/pypy/interpreter/pyparser/pyparse.py @@ -135,17 +135,8 @@ raise error.SyntaxError(space.str_w(w_message)) raise - f_flags, future_info = future.get_futures(self.future_flags, textsrc) - compile_info.last_future_import = future_info - compile_info.flags |= f_flags - flags = compile_info.flags - if flags & consts.CO_FUTURE_PRINT_FUNCTION: - self.grammar = pygram.python_grammar_no_print - else: - self.grammar = pygram.python_grammar - # The tokenizer is very picky about how it wants its input. source_lines = textsrc.splitlines(True) if source_lines and not source_lines[-1].endswith("\n"): @@ -157,7 +148,21 @@ tp = 0 try: try: + # Note: we no longer pass the CO_FUTURE_* to the tokenizer, + # which is expected to work independently of them. It's + # certainly the case for all futures in Python <= 2.7. tokens = pytokenizer.generate_tokens(source_lines, flags) + + newflags, last_future_import = ( + future.add_future_flags(self.future_flags, tokens)) + compile_info.last_future_import = last_future_import + compile_info.flags |= newflags + + if compile_info.flags & consts.CO_FUTURE_PRINT_FUNCTION: + self.grammar = pygram.python_grammar_no_print + else: + self.grammar = pygram.python_grammar + for tp, value, lineno, column, line in tokens: if self.add_token(tp, value, lineno, column, line): break diff --git a/pypy/interpreter/pyparser/test/test_futureautomaton.py b/pypy/interpreter/pyparser/test/test_future.py rename from pypy/interpreter/pyparser/test/test_futureautomaton.py rename to pypy/interpreter/pyparser/test/test_future.py --- a/pypy/interpreter/pyparser/test/test_futureautomaton.py +++ b/pypy/interpreter/pyparser/test/test_future.py @@ -1,29 +1,26 @@ import py -import pypy.interpreter.pyparser.future as future +from pypy.interpreter.pyparser import future, pytokenizer from pypy.tool import stdlib___future__ as fut -def run(s): - f = future.FutureAutomaton(future.futureFlags_2_7, s) - try: - f.start() - except future.DoneException: - pass - return f +def run(s, expected_last_future=None): + source_lines = s.splitlines(True) + tokens = pytokenizer.generate_tokens(source_lines, 0) + expected_last_future = expected_last_future or tokens[-1][2:4] + # + flags, last_future_import = future.add_future_flags( + future.futureFlags_2_7, tokens) + assert last_future_import == expected_last_future + return flags def test_docstring(): s = '"Docstring\\" "\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_comment(): s = '# A comment about nothing ;\n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_tripledocstring(): s = '''""" This is a @@ -31,9 +28,7 @@ breaks in it. It even has a \n""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_escapedquote_in_tripledocstring(): s = '''""" This is a @@ -41,233 +36,176 @@ breaks in it. \\"""It even has an escaped quote!""" ''' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_empty_line(): s = ' \t \f \n \n' f = run(s) - assert f.pos == len(s) - assert f.lineno == -1 - assert f.col_offset == 0 + assert f == 0 def test_from(): s = 'from __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms(): s = 'from __future__ import division, generators, with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_from_as(): s = 'from __future__ import division as b\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_as(): s = 'from __future__ import division as b, generators as c\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_from_paren(): s = 'from __future__ import (division)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_froms_paren(): s = 'from __future__ import (division, generators)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_froms_paren_as(): s = 'from __future__ import (division as b, generators,)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED) def test_paren_with_newline(): s = 'from __future__ import (division,\nabsolute_import)\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) + +def test_paren_with_newline_2(): + s = 'from __future__ import (\ndivision,\nabsolute_import)\n' + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_ABSOLUTE_IMPORT) def test_multiline(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,)\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_windows_style_lineendings(): s = '"abc" #def\r\n #ghi\r\nfrom __future__ import (division as b, generators,)\r\nfrom __future__ import with_statement\r\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_mac_style_lineendings(): s = '"abc" #def\r #ghi\rfrom __future__ import (division as b, generators,)\rfrom __future__ import with_statement\r' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 4 - assert f.col_offset == 0 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_semicolon(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert f.lineno == 3 - assert f.col_offset == 55 + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) + +def test_semicolon_2(): + s = 'from __future__ import division; from foo import bar' + f = run(s, expected_last_future=(1, 39)) + assert f == fut.CO_FUTURE_DIVISION def test_full_chain(): s = '"abc" #def\n #ghi\nfrom __future__ import (division as b, generators,); from __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags == (fut.CO_FUTURE_DIVISION | - fut.CO_GENERATOR_ALLOWED | - fut.CO_FUTURE_WITH_STATEMENT) - assert pos == (3, 55) + f = run(s) + assert f == (fut.CO_FUTURE_DIVISION | + fut.CO_GENERATOR_ALLOWED | + fut.CO_FUTURE_WITH_STATEMENT) def test_intervening_code(): s = 'from __future__ import (division as b, generators,)\nfrom sys import modules\nfrom __future__ import with_statement\n' - flags, pos = future.get_futures(future.futureFlags_2_5, s) - assert flags & fut.CO_FUTURE_WITH_STATEMENT == 0 - assert pos == (1, 0) + f = run(s, expected_last_future=(2, 5)) + assert f == (fut.CO_FUTURE_DIVISION | fut.CO_GENERATOR_ALLOWED) def test_nonexisting(): s = 'from __future__ import non_existing_feature\n' f = run(s) - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == 0 + +def test_nonexisting_2(): + s = 'from __future__ import non_existing_feature, with_statement\n' + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_from_import_abs_import(): s = 'from __future__ import absolute_import\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_ABSOLUTE_IMPORT - assert f.lineno == 1 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_ABSOLUTE_IMPORT def test_raw_doc(): s = 'r"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_unicode_doc(): s = 'u"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_raw_unicode_doc(): s = 'ru"Doc"\nfrom __future__ import with_statement\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_line(): s = "\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 2 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_continuation_lines(): s = "\\\n \t\\\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 3 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT def test_lots_of_continuation_lines(): s = "\\\n\\\n\\\n\\\n\\\n\\\n\nfrom __future__ import with_statement\n" f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_WITH_STATEMENT - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_WITH_STATEMENT -# This looks like a bug in cpython parser -# and would require extensive modifications -# to future.py in order to emulate the same behaviour def test_continuation_lines_raise(): - py.test.skip("probably a CPython bug") s = " \\\n \t\\\nfrom __future__ import with_statement\n" - try: - f = run(s) - except IndentationError, e: - assert e.args == 'unexpected indent' - assert f.pos == len(s) - assert f.flags == 0 - assert f.lineno == -1 - assert f.col_offset == 0 - else: - raise AssertionError('IndentationError not raised') - assert f.lineno == 2 - assert f.col_offset == 0 + f = run(s, expected_last_future=(1, 0)) + assert f == 0 # because of the INDENT def test_continuation_lines_in_docstring_single_quoted(): s = '"\\\n\\\n\\\n\\\n\\\n\\\n"\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION def test_continuation_lines_in_docstring_triple_quoted(): s = '"""\\\n\\\n\\\n\\\n\\\n\\\n"""\nfrom __future__ import division\n' f = run(s) - assert f.pos == len(s) - assert f.flags == fut.CO_FUTURE_DIVISION - assert f.lineno == 8 - assert f.col_offset == 0 + assert f == fut.CO_FUTURE_DIVISION + +def test_blank_lines(): + s = ('\n\t\n\nfrom __future__ import with_statement' + ' \n \n \nfrom __future__ import division') + f = run(s) + assert f == fut.CO_FUTURE_WITH_STATEMENT | fut.CO_FUTURE_DIVISION + +def test_dummy_semicolons(): + s = ('from __future__ import division;\n' + 'from __future__ import with_statement;') + f = run(s) + assert f == fut.CO_FUTURE_DIVISION | fut.CO_FUTURE_WITH_STATEMENT diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py b/pypy/interpreter/pyparser/test/test_pyparse.py --- a/pypy/interpreter/pyparser/test/test_pyparse.py +++ b/pypy/interpreter/pyparser/test/test_pyparse.py @@ -148,3 +148,6 @@ self.parse('0b1101') self.parse('0b0l') py.test.raises(SyntaxError, self.parse, "0b112") + + def test_print_function(self): + self.parse("from __future__ import print_function\nx = print\n") diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -303,6 +303,9 @@ 'from __future__ import nested_scopes, generators', 'from __future__ import (nested_scopes,\ngenerators)', 'from __future__ import (nested_scopes,\ngenerators,)', + 'from __future__ import (\nnested_scopes,\ngenerators)', + 'from __future__ import(\n\tnested_scopes,\n\tgenerators)', + 'from __future__ import(\n\t\nnested_scopes)', 'from sys import stdin, stderr, stdout', 'from sys import (stdin, stderr,\nstdout)', 'from sys import (stdin, stderr,\nstdout,)', diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -151,6 +151,7 @@ if w_fields == space.w_None: self.fields = None else: + self.fields = {} ofs_and_items = [] size = 0 for key in space.listview(w_fields): @@ -338,8 +339,9 @@ elif char == 'V': num = 20 basename = 'void' - w_box_type = space.gettypefor(interp_boxes.W_VoidBox) - return dtype_from_list(space, space.newlist([])) + itemtype = types.VoidType(size) + return W_Dtype(itemtype, 20, VOIDLTR, "void" + str(size), + "V", space.gettypefor(interp_boxes.W_VoidBox)) else: assert char == 'U' basename = 'unicode' diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,23 +275,12 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) assert loads(dumps(a.dtype)) == a.dtype - def test_pickle_record(self): - from numpypy import array, dtype - from cPickle import loads, dumps - - d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) - assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) - - new_d = loads(dumps(d)) - - assert new_d.__reduce__() == d.__reduce__() - class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): import numpypy as numpy @@ -769,6 +758,7 @@ assert isinstance(unicode_(3), unicode) class AppTestRecordDtypes(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): from numpypy import dtype, void @@ -815,6 +805,30 @@ assert dt.subdtype == (dtype(float), (10,)) assert dt.base == dtype(float) + def test_pickle_record(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32"), ("y", "int32"), ("z", "int32"), ("value", float)]) + assert d.__reduce__() == (dtype, ('V20', 0, 1), (3, '<', None, ('x', 'y', 'z', 'value'), {'y': (dtype('int32'), 4), 'x': (dtype('int32'), 0), 'z': (dtype('int32'), 8), 'value': (dtype('float64'), 12)}, 20, 1, 0)) + + new_d = loads(dumps(d)) + + assert new_d.__reduce__() == d.__reduce__() + + def test_pickle_record_subarrays(self): + from numpypy import array, dtype + from cPickle import loads, dumps + + d = dtype([("x", "int32", (3,)), ("y", "int32", (2,)), ("z", "int32", (4,)), ("value", float, (5,))]) + new_d = loads(dumps(d)) + + keys = d.fields.keys() + keys.sort() + assert keys == ["value", "x", "y", "z"] + + assert new_d.itemsize == d.itemsize == 76 + class AppTestNotDirect(BaseNumpyAppTest): def setup_class(cls): BaseNumpyAppTest.setup_class.im_func(cls) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1704,25 +1704,6 @@ T = lltype.Char def _coerce(self, space, arr, ofs, dtype, w_items, shape): - items_w = space.fixedview(w_items) - for i in range(len(items_w)): - subdtype = dtype.subdtype - itemtype = subdtype.itemtype - if space.len_w(shape) <= 1: - w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) - itemtype.store(arr, 0, ofs, w_box) - ofs += itemtype.get_element_size() - else: - size = 1 - for dimension in shape[1:]: - size *= dimension - size *= itemtype.get_element_size() - for w_item in items_w: - self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) - ofs += size - return arr - - def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match items_w = space.fixedview(w_items) subdtype = dtype.subdtype diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,7 +105,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -142,7 +141,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -339,7 +339,6 @@ loop, = log.loops_by_filename(self.filepath) # the int strategy is used here assert loop.match_by_id('append', """ - guard_not_invalidated(descr=...) i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) # Will be killed by the backend @@ -487,7 +486,6 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) - guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -587,6 +585,7 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' + guard_not_invalidated(descr=...) i1 = force_token() ''') diff --git a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py --- a/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py +++ b/pypy/module/test_lib_pypy/cffi_tests/backend_tests.py @@ -971,6 +971,16 @@ s.c = -4 assert s.c == -4 + def test_bitfield_enum(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef(""" + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_anonymous_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("typedef struct { int a; } foo_t;") diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -28,3 +28,12 @@ assert ffi.typeof("long(*)(long, long**, ...)").cname == ( "long(*)(long, long * *, ...)") assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True + + def test_new_handle(self): + ffi = FFI(backend=self.Backend()) + o = [2, 3, 4] + p = ffi.new_handle(o) + assert ffi.typeof(p) == ffi.typeof("void *") + assert ffi.from_handle(p) is o + assert ffi.from_handle(ffi.cast("char *", p)) is o + py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_function.py b/pypy/module/test_lib_pypy/cffi_tests/test_function.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_function.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_function.py @@ -334,6 +334,31 @@ assert lib.EE == -5 assert lib.FF == -4 + def test_void_star_accepts_string(self): + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(const void *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + + def test_signed_char_star_accepts_string(self): + if self.Backend is CTypesBackend: + py.test.skip("not supported by the ctypes backend") + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(signed char *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + + def test_unsigned_char_star_accepts_string(self): + if self.Backend is CTypesBackend: + py.test.skip("not supported by the ctypes backend") + ffi = FFI(backend=self.Backend()) + ffi.cdef("""int strlen(unsigned char *);""") + lib = ffi.dlopen(None) + res = lib.strlen(b"hello") + assert res == 5 + def test_missing_function(self): ffi = FFI(backend=self.Backend()) ffi.cdef(""" @@ -341,3 +366,19 @@ """) m = ffi.dlopen("m") assert not hasattr(m, 'nonexistent') + + def test_wraps_from_stdlib(self): + import functools + ffi = FFI(backend=self.Backend()) + ffi.cdef(""" + double sin(double x); + """) + def my_decorator(f): + @functools.wraps(f) + def wrapper(*args): + return f(*args) + 100 + return wrapper + m = ffi.dlopen("m") + sin100 = my_decorator(m.sin) + x = sin100(1.23) + assert x == math.sin(1.23) + 100 diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py @@ -522,6 +522,18 @@ py.test.raises(OverflowError, "s.b = 4") assert s.b == 3 +def test_struct_with_bitfield_enum(): + ffi = FFI() + code = """ + typedef enum { AA, BB, CC } foo_e; + typedef struct { foo_e f:2; } foo_s; + """ + ffi.cdef(code) + ffi.verify(code) + s = ffi.new("foo_s *") + s.f = 2 + assert s.f == 2 + def test_unsupported_struct_with_bitfield_ellipsis(): ffi = FFI() py.test.raises(NotImplementedError, ffi.cdef, diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py b/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_zintegration.py @@ -24,6 +24,12 @@ modules = ('cffi', '_cffi_backend') except ImportError: modules = ('cffi', '_cffi_backend', 'pycparser') + try: + import ply + except ImportError: + pass + else: + modules += ('ply',) # needed for older versions of pycparser for module in modules: target = imp.find_module(module)[1] os.symlink(target, os.path.join(site_packages, diff --git a/pypy/objspace/std/iterobject.py b/pypy/objspace/std/iterobject.py --- a/pypy/objspace/std/iterobject.py +++ b/pypy/objspace/std/iterobject.py @@ -1,16 +1,17 @@ """Generic iterator implementations""" -from pypy.interpreter import gateway + from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.gateway import interp2app, interpindirect2app from pypy.interpreter.error import OperationError from pypy.objspace.std.stdtypedef import StdTypeDef class W_AbstractSeqIterObject(W_Root): - def __init__(w_self, w_seq, index=0): + def __init__(self, w_seq, index=0): if index < 0: index = 0 - w_self.w_seq = w_seq - w_self.index = index + self.w_seq = w_seq + self.index = index def getlength(self, space): if self.w_seq is None: @@ -33,8 +34,6 @@ XXX to do: remove this __reduce__ method and do a registration with copy_reg, instead. """ - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(self, W_AbstractSeqIterObject) from pypy.interpreter.mixedmodule import MixedModule w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) @@ -43,8 +42,6 @@ return space.newtuple([new_inst, space.newtuple(tup)]) def descr_length_hint(self, space): - from pypy.objspace.std.iterobject import W_AbstractSeqIterObject - assert isinstance(self, W_AbstractSeqIterObject) return self.getlength(space) W_AbstractSeqIterObject.typedef = StdTypeDef( @@ -55,12 +52,10 @@ Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.''', - - __iter__ = gateway.interp2app(W_AbstractSeqIterObject.descr_iter), - next = gateway.interpindirect2app(W_AbstractSeqIterObject.descr_next), - __reduce__ = gateway.interp2app(W_AbstractSeqIterObject.descr_reduce), - __length_hint__ = gateway.interp2app( - W_AbstractSeqIterObject.descr_length_hint), + __iter__ = interp2app(W_AbstractSeqIterObject.descr_iter), + next = interpindirect2app(W_AbstractSeqIterObject.descr_next), + __reduce__ = interp2app(W_AbstractSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_AbstractSeqIterObject.descr_length_hint), ) W_AbstractSeqIterObject.typedef.acceptable_as_base_class = False @@ -105,9 +100,9 @@ """Sequence iterator specialized for tuples, accessing directly their RPython-level list of wrapped objects. """ - def __init__(w_self, w_seq, wrappeditems): - W_AbstractSeqIterObject.__init__(w_self, w_seq) - w_self.tupleitems = wrappeditems + def __init__(self, w_seq, wrappeditems): + W_AbstractSeqIterObject.__init__(self, w_seq) + self.tupleitems = wrappeditems def descr_next(self, space): if self.tupleitems is None: @@ -124,18 +119,16 @@ class W_ReverseSeqIterObject(W_Root): - def __init__(w_self, space, w_seq, index=-1): - w_self.w_seq = w_seq - w_self.w_len = space.len(w_seq) - w_self.index = space.int_w(w_self.w_len) + index + def __init__(self, space, w_seq, index=-1): + self.w_seq = w_seq + self.w_len = space.len(w_seq) + self.index = space.int_w(self.w_len) + index def descr_reduce(self, space): """ XXX to do: remove this __reduce__ method and do a registration with copy_reg, instead. """ - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(self, W_ReverseSeqIterObject) from pypy.interpreter.mixedmodule import MixedModule w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) @@ -144,8 +137,6 @@ return space.newtuple([new_inst, space.newtuple(tup)]) def descr_length_hint(self, space): - from pypy.objspace.std.iterobject import W_ReverseSeqIterObject - assert isinstance(self, W_ReverseSeqIterObject) if self.w_seq is None: return space.wrap(0) index = self.index + 1 @@ -178,10 +169,9 @@ W_ReverseSeqIterObject.typedef = StdTypeDef( "reversesequenceiterator", - __iter__ = gateway.interp2app(W_ReverseSeqIterObject.descr_iter), - next = gateway.interp2app(W_ReverseSeqIterObject.descr_next), - __reduce__ = gateway.interp2app(W_ReverseSeqIterObject.descr_reduce), - __length_hint__ = gateway.interp2app( - W_ReverseSeqIterObject.descr_length_hint), + __iter__ = interp2app(W_ReverseSeqIterObject.descr_iter), + next = interp2app(W_ReverseSeqIterObject.descr_next), + __reduce__ = interp2app(W_ReverseSeqIterObject.descr_reduce), + __length_hint__ = interp2app(W_ReverseSeqIterObject.descr_length_hint), ) W_ReverseSeqIterObject.typedef.acceptable_as_base_class = False diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -1,5 +1,14 @@ +"""The builtin list implementation + +Lists optimize their storage by holding certain primitive datatypes in +unwrapped form. For more information: + +http://morepypy.blogspot.com/2011/10/more-compact-lists-with-list-strategies.html + +""" + import operator -from sys import maxint +import sys from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, operationerrfmt @@ -18,11 +27,11 @@ from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject -from pypy.objspace.std.util import negate, get_positive_index -from rpython.rlib import rerased, jit, debug +from pypy.objspace.std.util import get_positive_index, negate +from rpython.rlib import debug, jit, rerased from rpython.rlib.listsort import make_timsort_class -from rpython.rlib.objectmodel import (instantiate, newlist_hint, specialize, - resizelist_hint) +from rpython.rlib.objectmodel import ( + instantiate, newlist_hint, resizelist_hint, specialize) from rpython.tool.sourcetools import func_with_new_name __all__ = ['W_ListObject', 'make_range_list', 'make_empty_list_with_size'] @@ -130,26 +139,26 @@ class W_ListObject(W_Root): - def __init__(w_self, space, wrappeditems, sizehint=-1): + + def __init__(self, space, wrappeditems, sizehint=-1): assert isinstance(wrappeditems, list) - w_self.space = space + self.space = space if space.config.objspace.std.withliststrategies: - w_self.strategy = get_strategy_from_list_objects(space, - wrappeditems, - sizehint) + self.strategy = get_strategy_from_list_objects(space, wrappeditems, + sizehint) else: - w_self.strategy = space.fromcache(ObjectListStrategy) - w_self.init_from_list_w(wrappeditems) + self.strategy = space.fromcache(ObjectListStrategy) + self.init_from_list_w(wrappeditems) @staticmethod def from_storage_and_strategy(space, storage, strategy): - w_self = instantiate(W_ListObject) - w_self.space = space - w_self.strategy = strategy - w_self.lstorage = storage + self = instantiate(W_ListObject) + self.space = space + self.strategy = strategy + self.lstorage = storage if not space.config.objspace.std.withliststrategies: - w_self.switch_to_object_strategy() - return w_self + self.switch_to_object_strategy() + return self @staticmethod def newlist_str(space, list_s): @@ -157,10 +166,10 @@ storage = strategy.erase(list_s) return W_ListObject.from_storage_and_strategy(space, storage, strategy) - def __repr__(w_self): + def __repr__(self): """ representation for debugging purposes """ - return "%s(%s, %s)" % (w_self.__class__.__name__, w_self.strategy, - w_self.lstorage._x) + return "%s(%s, %s)" % (self.__class__.__name__, self.strategy, + self.lstorage._x) def unwrap(w_list, space): # for tests only! @@ -216,7 +225,7 @@ strategy and storage according to the other W_List""" self.strategy.copy_into(self, other) - def find(self, w_item, start=0, end=maxint): + def find(self, w_item, start=0, end=sys.maxint): """Find w_item in list[start:end]. If not found, raise ValueError""" return self.strategy.find(self, w_item, start, end) @@ -590,14 +599,14 @@ 'L.remove(value) -- remove first occurrence of value' # needs to be safe against eq_w() mutating the w_list behind our back try: - i = self.find(w_value, 0, maxint) + i = self.find(w_value, 0, sys.maxint) except ValueError: raise OperationError(space.w_ValueError, space.wrap("list.remove(x): x not in list")) if i < self.length(): # otherwise list was mutated self.pop(i) - @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) def descr_index(self, space, w_value, w_start, w_stop): '''L.index(value, [start, [stop]]) -> integer -- return first index of value''' diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -18,18 +18,18 @@ class W_BaseSetObject(W_Root): typedef = None - def __init__(w_self, space, w_iterable=None): + def __init__(self, space, w_iterable=None): """Initialize the set by taking ownership of 'setdata'.""" - w_self.space = space - set_strategy_and_setdata(space, w_self, w_iterable) + self.space = space + set_strategy_and_setdata(space, self, w_iterable) - def __repr__(w_self): + def __repr__(self): """representation for debugging purposes""" - reprlist = [repr(w_item) for w_item in w_self.getkeys()] - return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist)) + reprlist = [repr(w_item) for w_item in self.getkeys()] + return "<%s(%s)>" % (self.__class__.__name__, ', '.join(reprlist)) - def from_storage_and_strategy(w_self, storage, strategy): - obj = w_self._newobj(w_self.space, None) + def from_storage_and_strategy(self, storage, strategy): + obj = self._newobj(self.space, None) assert isinstance(obj, W_BaseSetObject) obj.strategy = strategy obj.sstorage = storage @@ -501,11 +501,11 @@ class W_SetObject(W_BaseSetObject): - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new set by taking ownership of 'w_iterable'.""" - if type(w_self) is W_SetObject: + if type(self) is W_SetObject: return W_SetObject(space, w_iterable) - w_type = space.type(w_self) + w_type = space.type(self) w_obj = space.allocate_instance(W_SetObject, w_type) W_SetObject.__init__(w_obj, space, w_iterable) return w_obj @@ -577,11 +577,11 @@ class W_FrozensetObject(W_BaseSetObject): hash = 0 - def _newobj(w_self, space, w_iterable): + def _newobj(self, space, w_iterable): """Make a new frozenset by taking ownership of 'w_iterable'.""" - if type(w_self) is W_FrozensetObject: + if type(self) is W_FrozensetObject: return W_FrozensetObject(space, w_iterable) - w_type = space.type(w_self) + w_type = space.type(self) w_obj = space.allocate_instance(W_FrozensetObject, w_type) W_FrozensetObject.__init__(w_obj, space, w_iterable) return w_obj @@ -1439,9 +1439,9 @@ class W_SetIterObject(W_Root): - def __init__(w_self, space, iterimplementation): - w_self.space = space - w_self.iterimplementation = iterimplementation + def __init__(self, space, iterimplementation): + self.space = space + self.iterimplementation = iterimplementation def descr_length_hint(self, space): return space.wrap(self.iterimplementation.length()) diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py --- a/pypy/objspace/std/specialisedtupleobject.py +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -14,13 +14,13 @@ def make_specialised_class(typetuple): assert type(typetuple) == tuple - nValues = len(typetuple) - iter_n = unrolling_iterable(range(nValues)) + typelen = len(typetuple) + iter_n = unrolling_iterable(range(typelen)) class cls(W_AbstractTupleObject): def __init__(self, space, *values_w): self.space = space - assert len(values_w) == nValues + assert len(values_w) == typelen for i in iter_n: w_obj = values_w[i] val_type = typetuple[i] @@ -37,10 +37,10 @@ setattr(self, 'value%s' % i, unwrapped) def length(self): - return nValues + return typelen def tolist(self): - list_w = [None] * nValues + list_w = [None] * typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] != object: @@ -54,7 +54,7 @@ def descr_hash(self, space): mult = 1000003 x = 0x345678 - z = nValues + z = typelen for i in iter_n: value = getattr(self, 'value%s' % i) if typetuple[i] == object: @@ -76,7 +76,7 @@ if not isinstance(w_other, W_AbstractTupleObject): return space.w_NotImplemented if not isinstance(w_other, cls): - if nValues != w_other.length(): + if typelen != w_other.length(): return space.w_False for i in iter_n: myval = getattr(self, 'value%s' % i) @@ -102,7 +102,7 @@ def getitem(self, space, index): if index < 0: - index += nValues + index += typelen for i in iter_n: if index == i: value = getattr(self, 'value%s' % i) diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -1,8 +1,11 @@ +"""The builtin tuple implementation""" + import sys -from pypy.interpreter import gateway + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app, interpindirect2app +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) from pypy.objspace.std import slicetype from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice @@ -177,8 +180,7 @@ count += 1 return space.wrap(count) - @gateway.unwrap_spec(w_start=gateway.WrappedDefault(0), - w_stop=gateway.WrappedDefault(sys.maxint)) + @unwrap_spec(w_start=WrappedDefault(0), w_stop=WrappedDefault(sys.maxint)) @jit.look_inside_iff(lambda self, _1, _2, _3, _4: _unroll_condition(self)) def descr_index(self, space, w_obj, w_start, w_stop): """index(obj, [start, [stop]]) -> first index that obj appears in the 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 @@ -73,6 +73,11 @@ rename_pypy_c += '.exe' binaries = [(pypy_c, rename_pypy_c)] # + builddir = udir.ensure("build", dir=True) + pypydir = builddir.ensure(name, dir=True) + includedir = basedir.join('include') + pypydir.ensure('include', dir=True) + if sys.platform == 'win32': #Don't include a mscvrXX.dll, users should get their own. #Instructions are provided on the website. @@ -85,12 +90,22 @@ p = pypy_c.dirpath().join(extra) if not p.check(): p = py.path.local.sysfind(extra) - assert p, "%s not found" % (extra,) + if not p: + print "%s not found, expect trouble if this is a shared build" % (extra,) + continue print "Picking %s" % p binaries.append((p, p.basename)) - # - builddir = udir.ensure("build", dir=True) - pypydir = builddir.ensure(name, dir=True) + if pypy_c.dirpath().join("libpypy-c.lib").check(): + shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), + str(pypydir.join('include/python27.lib'))) + print "Picking %s as %s" % (pypy_c.dirpath().join("libpypy-c.lib"), + pypydir.join('include/python27.lib')) + else: + pass + # XXX users will complain that they cannot compile cpyext + # modules for windows, has the lib moved or are there no + # exported functions in the dll so no import library is created? + # Careful: to copy lib_pypy, copying just the svn-tracked files # would not be enough: there are also ctypes_config_cache/_*_cache.py. shutil.copytree(str(basedir.join('lib-python').join(STDLIB_VER)), @@ -102,15 +117,10 @@ '*.c', '*.o')) for file in ['LICENSE', 'README.rst']: shutil.copy(str(basedir.join(file)), str(pypydir)) - pypydir.ensure('include', dir=True) - if sys.platform == 'win32': - shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), - str(pypydir.join('include/python27.lib'))) - # we want to put there all *.h and *.inl from trunk/include - # and from pypy/_interfaces - includedir = basedir.join('include') headers = includedir.listdir('*.h') + includedir.listdir('*.inl') for n in headers: + # we want to put there all *.h and *.inl from trunk/include + # and from pypy/_interfaces shutil.copy(str(n), str(pypydir.join('include'))) # spdir = pypydir.ensure('site-packages', dir=True) diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -3,8 +3,6 @@ from rpython.config.config import ChoiceOption, StrOption, Config from rpython.config.config import ConfigError from rpython.config.support import detect_number_of_processors -from rpython.jit.backend.detect_cpu import autodetect -from rpython.jit.backend.detect_cpu import MODEL_X86, MODEL_X86_NO_SSE2, MODEL_X86_64 DEFL_INLINE_THRESHOLD = 32.4 # just enough to inline add__Int_Int() # and just small enough to prevend inlining of some rlist functions. @@ -15,9 +13,7 @@ DEFL_GC = "minimark" -_is_x86 = autodetect() in (MODEL_X86, MODEL_X86_64, MODEL_X86_NO_SSE2) - -if sys.platform.startswith("linux") and _is_x86: +if sys.platform.startswith("linux"): DEFL_ROOTFINDER_WITHJIT = "asmgcc" else: DEFL_ROOTFINDER_WITHJIT = "shadowstack" diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -85,7 +85,7 @@ # exported_state is clear by optimizeopt when the short preamble is # constrcucted. if that did not happen the label should not show up # in a trace that will be used - assert descr.exported_state is None + assert descr.exported_state is None if not we_are_translated(): op._descr_wref = weakref.ref(op._descr) op.cleardescr() # clear reference to prevent the history.Stats @@ -819,7 +819,7 @@ # The history contains new operations to attach as the code for the # failure of 'resumekey.guard_op'. - # + # # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. new_trace = create_empty_loop(metainterp) From noreply at buildbot.pypy.org Sat May 25 20:35:25 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 25 May 2013 20:35:25 +0200 (CEST) Subject: [pypy-commit] stm default: Tweaks Message-ID: <20130525183526.339D21C0203@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r7:98fb519334f7 Date: 2013-05-25 20:35 +0200 http://bitbucket.org/pypy/stm/changeset/98fb519334f7/ Log: Tweaks diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -454,16 +454,20 @@ for (i = 0; i < intermediate_limit; i++) { gcptr R = items[i]; gcptr L; + revision_t v = R->h_revision; assert(dclassify(R) == K_PUBLIC); - assert(!(R->h_revision & 1)); /* "is a pointer" */ - assert(R->h_revision & 2); /* a pointer with bit 2 set */ - L = (gcptr)(R->h_revision & ~2); - assert(dclassify(L) == K_PROTECTED); - visit_if_young(&L _REASON("public.h_revision -> PROTECTED")); - /* The new value of L is the previously-protected object moved - outside. We can't store it immediately in R->h_revision! - We have to wait until the end of the minor collection. See - finish_public_to_young(). */ + assert(!(v & 1)); /* "is a pointer" */ + + if (v & 2) { /* a pointer with bit 2 set. + Normally set, except if R was stolen */ + L = (gcptr)(v & ~2); + assert(dclassify(L) == K_PROTECTED); + visit_if_young(&L _REASON("public.h_revision -> PROTECTED")); + /* The new value of L is the previously-protected object moved + outside. We can't store it immediately in R->h_revision! + We have to wait until the end of the minor collection. See + finish_public_to_young(). */ + } /*mark*/ } @@ -506,19 +510,23 @@ for (i = 0; i < intermediate_limit; i++) { gcptr R = items[i]; gcptr L; + revision_t v = R->h_revision; assert(dclassify(R) == K_PUBLIC); - assert(!(R->h_revision & 1)); /* "is a pointer" */ - assert(R->h_revision & 2); /* a pointer with bit 2 set */ - L = (gcptr)(R->h_revision & ~2); + assert(!(v & 1)); /* "is a pointer" */ + if (v & 2) { /* a pointer with bit 2 set. + Normally set, except if R was stolen */ + L = (gcptr)(v & ~2); - /* use visit_if_young() again to find the final newly-public object */ - visit_if_young(&L _REASON("public.h_revision -> FETCH PUBLIC")); - assert(dclassify(L) == K_PUBLIC); + /* use visit_if_young() again to find the final newly-public + object */ + visit_if_young(&L _REASON("public.h_revision -> FETCH PUBLIC")); + assert(dclassify(L) == K_PUBLIC); - /* Note that although R is public, its h_revision cannot be - modified under our feet as long as we hold the collection lock, - because it's pointing to one of our protected objects */ - ACCESS_ONCE(R->h_revision) = (revision_t)L; + /* Note that although R is public, its h_revision cannot be + modified under our feet as long as we hold the collection lock, + because it's pointing to one of our protected objects */ + R->h_revision = (revision_t)L; + } /*mark*/ } From noreply at buildbot.pypy.org Sat May 25 21:47:41 2013 From: noreply at buildbot.pypy.org (amauryfa) Date: Sat, 25 May 2013 21:47:41 +0200 (CEST) Subject: [pypy-commit] pypy default: Issue1498: Fix another issue with subclasses of ctypes structures. Message-ID: <20130525194741.874951C0203@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: Changeset: r64558:ff06e504ab9c Date: 2013-05-25 21:37 +0200 http://bitbucket.org/pypy/pypy/changeset/ff06e504ab9c/ Log: Issue1498: Fix another issue with subclasses of ctypes structures. diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -166,8 +166,7 @@ if self is StructOrUnion: return if '_fields_' not in self.__dict__: - self._fields_ = [] - _set_shape(self, [], self._is_union) + self._fields_ = [] # As a side-effet, this also sets the ffishape. __setattr__ = struct_setattr diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -239,6 +239,9 @@ pass pos = POSITION(1, 2) assert (pos.x, pos.y) == (1, 2) + # Try a second time, result may be different (cf. issue1498) + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) def test_invalid_field_types(self): From noreply at buildbot.pypy.org Sat May 25 22:38:38 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sat, 25 May 2013 22:38:38 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: ease the W_TypeObject assertion to accomodate Dummy/FakeObjSpaces Message-ID: <20130525203838.E5E7A1C12FE@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64559:52c9fdaa5b22 Date: 2013-05-25 13:37 -0700 http://bitbucket.org/pypy/pypy/changeset/52c9fdaa5b22/ Log: ease the W_TypeObject assertion to accomodate Dummy/FakeObjSpaces diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -355,18 +355,21 @@ self.xstrings = strings for i, _, attr in entries: setattr(self, attr, args[i]) - assert _is_type(w_type) + assert w_type is not None + # space may be None during tests + self.space = w_type.space if _is_type(w_type) else None def _compute_value(self): + space = self.space lst = [None] * (len(formats) + len(formats) + 1) for i, fmt, attr in entries: string = self.xstrings[i] value = getattr(self, attr) lst[i+i] = string - if fmt in 'NT': - space = self.w_type.space - if fmt == 'T': - value = space.type(value) + if fmt == 'T': + type_ = type if space is None else space.type + value = type_(value) + if fmt in 'NT' and space is not None: lst[i+i+1] = value.getname(space) else: lst[i+i+1] = str(value) diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -12,26 +12,25 @@ assert (decompose_valuefmt("%s%d%%%s") == (("", "", "%", ""), ('s', 'd', 's'))) -def test_get_operrcls2(space): +def test_get_operrcls2(): cls, strings = get_operrcls2('abc %s def %d') assert strings == ("abc ", " def ", "") assert issubclass(cls, OperationError) - inst = cls(space.w_OSError, strings, "hello", 42) + inst = cls("w_type", strings, "hello", 42) assert inst._compute_value() == "abc hello def 42" cls2, strings2 = get_operrcls2('a %s b %d c') assert cls2 is cls # caching assert strings2 == ("a ", " b ", " c") -def test_operationerrfmt(space): - w_exc = space.w_IOError - operr = operationerrfmt(w_exc, "abc %s def %d", "foo", 42) +def test_operationerrfmt(): + operr = operationerrfmt("w_type", "abc %s def %d", "foo", 42) assert isinstance(operr, OperationError) - assert operr.w_type == w_exc + assert operr.w_type == "w_type" assert operr._w_value is None assert operr._compute_value() == "abc foo def 42" - operr2 = operationerrfmt(w_exc, "a %s b %d c", "bar", 43) + operr2 = operationerrfmt("w_type2", "a %s b %d c", "bar", 43) assert operr2.__class__ is operr.__class__ - operr3 = operationerrfmt(w_exc, "a %s b %s c", "bar", "4b") + operr3 = operationerrfmt("w_type2", "a %s b %s c", "bar", "4b") assert operr3.__class__ is not operr.__class__ def test_operationerrfmt_T(space): From noreply at buildbot.pypy.org Sun May 26 00:35:50 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 26 May 2013 00:35:50 +0200 (CEST) Subject: [pypy-commit] pypy default: use W_TypeObjects throughout Message-ID: <20130525223550.CE23C1C12FE@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64560:80ac073c7257 Date: 2013-05-25 15:31 -0700 http://bitbucket.org/pypy/pypy/changeset/80ac073c7257/ Log: use W_TypeObjects throughout diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -46,11 +46,11 @@ self.name = name class FakeSpace(object): - w_ValueError = "ValueError" - w_TypeError = "TypeError" - w_IndexError = "IndexError" - w_OverflowError = "OverflowError" - w_NotImplementedError = "NotImplementedError" + w_ValueError = W_TypeObject("ValueError") + w_TypeError = W_TypeObject("TypeError") + w_IndexError = W_TypeObject("IndexError") + w_OverflowError = W_TypeObject("OverflowError") + w_NotImplementedError = W_TypeObject("NotImplementedError") w_None = None w_bool = W_TypeObject("bool") From noreply at buildbot.pypy.org Sun May 26 00:35:52 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 26 May 2013 00:35:52 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: merge default Message-ID: <20130525223552.212761C12FE@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64561:0cd18b874a6c Date: 2013-05-25 15:31 -0700 http://bitbucket.org/pypy/pypy/changeset/0cd18b874a6c/ Log: merge default diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -166,8 +166,7 @@ if self is StructOrUnion: return if '_fields_' not in self.__dict__: - self._fields_ = [] - _set_shape(self, [], self._is_union) + self._fields_ = [] # As a side-effet, this also sets the ffishape. __setattr__ = struct_setattr diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -46,11 +46,11 @@ self.name = name class FakeSpace(object): - w_ValueError = "ValueError" - w_TypeError = "TypeError" - w_IndexError = "IndexError" - w_OverflowError = "OverflowError" - w_NotImplementedError = "NotImplementedError" + w_ValueError = W_TypeObject("ValueError") + w_TypeError = W_TypeObject("TypeError") + w_IndexError = W_TypeObject("IndexError") + w_OverflowError = W_TypeObject("OverflowError") + w_NotImplementedError = W_TypeObject("NotImplementedError") w_None = None w_bool = W_TypeObject("bool") diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -239,6 +239,9 @@ pass pos = POSITION(1, 2) assert (pos.x, pos.y) == (1, 2) + # Try a second time, result may be different (cf. issue1498) + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) def test_invalid_field_types(self): From noreply at buildbot.pypy.org Sun May 26 00:35:53 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 26 May 2013 00:35:53 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: utilize %T everywhere Message-ID: <20130525223553.A20CE1C12FE@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64562:681043e107df Date: 2013-05-25 15:32 -0700 http://bitbucket.org/pypy/pypy/changeset/681043e107df/ Log: utilize %T everywhere diff too long, truncating to 2000 out of 2206 lines diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -86,12 +86,9 @@ args_w = space.fixedview(w_stararg) except OperationError, e: if e.match(space, space.w_TypeError): - w_type = space.type(w_stararg) - typename = w_type.getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap("argument after * must be " - "a sequence, not %s" % (typename,))) + "argument after * must be a sequence, not %T", w_stararg) raise self.arguments_w = self.arguments_w + args_w @@ -116,12 +113,10 @@ w_keys = space.call_method(w_starstararg, "keys") except OperationError, e: if e.match(space, space.w_AttributeError): - w_type = space.type(w_starstararg) - typename = w_type.getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap("argument after ** must be " - "a mapping, not %s" % (typename,))) + "argument after ** must be a mapping, not %T", + w_starstararg) raise keys_w = space.unpackiterable(w_keys) keywords_w = [None] * len(keys_w) diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2793,8 +2793,7 @@ def Module_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2835,8 +2834,7 @@ def Interactive_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2881,8 +2879,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Expression_set_body(space, w_self, w_new_value): @@ -2925,8 +2922,7 @@ def Suite_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2971,8 +2967,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def stmt_set_lineno(space, w_self, w_new_value): @@ -2993,8 +2988,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def stmt_set_col_offset(space, w_self, w_new_value): @@ -3024,8 +3018,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def FunctionDef_set_name(space, w_self, w_new_value): @@ -3046,8 +3039,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') return space.wrap(w_self.args) def FunctionDef_set_args(space, w_self, w_new_value): @@ -3064,8 +3056,7 @@ def FunctionDef_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3081,8 +3072,7 @@ def FunctionDef_get_decorator_list(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'decorator_list') if w_self.w_decorator_list is None: if w_self.decorator_list is None: list_w = [] @@ -3131,8 +3121,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def ClassDef_set_name(space, w_self, w_new_value): @@ -3149,8 +3138,7 @@ def ClassDef_get_bases(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'bases') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'bases') if w_self.w_bases is None: if w_self.bases is None: list_w = [] @@ -3166,8 +3154,7 @@ def ClassDef_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3183,8 +3170,7 @@ def ClassDef_get_decorator_list(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'decorator_list') if w_self.w_decorator_list is None: if w_self.decorator_list is None: list_w = [] @@ -3234,8 +3220,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Return_set_value(space, w_self, w_new_value): @@ -3278,8 +3263,7 @@ def Delete_get_targets(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'targets') if w_self.w_targets is None: if w_self.targets is None: list_w = [] @@ -3320,8 +3304,7 @@ def Assign_get_targets(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'targets') if w_self.w_targets is None: if w_self.targets is None: list_w = [] @@ -3341,8 +3324,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Assign_set_value(space, w_self, w_new_value): @@ -3391,8 +3373,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def AugAssign_set_target(space, w_self, w_new_value): @@ -3415,8 +3396,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return operator_to_class[w_self.op - 1]() def AugAssign_set_op(space, w_self, w_new_value): @@ -3439,8 +3419,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def AugAssign_set_value(space, w_self, w_new_value): @@ -3489,8 +3468,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dest') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'dest') return space.wrap(w_self.dest) def Print_set_dest(space, w_self, w_new_value): @@ -3509,8 +3487,7 @@ def Print_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -3530,8 +3507,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'nl') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'nl') return space.wrap(w_self.nl) def Print_set_nl(space, w_self, w_new_value): @@ -3579,8 +3555,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def For_set_target(space, w_self, w_new_value): @@ -3603,8 +3578,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'iter') return space.wrap(w_self.iter) def For_set_iter(space, w_self, w_new_value): @@ -3623,8 +3597,7 @@ def For_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3640,8 +3613,7 @@ def For_get_orelse(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3690,8 +3662,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def While_set_test(space, w_self, w_new_value): @@ -3710,8 +3681,7 @@ def While_get_body(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3727,8 +3697,7 @@ def While_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3776,8 +3745,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def If_set_test(space, w_self, w_new_value): @@ -3796,8 +3764,7 @@ def If_get_body(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3813,8 +3780,7 @@ def If_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3862,8 +3828,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'context_expr') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'context_expr') return space.wrap(w_self.context_expr) def With_set_context_expr(space, w_self, w_new_value): @@ -3886,8 +3851,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'optional_vars') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'optional_vars') return space.wrap(w_self.optional_vars) def With_set_optional_vars(space, w_self, w_new_value): @@ -3906,8 +3870,7 @@ def With_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3954,8 +3917,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'type') return space.wrap(w_self.type) def Raise_set_type(space, w_self, w_new_value): @@ -3978,8 +3940,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'inst') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'inst') return space.wrap(w_self.inst) def Raise_set_inst(space, w_self, w_new_value): @@ -4002,8 +3963,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'tback') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'tback') return space.wrap(w_self.tback) def Raise_set_tback(space, w_self, w_new_value): @@ -4048,8 +4008,7 @@ def TryExcept_get_body(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -4065,8 +4024,7 @@ def TryExcept_get_handlers(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'handlers') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'handlers') if w_self.w_handlers is None: if w_self.handlers is None: list_w = [] @@ -4082,8 +4040,7 @@ def TryExcept_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -4128,8 +4085,7 @@ def TryFinally_get_body(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -4145,8 +4101,7 @@ def TryFinally_get_finalbody(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'finalbody') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'finalbody') if w_self.w_finalbody is None: if w_self.finalbody is None: list_w = [] @@ -4193,8 +4148,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def Assert_set_test(space, w_self, w_new_value): @@ -4217,8 +4171,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'msg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'msg') return space.wrap(w_self.msg) def Assert_set_msg(space, w_self, w_new_value): @@ -4262,8 +4215,7 @@ def Import_get_names(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4308,8 +4260,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'module') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'module') return space.wrap(w_self.module) def ImportFrom_set_module(space, w_self, w_new_value): @@ -4329,8 +4280,7 @@ def ImportFrom_get_names(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4350,8 +4300,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'level') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'level') return space.wrap(w_self.level) def ImportFrom_set_level(space, w_self, w_new_value): @@ -4399,8 +4348,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Exec_set_body(space, w_self, w_new_value): @@ -4423,8 +4371,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'globals') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'globals') return space.wrap(w_self.globals) def Exec_set_globals(space, w_self, w_new_value): @@ -4447,8 +4394,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'locals') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'locals') return space.wrap(w_self.locals) def Exec_set_locals(space, w_self, w_new_value): @@ -4493,8 +4439,7 @@ def Global_get_names(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4539,8 +4484,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Expr_set_value(space, w_self, w_new_value): @@ -4638,8 +4582,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def expr_set_lineno(space, w_self, w_new_value): @@ -4660,8 +4603,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def expr_set_col_offset(space, w_self, w_new_value): @@ -4691,8 +4633,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return boolop_to_class[w_self.op - 1]() def BoolOp_set_op(space, w_self, w_new_value): @@ -4711,8 +4652,7 @@ def BoolOp_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -4758,8 +4698,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'left') return space.wrap(w_self.left) def BinOp_set_left(space, w_self, w_new_value): @@ -4782,8 +4721,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return operator_to_class[w_self.op - 1]() def BinOp_set_op(space, w_self, w_new_value): @@ -4806,8 +4744,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'right') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'right') return space.wrap(w_self.right) def BinOp_set_right(space, w_self, w_new_value): @@ -4856,8 +4793,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return unaryop_to_class[w_self.op - 1]() def UnaryOp_set_op(space, w_self, w_new_value): @@ -4880,8 +4816,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'operand') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'operand') return space.wrap(w_self.operand) def UnaryOp_set_operand(space, w_self, w_new_value): @@ -4929,8 +4864,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') return space.wrap(w_self.args) def Lambda_set_args(space, w_self, w_new_value): @@ -4951,8 +4885,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Lambda_set_body(space, w_self, w_new_value): @@ -5000,8 +4933,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def IfExp_set_test(space, w_self, w_new_value): @@ -5024,8 +4956,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def IfExp_set_body(space, w_self, w_new_value): @@ -5048,8 +4979,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') return space.wrap(w_self.orelse) def IfExp_set_orelse(space, w_self, w_new_value): @@ -5094,8 +5024,7 @@ def Dict_get_keys(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keys') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'keys') if w_self.w_keys is None: if w_self.keys is None: list_w = [] @@ -5111,8 +5040,7 @@ def Dict_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -5155,8 +5083,7 @@ def Set_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -5201,8 +5128,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def ListComp_set_elt(space, w_self, w_new_value): @@ -5221,8 +5147,7 @@ def ListComp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5268,8 +5193,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def SetComp_set_elt(space, w_self, w_new_value): @@ -5288,8 +5212,7 @@ def SetComp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5335,8 +5258,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'key') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'key') return space.wrap(w_self.key) def DictComp_set_key(space, w_self, w_new_value): @@ -5359,8 +5281,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def DictComp_set_value(space, w_self, w_new_value): @@ -5379,8 +5300,7 @@ def DictComp_get_generators(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5427,8 +5347,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def GeneratorExp_set_elt(space, w_self, w_new_value): @@ -5447,8 +5366,7 @@ def GeneratorExp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5494,8 +5412,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Yield_set_value(space, w_self, w_new_value): @@ -5542,8 +5459,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'left') return space.wrap(w_self.left) def Compare_set_left(space, w_self, w_new_value): @@ -5562,8 +5478,7 @@ def Compare_get_ops(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ops') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ops') if w_self.w_ops is None: if w_self.ops is None: list_w = [] @@ -5579,8 +5494,7 @@ def Compare_get_comparators(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'comparators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'comparators') if w_self.w_comparators is None: if w_self.comparators is None: list_w = [] @@ -5628,8 +5542,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'func') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'func') return space.wrap(w_self.func) def Call_set_func(space, w_self, w_new_value): @@ -5648,8 +5561,7 @@ def Call_get_args(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') if w_self.w_args is None: if w_self.args is None: list_w = [] @@ -5665,8 +5577,7 @@ def Call_get_keywords(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keywords') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'keywords') if w_self.w_keywords is None: if w_self.keywords is None: list_w = [] @@ -5686,8 +5597,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'starargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'starargs') return space.wrap(w_self.starargs) def Call_set_starargs(space, w_self, w_new_value): @@ -5710,8 +5620,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 64: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwargs') return space.wrap(w_self.kwargs) def Call_set_kwargs(space, w_self, w_new_value): @@ -5764,8 +5673,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Repr_set_value(space, w_self, w_new_value): @@ -5812,8 +5720,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'n') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'n') return w_self.n def Num_set_n(space, w_self, w_new_value): @@ -5858,8 +5765,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 's') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 's') return w_self.s def Str_set_s(space, w_self, w_new_value): @@ -5904,8 +5810,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Attribute_set_value(space, w_self, w_new_value): @@ -5928,8 +5833,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'attr') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'attr') return space.wrap(w_self.attr) def Attribute_set_attr(space, w_self, w_new_value): @@ -5950,8 +5854,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Attribute_set_ctx(space, w_self, w_new_value): @@ -6000,8 +5903,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Subscript_set_value(space, w_self, w_new_value): @@ -6024,8 +5926,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'slice') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'slice') return space.wrap(w_self.slice) def Subscript_set_slice(space, w_self, w_new_value): @@ -6048,8 +5949,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Subscript_set_ctx(space, w_self, w_new_value): @@ -6098,8 +5998,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'id') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'id') return space.wrap(w_self.id) def Name_set_id(space, w_self, w_new_value): @@ -6120,8 +6019,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Name_set_ctx(space, w_self, w_new_value): @@ -6165,8 +6063,7 @@ def List_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -6186,8 +6083,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def List_set_ctx(space, w_self, w_new_value): @@ -6232,8 +6128,7 @@ def Tuple_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -6253,8 +6148,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Tuple_set_ctx(space, w_self, w_new_value): @@ -6303,8 +6197,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return w_self.value def Const_set_value(space, w_self, w_new_value): @@ -6422,8 +6315,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lower') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lower') return space.wrap(w_self.lower) def Slice_set_lower(space, w_self, w_new_value): @@ -6446,8 +6338,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'upper') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'upper') return space.wrap(w_self.upper) def Slice_set_upper(space, w_self, w_new_value): @@ -6470,8 +6361,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'step') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'step') return space.wrap(w_self.step) def Slice_set_step(space, w_self, w_new_value): @@ -6516,8 +6406,7 @@ def ExtSlice_get_dims(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dims') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'dims') if w_self.w_dims is None: if w_self.dims is None: list_w = [] @@ -6562,8 +6451,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Index_set_value(space, w_self, w_new_value): @@ -6834,8 +6722,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def comprehension_set_target(space, w_self, w_new_value): @@ -6858,8 +6745,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'iter') return space.wrap(w_self.iter) def comprehension_set_iter(space, w_self, w_new_value): @@ -6878,8 +6764,7 @@ def comprehension_get_ifs(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ifs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ifs') if w_self.w_ifs is None: if w_self.ifs is None: list_w = [] @@ -6926,8 +6811,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def excepthandler_set_lineno(space, w_self, w_new_value): @@ -6948,8 +6832,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def excepthandler_set_col_offset(space, w_self, w_new_value): @@ -6979,8 +6862,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'type') return space.wrap(w_self.type) def ExceptHandler_set_type(space, w_self, w_new_value): @@ -7003,8 +6885,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def ExceptHandler_set_name(space, w_self, w_new_value): @@ -7023,8 +6904,7 @@ def ExceptHandler_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -7067,8 +6947,7 @@ def arguments_get_args(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') if w_self.w_args is None: if w_self.args is None: list_w = [] @@ -7088,8 +6967,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'vararg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'vararg') return space.wrap(w_self.vararg) def arguments_set_vararg(space, w_self, w_new_value): @@ -7113,8 +6991,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwarg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwarg') return space.wrap(w_self.kwarg) def arguments_set_kwarg(space, w_self, w_new_value): @@ -7134,8 +7011,7 @@ def arguments_get_defaults(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'defaults') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'defaults') if w_self.w_defaults is None: if w_self.defaults is None: list_w = [] @@ -7184,8 +7060,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'arg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'arg') return space.wrap(w_self.arg) def keyword_set_arg(space, w_self, w_new_value): @@ -7206,8 +7081,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def keyword_set_value(space, w_self, w_new_value): @@ -7255,8 +7129,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def alias_set_name(space, w_self, w_new_value): @@ -7277,8 +7150,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'asname') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'asname') return space.wrap(w_self.asname) def alias_set_asname(space, w_self, w_new_value): diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -409,8 +409,7 @@ self.emit(" if w_obj is not None:", 1) self.emit(" return w_obj", 1) self.emit("if not w_self.initialization_state & %s:" % (flag,), 1) - self.emit("typename = space.type(w_self).getname(space)", 2) - self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%s' object has no attribute '%%s'\", typename, '%s')" % + self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%T' object has no attribute '%%s'\", w_self, '%s')" % (field.name,), 2) if field.seq: self.emit("if w_self.w_%s is None:" % (field.name,), 1) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -61,10 +61,9 @@ return False def setdict(self, space, w_dict): - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "attribute '__dict__' of %s objects " - "is not writable", typename) + "attribute '__dict__' of %T objects " + "is not writable", self) # to be used directly only by space.type implementations def getclass(self, space): @@ -124,9 +123,8 @@ classname = '?' else: classname = wrappable_class_name(RequiredClass) - msg = "'%s' object expected, got '%s' instead" - raise operationerrfmt(space.w_TypeError, msg, - classname, self.getclass(space).getname(space)) + msg = "'%s' object expected, got '%T' instead" + raise operationerrfmt(space.w_TypeError, msg, classname, self) # used by _weakref implemenation @@ -134,9 +132,8 @@ return None def setweakref(self, space, weakreflifeline): - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "cannot create weak reference to '%s' object", typename) + "cannot create weak reference to '%T' object", self) def delweakref(self): pass @@ -226,18 +223,15 @@ def int(self, space): w_impl = space.lookup(self, '__int__') if w_impl is None: - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "unsupported operand type for int(): '%s'", - typename) + "unsupported operand type for int(): '%T'", self) w_result = space.get_and_call_function(w_impl, self) if (space.isinstance_w(w_result, space.w_int) or space.isinstance_w(w_result, space.w_long)): return w_result - typename = space.type(w_result).getname(space) - msg = "__int__ returned non-int (type '%s')" - raise operationerrfmt(space.w_TypeError, msg, typename) + msg = "__int__ returned non-int (type '%T')" + raise operationerrfmt(space.w_TypeError, msg, w_result) def __spacebind__(self, space): return self @@ -749,10 +743,9 @@ if can_be_None and self.is_none(w_obj): return None if not isinstance(w_obj, RequiredClass): # or obj is None - msg = "'%s' object expected, got '%s' instead" + msg = "'%s' object expected, got '%T' instead" raise operationerrfmt(self.w_TypeError, msg, - wrappable_class_name(RequiredClass), - w_obj.getclass(self).getname(self)) + wrappable_class_name(RequiredClass), w_obj) return w_obj interp_w._annspecialcase_ = 'specialize:arg(1)' @@ -1221,9 +1214,8 @@ except OperationError, err: if objdescr is None or not err.match(self, self.w_TypeError): raise - msg = "%s must be an integer, not %s" - raise operationerrfmt(self.w_TypeError, msg, - objdescr, self.type(w_obj).getname(self)) + msg = "%s must be an integer, not %T" + raise operationerrfmt(self.w_TypeError, msg, objdescr, w_obj) try: index = self.int_w(w_index) except OperationError, err: @@ -1237,9 +1229,8 @@ return sys.maxint else: raise operationerrfmt( - w_exception, - "cannot fit '%s' into an index-sized " - "integer", self.type(w_obj).getname(self)) + w_exception, "cannot fit '%T' into an index-sized integer", + w_obj) else: return index diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -915,10 +915,9 @@ w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") if w_enter is None or w_descr is None: - typename = self.space.type(w_manager).getname(self.space) raise operationerrfmt(self.space.w_AttributeError, - "'%s' object is not a context manager" - " (no __enter__/__exit__ method)", typename) + "'%T' object is not a context manager" + " (no __enter__/__exit__ method)", w_manager) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) w_result = self.space.get_and_call_function(w_enter, w_manager) diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -553,12 +553,9 @@ def typecheck(self, space, w_obj): if not space.isinstance_w(w_obj, self.w_cls): - raise operationerrfmt(space.w_TypeError, - "descriptor '%s' for '%s'" - " objects doesn't apply to '%s' object", - self.name, - self.w_cls.name, - space.type(w_obj).getname(space)) + m = "descriptor '%s' for '%s' objects doesn't apply to '%T' object" + raise operationerrfmt(space.w_TypeError, m, + self.name, self.w_cls.name, w_obj) def descr_member_get(self, space, w_obj, w_cls=None): """member.__get__(obj[, type]) -> value @@ -627,10 +624,8 @@ def descr_get_dict(space, w_obj): w_dict = w_obj.getdict(space) if w_dict is None: - typename = space.type(w_obj).getname(space) - raise operationerrfmt(space.w_TypeError, - "descriptor '__dict__' doesn't apply to" - " '%s' objects", typename) + msg = "descriptor '__dict__' doesn't apply to '%T' objects" + raise operationerrfmt(space.w_TypeError, msg, w_obj) return w_dict def descr_set_dict(space, w_obj, w_dict): diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -10,10 +10,8 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space) - raise operationerrfmt(space.w_TypeError, - "argument %s must be %s, not %s", - argument, expected, type_name) + raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %T", + argument, expected, w_obj) def unwrap_attr(space, w_attr): try: diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -27,8 +27,8 @@ # if not space.is_true(space.callable(w_callable)): raise operationerrfmt(space.w_TypeError, - "expected a callable object, not %s", - space.type(w_callable).getname(space)) + "expected a callable object, not %T", + w_callable) self.w_callable = w_callable # fresult = self.getfunctype().ctitem 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 @@ -54,8 +54,8 @@ else: raise operationerrfmt(space.w_TypeError, "argument %d passed in the variadic part " - "needs to be a cdata object (got %s)", - i + 1, space.type(w_obj).getname(space)) + "needs to be a cdata object (got %T)", + i + 1, w_obj) fvarargs[i] = ct ctypefunc = instantiate(W_CTypeFunc) ctypefunc.space = space 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 @@ -88,8 +88,7 @@ else: return operationerrfmt(space.w_TypeError, "initializer for ctype '%s' must be a %s, " - "not %s", self.name, expected, - space.type(w_got).getname(space)) + "not %T", self.name, expected, w_got) def _cannot_index(self): space = self.space diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -218,9 +218,8 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def xmlcharrefreplace_errors(space, w_exc): check_exception(space, w_exc) @@ -239,9 +238,8 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def backslashreplace_errors(space, w_exc): check_exception(space, w_exc) @@ -272,9 +270,8 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def register_builtin_error_handlers(space): "NOT_RPYTHON" diff --git a/pypy/module/_io/interp_bytesio.py b/pypy/module/_io/interp_bytesio.py --- a/pypy/module/_io/interp_bytesio.py +++ b/pypy/module/_io/interp_bytesio.py @@ -138,10 +138,8 @@ if space.len_w(w_state) != 3: raise operationerrfmt(space.w_TypeError, - "%s.__setstate__ argument should be 3-tuple, got %s", - space.type(self).getname(space), - space.type(w_state).getname(space) - ) + "%T.__setstate__ argument should be 3-tuple, got %T", + self, w_state) w_content, w_pos, w_dict = space.unpackiterable(w_state, 3) self.truncate(0) self.write_w(space, w_content) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -163,8 +163,8 @@ if not space.isinstance_w(w_readahead, space.w_str): raise operationerrfmt( space.w_IOError, - "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space)) + "peek() should have returned a bytes object, not '%T'", + w_readahead) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -189,8 +189,8 @@ if not space.isinstance_w(w_read, space.w_str): raise operationerrfmt( space.w_IOError, - "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space)) + "peek() should have returned a bytes object, not '%T'", + w_read) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -71,10 +71,8 @@ # backwards-compatibility if not space.isinstance_w(w_state, space.w_tuple) or space.len_w(w_state) < 4: raise operationerrfmt(space.w_TypeError, - "%s.__setstate__ argument should be a 4-tuple, got %s", - space.type(self).getname(space), - space.type(w_state).getname(space) - ) + "%T.__setstate__ argument should be a 4-tuple, got %T", + self, w_state) w_initval, w_readnl, w_pos, w_dict = space.unpackiterable(w_state, 4) # Initialize state self.descr_init(space, w_initval, w_readnl) @@ -98,9 +96,8 @@ if not space.is_w(w_dict, space.w_None): if not space.isinstance_w(w_dict, space.w_dict): raise operationerrfmt(space.w_TypeError, - "fourth item of state should be a dict, got a %s", - space.type(w_dict).getname(space) - ) + "fourth item of state should be a dict, got a %T", + w_dict) # Alternatively, we could replace the internal dictionary # completely. However, it seems more practical to just update it. space.call_method(self.w_dict, "update", w_dict) @@ -129,8 +126,8 @@ def write_w(self, space, w_obj): if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, - "unicode argument expected, got '%s'", - space.type(w_obj).getname(space)) + "unicode argument expected, got '%T'", + w_obj) self._check_closed(space) orig_size = space.len_w(w_obj) 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 @@ -31,9 +31,8 @@ try: name = space.str_w(l_w[0]) except OperationError: - raise OperationError(space.w_TypeError, space.wrap( - "structure field name must be string not %s" % - space.type(l_w[0]).getname(space))) + raise operationerrfmt(space.w_TypeError, + "structure field name must be string not %T", l_w[0]) tp = unpack_shape_with_length(space, l_w[1]) if len_l == 3: diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -1,6 +1,6 @@ import sys -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rarithmetic import r_singlefloat @@ -430,9 +430,8 @@ offset = capi.c_base_offset(space, w_obj.cppclass, self.cppclass, rawobject, 1) obj_address = capi.direct_ptradd(rawobject, offset) return rffi.cast(capi.C_OBJECT, obj_address) - raise OperationError(space.w_TypeError, - space.wrap("cannot pass %s as %s" % - (space.type(w_obj).getname(space, "?"), self.cppclass.name))) + raise operationerrfmt(space.w_TypeError, "cannot pass %T as %s", + w_obj, self.cppclass.name) def convert_argument(self, space, w_obj, address, call_local): x = rffi.cast(rffi.VOIDPP, address) diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -153,8 +153,9 @@ is the equivalent of the Python statement o[i] = v. This function does not steal a reference to v.""" if PyDict_Check(space, w_o) or not PySequence_Check(space, w_o): - raise operationerrfmt(space.w_TypeError, "'%s' object does not support item assignment", - space.type(w_o).getname(space)) + raise operationerrfmt(space.w_TypeError, + "'%T' object does not support item assignment", + w_o) space.setitem(w_o, space.wrap(i), w_v) return 0 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 @@ -274,11 +274,9 @@ if not space.is_true(space.issubtype(space.type(w_self), space.type(w_other))): - raise OperationError(space.w_TypeError, space.wrap( - "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'" % - (space.type(w_self).getname(space), - space.type(w_self).getname(space), - space.type(w_other).getname(space)))) + raise operationerrfmt(space.w_TypeError, + "%T.__cmp__(x,y) requires y to be a '%T', not a '%T'", + w_self, w_self, w_other) return space.wrap(generic_cpy_call(space, func_target, w_self, w_other)) diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -1,7 +1,7 @@ import sys from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import (TypeDef, GetSetProperty, interp_attrproperty, interp_attrproperty_w) @@ -401,10 +401,8 @@ return dtype if w_dtype is dtype.w_box_type: return dtype - typename = space.type(w_dtype).getname(space) - raise OperationError(space.w_TypeError, space.wrap( - "data type not understood (value of type " + - "%s not expected here)" % typename)) + msg = "data type not understood (value of type %T not expected here)" + raise operationerrfmt(space.w_TypeError, msg, w_dtype) W_Dtype.typedef = TypeDef("dtype", __module__ = "numpypy", diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py --- a/pypy/module/oracle/interp_variable.py +++ b/pypy/module/oracle/interp_variable.py @@ -2,7 +2,7 @@ from pypy.interpreter.typedef import TypeDef from pypy.interpreter.typedef import interp_attrproperty from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rarithmetic import ovfcheck @@ -1486,10 +1486,9 @@ varType, size, _ = typeByValue(space, w_element, numElements) return varType, size, len(elements_w) - raise OperationError( - moduledict.w_NotSupportedError, - space.wrap("Variable_TypeByValue(): unhandled data type %s" % - (space.type(w_value).getname(space),))) + raise operationerrfmt(moduledict.w_NotSupportedError, + "Variable_TypeByValue(): unhandled data type %T", + w_value) def newByInputTypeHandler(space, cursor, w_inputTypeHandler, w_value, numElements): w_var = space.call(w_inputTypeHandler, diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from rpython.rlib import rgc, jit from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rtyper.tool import rffi_platform @@ -801,11 +801,10 @@ elif space.isinstance_w(w_encoding, space.w_str): encoding = space.str_w(w_encoding) else: - type_name = space.type(w_encoding).getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap('ParserCreate() argument 1 must be string or None,' - ' not %s' % (type_name,))) + 'ParserCreate() argument 1 must be string or None, not %T', + w_encoding) if space.is_none(w_namespace_separator): namespace_separator = 0 @@ -821,11 +820,10 @@ space.wrap('namespace_separator must be at most one character,' ' omitted, or None')) else: - type_name = space.type(w_namespace_separator).getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap('ParserCreate() argument 2 must be string or None,' - ' not %s' % (type_name,))) + 'ParserCreate() argument 2 must be string or None, not %T', + w_namespace_separator) # Explicitly passing None means no interning is desired. # Not passing anything means that a new dictionary is used. diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -52,16 +52,14 @@ list_iter._annspecialcase_ = 'specialize:memo' def raiseattrerror(space, w_obj, name, w_descr=None): - w_type = space.type(w_obj) - typename = w_type.getname(space) if w_descr is None: raise operationerrfmt(space.w_AttributeError, - "'%s' object has no attribute '%s'", - typename, name) + "'%T' object has no attribute '%s'", + w_obj, name) else: raise operationerrfmt(space.w_AttributeError, - "'%s' object attribute '%s' is read-only", - typename, name) + "'%T' object attribute '%s' is read-only", + w_obj, name) # Helpers for old-style and mix-style mixup @@ -162,10 +160,9 @@ return w_obj.call_args(args) w_descr = space.lookup(w_obj, '__call__') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object is not callable", - typename) + "'%T' object is not callable", + w_obj) return space.get_and_call_args(w_descr, w_obj, args) def get(space, w_descr, w_obj, w_type=None): @@ -179,19 +176,17 @@ def set(space, w_descr, w_obj, w_val): w_set = space.lookup(w_descr, '__set__') if w_set is None: - typename = space.type(w_descr).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object is not a descriptor with set", - typename) + "'%T' object is not a descriptor with set", + w_descr) return space.get_and_call_function(w_set, w_descr, w_obj, w_val) def delete(space, w_descr, w_obj): w_delete = space.lookup(w_descr, '__delete__') if w_delete is None: - typename = space.type(w_descr).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object is not a descriptor with delete", - typename) + "'%T' object is not a descriptor with delete", + w_descr) return space.get_and_call_function(w_delete, w_descr, w_obj) def getattr(space, w_obj, w_name): @@ -215,19 +210,17 @@ def setattr(space, w_obj, w_name, w_val): w_descr = space.lookup(w_obj, '__setattr__') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_AttributeError, - "'%s' object is readonly", - typename) + "'%T' object is readonly", + w_obj) return space.get_and_call_function(w_descr, w_obj, w_name, w_val) def delattr(space, w_obj, w_name): w_descr = space.lookup(w_obj, '__delattr__') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_AttributeError, - "'%s' object does not support attribute removal", - typename) + "'%T' object does not support attribute removal", + w_obj) return space.get_and_call_function(w_descr, w_obj, w_name) def is_true(space, w_obj): @@ -264,9 +257,8 @@ def len(space, w_obj): w_descr = space.lookup(w_obj, '__len__') if w_descr is None: - name = space.type(w_obj).getname(space) - msg = "'%s' has no length" % (name,) - raise OperationError(space.w_TypeError, space.wrap(msg)) + raise operationerrfmt(space.w_TypeError, "'%T' has no length", + w_obj) w_res = space.get_and_call_function(w_descr, w_obj) return space.wrap(space._check_len_result(w_res)) @@ -283,10 +275,9 @@ if w_descr is None: w_descr = space.lookup(w_obj, '__getitem__') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object is not iterable", - typename) + "'%T' object is not iterable", + w_obj) return space.newseqiter(w_obj) w_iter = space.get_and_call_function(w_descr, w_obj) w_next = space.lookup(w_iter, 'next') @@ -298,37 +289,34 @@ def next(space, w_obj): w_descr = space.lookup(w_obj, 'next') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object is not an iterator", - typename) + "'%T' object is not an iterator", + w_obj) return space.get_and_call_function(w_descr, w_obj) def getitem(space, w_obj, w_key): w_descr = space.lookup(w_obj, '__getitem__') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object is not subscriptable", - typename) + "'%T' object is not subscriptable", + w_obj) return space.get_and_call_function(w_descr, w_obj, w_key) def setitem(space, w_obj, w_key, w_val): w_descr = space.lookup(w_obj, '__setitem__') if w_descr is None: - typename = space.type(w_obj).getname(space) - raise operationerrfmt(space.w_TypeError, - "'%s' object does not support item assignment", - typename) + raise operationerrfmt( + space.w_TypeError, + "'%T' object does not support item assignment", + w_obj) return space.get_and_call_function(w_descr, w_obj, w_key, w_val) def delitem(space, w_obj, w_key): w_descr = space.lookup(w_obj, '__delitem__') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object does not support item deletion", - typename) + "'%T' object does not support item deletion", + w_obj) return space.get_and_call_function(w_descr, w_obj, w_key) def getslice(space, w_obj, w_start, w_stop): @@ -358,17 +346,13 @@ def format(space, w_obj, w_format_spec): w_descr = space.lookup(w_obj, '__format__') if w_descr is None: - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' object does not define __format__", - typename) + "'%T' object does not define __format__", + w_obj) w_res = space.get_and_call_function(w_descr, w_obj, w_format_spec) if not space.isinstance_w(w_res, space.w_basestring): - typename = space.type(w_obj).getname(space) - restypename = space.type(w_res).getname(space) - raise operationerrfmt(space.w_TypeError, - "%s.__format__ must return string or unicode, not %s", - typename, restypename) + msg = "%T.__format__ must return string or unicode, not %T" + raise operationerrfmt(space.w_TypeError, msg, w_obj, w_res) return w_res def pow(space, w_obj1, w_obj2, w_obj3): @@ -444,9 +428,8 @@ # obscure circumstances. return default_identity_hash(space, w_obj) if space.is_w(w_hash, space.w_None): - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "'%s' objects are unhashable", typename) From noreply at buildbot.pypy.org Sun May 26 00:35:55 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 26 May 2013 00:35:55 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: utilize %N everywhere Message-ID: <20130525223555.1FE981C12FE@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64563:6ee585ed9ea5 Date: 2013-05-25 15:34 -0700 http://bitbucket.org/pypy/pypy/changeset/6ee585ed9ea5/ Log: utilize %N everywhere diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -225,10 +225,9 @@ def _exception_getclass(self, space, w_inst): w_type = space.exception_getclass(w_inst) if not space.exception_is_valid_class_w(w_type): - typename = w_type.getname(space) msg = ("exceptions must be old-style classes or derived " - "from BaseException, not %s") - raise operationerrfmt(space.w_TypeError, msg, typename) + "from BaseException, not %N") + raise operationerrfmt(space.w_TypeError, msg, w_type) return w_type def write_unraisable(self, space, where, w_object=None, diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -69,9 +69,9 @@ _attrs_ = () def descr__new__(space, w_subtype, __args__): - raise operationerrfmt(space.w_TypeError, "cannot create '%s' instances", - w_subtype.getname(space, '?') - ) + raise operationerrfmt(space.w_TypeError, + "cannot create '%N' instances", + w_subtype) def get_dtype(self, space): return self._get_dtype(space) diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -669,7 +669,7 @@ def _make_binop_impl(symbol, specialnames): left, right = specialnames - errormsg = "unsupported operand type(s) for %s: '%%s' and '%%s'" % ( + errormsg = "unsupported operand type(s) for %s: '%%N' and '%%N'" % ( symbol.replace('%', '%%'),) def binop_impl(space, w_obj1, w_obj2): @@ -710,10 +710,7 @@ w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1) if w_res is not None: return w_res - typename1 = w_typ1.getname(space) - typename2 = w_typ2.getname(space) - raise operationerrfmt(space.w_TypeError, errormsg, - typename1, typename2) + raise operationerrfmt(space.w_TypeError, errormsg, w_typ1, w_typ2) return func_with_new_name(binop_impl, "binop_%s_impl"%left.strip('_')) diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py --- a/pypy/objspace/std/objecttype.py +++ b/pypy/objspace/std/objecttype.py @@ -44,8 +44,8 @@ w_obj.setclass(space, w_newcls) else: raise operationerrfmt(space.w_TypeError, - "__class__ assignment: '%s' object layout differs from '%s'", - w_oldcls.getname(space), w_newcls.getname(space)) + "__class__ assignment: '%N' object layout differs from '%N'", + w_oldcls, w_newcls) app = gateway.applevel(""" diff --git a/pypy/objspace/std/transparent.py b/pypy/objspace/std/transparent.py --- a/pypy/objspace/std/transparent.py +++ b/pypy/objspace/std/transparent.py @@ -58,8 +58,7 @@ if w_lookup == k: return v(space, w_type, w_controller) raise operationerrfmt(space.w_TypeError, - "'%s' object could not be wrapped", - w_type.getname(space)) + "'%N' object could not be wrapped", w_type) def register_proxyable(space, cls): tpdef = cls.typedef diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -686,11 +686,9 @@ newlayout = w_newbestbase.get_full_instance_layout() if oldlayout != newlayout: - raise operationerrfmt(space.w_TypeError, - "__bases__ assignment: '%s' object layout" - " differs from '%s'", - w_newbestbase.getname(space), - w_oldbestbase.getname(space)) + msg = "__bases__ assignment: '%N' object layout differs from '%N'" + raise operationerrfmt(space.w_TypeError, msg, + w_newbestbase, w_oldbestbase) # invalidate the version_tag of all the current subclasses w_type.mutated(None) @@ -1202,9 +1200,8 @@ candidate = orderlists[-1][0] if candidate in orderlists[-1][1:]: # explicit error message for this specific case - raise operationerrfmt(space.w_TypeError, - "duplicate base class '%s'", - candidate.getname(space)) + raise operationerrfmt(space.w_TypeError, "duplicate base class '%N'", + candidate) while candidate not in cycle: cycle.append(candidate) nextblockinglist = mro_blockinglist(candidate, orderlists) From noreply at buildbot.pypy.org Sun May 26 01:20:50 2013 From: noreply at buildbot.pypy.org (r3m0t) Date: Sun, 26 May 2013 01:20:50 +0200 (CEST) Subject: [pypy-commit] pypy default: add missing stub methods to io.IOBase Message-ID: <20130525232050.D13571C0DC9@cobra.cs.uni-duesseldorf.de> Author: Tomer Chachamu Branch: Changeset: r64564:2780a755bf49 Date: 2013-05-10 01:00 +0100 http://bitbucket.org/pypy/pypy/changeset/2780a755bf49/ Log: add missing stub methods to io.IOBase diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -49,6 +49,11 @@ self.streamholder = None # needed by AutoFlusher get_autoflusher(space).add(self) + def _unsupportedoperation(self, space, message): + w_exc = space.getattr(space.getbuiltinmodule('_io'), + space.wrap('UnsupportedOperation')) + raise OperationError(w_exc, space.wrap(message)) + def getdict(self, space): return self.w_dict @@ -144,6 +149,15 @@ def seekable_w(self, space): return space.w_False + def seek_w(self, space, w_offset, w_whence=None): + self._unsupportedoperation(space, "seek") + + def truncate_w(self, space, w_size=None): + self._unsupportedoperation(space, "truncate") + + def fileno_w(self, space): + self._unsupportedoperation(space, "fileno") + # ______________________________________________________________ def readline_w(self, space, w_limit=None): @@ -253,6 +267,11 @@ readable = interp2app(W_IOBase.readable_w), writable = interp2app(W_IOBase.writable_w), seekable = interp2app(W_IOBase.seekable_w), + + seek = interp2app(W_IOBase.seek_w), + truncate = interp2app(W_IOBase.truncate_w), + fileno = interp2app(W_IOBase.fileno_w), + _checkReadable = interp2app(check_readable_w), _checkWritable = interp2app(check_writable_w), _checkSeekable = interp2app(check_seekable_w), diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -196,11 +196,6 @@ def __init__(self, space): W_IOBase.__init__(self, space) - def _unsupportedoperation(self, space, message): - w_exc = space.getattr(space.getbuiltinmodule('_io'), - space.wrap('UnsupportedOperation')) - raise OperationError(w_exc, space.wrap(message)) - def read_w(self, space, w_size=None): self._unsupportedoperation(space, "read") diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -16,7 +16,7 @@ class MyFile(io.BufferedIOBase): def __init__(self, filename): pass - MyFile("file") + f = MyFile("file") def test_openclose(self): import io @@ -43,6 +43,16 @@ import _io e = _io.UnsupportedOperation("seek") + def test_default_implementations(self): + import io + class MyFile(io.BufferedIOBase): + def __init__(self, filename): + pass + f = MyFile("file") + raises(io.UnsupportedOperation, f.seek, 0) + raises(io.UnsupportedOperation, f.fileno) + raises(io.UnsupportedOperation, f.truncate) + def test_blockingerror(self): import _io try: diff --git a/pypy/module/_io/test/test_textio.py b/pypy/module/_io/test/test_textio.py --- a/pypy/module/_io/test/test_textio.py +++ b/pypy/module/_io/test/test_textio.py @@ -26,6 +26,17 @@ assert t.readable() assert t.seekable() + def test_textiobase(self): + import _io + class TextIOBad(_io._TextIOBase): + def __init__(self): + pass + txt = TextIOBad() + raises(_io.UnsupportedOperation, txt.read) + raises(_io.UnsupportedOperation, txt.seek, 0) + raises(_io.UnsupportedOperation, txt.readline) + raises(_io.UnsupportedOperation, txt.detach) + def test_unreadable(self): import _io class UnReadable(_io.BytesIO): From noreply at buildbot.pypy.org Sun May 26 01:20:52 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 26 May 2013 01:20:52 +0200 (CEST) Subject: [pypy-commit] pypy default: rearrange to match py3k which already implemented these Message-ID: <20130525232052.8FCFF1C0DC9@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64565:d7ce4a47ae50 Date: 2013-05-25 16:02 -0700 http://bitbucket.org/pypy/pypy/changeset/d7ce4a47ae50/ Log: rearrange to match py3k which already implemented these diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -16,6 +16,11 @@ else: return space.int_w(w_size) +def unsupported(space, message): + w_exc = space.getattr(space.getbuiltinmodule('_io'), + space.wrap('UnsupportedOperation')) + return OperationError(w_exc, space.wrap(message)) + # May be called with any object def check_readable_w(space, w_obj): if not space.is_true(space.call_method(w_obj, 'readable')): @@ -49,11 +54,6 @@ self.streamholder = None # needed by AutoFlusher get_autoflusher(space).add(self) - def _unsupportedoperation(self, space, message): - w_exc = space.getattr(space.getbuiltinmodule('_io'), - space.wrap('UnsupportedOperation')) - raise OperationError(w_exc, space.wrap(message)) - def getdict(self, space): return self.w_dict @@ -91,6 +91,9 @@ # attribute as returned by whatever subclass. return self.__IOBase_closed + def _unsupportedoperation(self, space, message): + raise unsupported(space, message) + def _check_closed(self, space, message=None): if message is None: message = "I/O operation on closed file" @@ -116,9 +119,18 @@ space.w_ValueError, space.wrap("I/O operation on closed file")) + def seek_w(self, space, w_offset, w_whence=None): + self._unsupportedoperation(space, "seek") + def tell_w(self, space): return space.call_method(self, "seek", space.wrap(0), space.wrap(1)) + def truncate_w(self, space, w_size=None): + self._unsupportedoperation(space, "truncate") + + def fileno_w(self, space): + self._unsupportedoperation(space, "fileno") + def enter_w(self, space): self._check_closed(space) return space.wrap(self) @@ -149,15 +161,6 @@ def seekable_w(self, space): return space.w_False - def seek_w(self, space, w_offset, w_whence=None): - self._unsupportedoperation(space, "seek") - - def truncate_w(self, space, w_size=None): - self._unsupportedoperation(space, "truncate") - - def fileno_w(self, space): - self._unsupportedoperation(space, "fileno") - # ______________________________________________________________ def readline_w(self, space, w_limit=None): @@ -262,16 +265,15 @@ next = interp2app(W_IOBase.next_w), close = interp2app(W_IOBase.close_w), flush = interp2app(W_IOBase.flush_w), + seek = interp2app(W_IOBase.seek_w), tell = interp2app(W_IOBase.tell_w), + truncate = interp2app(W_IOBase.truncate_w), + fileno = interp2app(W_IOBase.fileno_w), isatty = interp2app(W_IOBase.isatty_w), readable = interp2app(W_IOBase.readable_w), writable = interp2app(W_IOBase.writable_w), seekable = interp2app(W_IOBase.seekable_w), - seek = interp2app(W_IOBase.seek_w), - truncate = interp2app(W_IOBase.truncate_w), - fileno = interp2app(W_IOBase.fileno_w), - _checkReadable = interp2app(check_readable_w), _checkWritable = interp2app(check_writable_w), _checkSeekable = interp2app(check_seekable_w), diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -16,7 +16,7 @@ class MyFile(io.BufferedIOBase): def __init__(self, filename): pass - f = MyFile("file") + MyFile("file") def test_openclose(self): import io @@ -44,14 +44,11 @@ e = _io.UnsupportedOperation("seek") def test_default_implementations(self): - import io - class MyFile(io.BufferedIOBase): - def __init__(self, filename): - pass - f = MyFile("file") - raises(io.UnsupportedOperation, f.seek, 0) - raises(io.UnsupportedOperation, f.fileno) - raises(io.UnsupportedOperation, f.truncate) + import _io + file = _io._IOBase() + raises(_io.UnsupportedOperation, file.seek, 0, 1) + raises(_io.UnsupportedOperation, file.fileno) + raises(_io.UnsupportedOperation, file.truncate) def test_blockingerror(self): import _io diff --git a/pypy/module/_io/test/test_textio.py b/pypy/module/_io/test/test_textio.py --- a/pypy/module/_io/test/test_textio.py +++ b/pypy/module/_io/test/test_textio.py @@ -26,16 +26,13 @@ assert t.readable() assert t.seekable() - def test_textiobase(self): + def test_default_implementations(self): import _io - class TextIOBad(_io._TextIOBase): - def __init__(self): - pass - txt = TextIOBad() - raises(_io.UnsupportedOperation, txt.read) - raises(_io.UnsupportedOperation, txt.seek, 0) - raises(_io.UnsupportedOperation, txt.readline) - raises(_io.UnsupportedOperation, txt.detach) + file = _io._TextIOBase() + raises(_io.UnsupportedOperation, file.read) + raises(_io.UnsupportedOperation, file.seek, 0) + raises(_io.UnsupportedOperation, file.readline) + raises(_io.UnsupportedOperation, file.detach) def test_unreadable(self): import _io From noreply at buildbot.pypy.org Sun May 26 01:20:54 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 26 May 2013 01:20:54 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130525232054.5229B1C0DC9@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64566:55f0c664d6b0 Date: 2013-05-25 16:19 -0700 http://bitbucket.org/pypy/pypy/changeset/55f0c664d6b0/ Log: merge default diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -166,8 +166,7 @@ if self is StructOrUnion: return if '_fields_' not in self.__dict__: - self._fields_ = [] - _set_shape(self, [], self._is_union) + self._fields_ = [] # As a side-effet, this also sets the ffishape. __setattr__ = struct_setattr diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -136,7 +136,7 @@ def tell_w(self, space): return space.call_method(self, "seek", space.wrap(0), space.wrap(1)) - def truncate_w(self, space): + def truncate_w(self, space, w_size=None): self._unsupportedoperation(space, "truncate") def fileno_w(self, space): @@ -290,6 +290,7 @@ readable = interp2app(W_IOBase.readable_w), writable = interp2app(W_IOBase.writable_w), seekable = interp2app(W_IOBase.seekable_w), + _checkReadable = interp2app(check_readable_w), _checkWritable = interp2app(check_writable_w), _checkSeekable = interp2app(check_seekable_w), diff --git a/pypy/module/_io/test/test_textio.py b/pypy/module/_io/test/test_textio.py --- a/pypy/module/_io/test/test_textio.py +++ b/pypy/module/_io/test/test_textio.py @@ -26,6 +26,14 @@ assert t.readable() assert t.seekable() + def test_default_implementations(self): + import _io + file = _io._TextIOBase() + raises(_io.UnsupportedOperation, file.read) + raises(_io.UnsupportedOperation, file.seek, 0) + raises(_io.UnsupportedOperation, file.readline) + raises(_io.UnsupportedOperation, file.detach) + def test_isatty(self): import _io class Tty(_io.BytesIO): diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -46,11 +46,11 @@ self.name = name class FakeSpace(object): - w_ValueError = "ValueError" - w_TypeError = "TypeError" - w_IndexError = "IndexError" - w_OverflowError = "OverflowError" - w_NotImplementedError = "NotImplementedError" + w_ValueError = W_TypeObject("ValueError") + w_TypeError = W_TypeObject("TypeError") + w_IndexError = W_TypeObject("IndexError") + w_OverflowError = W_TypeObject("OverflowError") + w_NotImplementedError = W_TypeObject("NotImplementedError") w_None = None w_bool = W_TypeObject("bool") diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -239,6 +239,9 @@ pass pos = POSITION(1, 2) assert (pos.x, pos.y) == (1, 2) + # Try a second time, result may be different (cf. issue1498) + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) def test_invalid_field_types(self): From noreply at buildbot.pypy.org Sun May 26 12:09:45 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 12:09:45 +0200 (CEST) Subject: [pypy-commit] stmgc default: Untested, work in progress Message-ID: <20130526100945.6BBA51C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r8:26dca82e7423 Date: 2013-05-26 12:05 +0200 http://bitbucket.org/pypy/stmgc/changeset/26dca82e7423/ Log: Untested, work in progress diff --git a/c3/atomic_ops.h b/c3/atomic_ops.h --- a/c3/atomic_ops.h +++ b/c3/atomic_ops.h @@ -115,7 +115,7 @@ } while (1) #define spinlock_release(lock) \ - do { smp_wmb(); assert((lock) == 1); (lock) = 0; } while (0) + do { smp_wmb(); assert((lock) != 0); (lock) = 0; } while (0) #endif /* _SRCSTM_ATOMIC_OPS_ */ diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -314,6 +314,13 @@ struct tx_descriptor *d = thread_descriptor; assert(d->active >= 1); + /* must normalize the situation now, otherwise we risk that + LocalizePublic creates a new private version of a public + object that has got one, attached to the equivalent stolen + protected object */ + if (gcptrlist_size(&d->stolen_objects) > 0) + stmgc_normalize_stolen_objects(); + /* XXX optimize me based on common patterns */ R = HeadOfRevisionChainList(d, P); @@ -352,11 +359,9 @@ v = ACCESS_ONCE(R->h_revision); if (!(v & 1)) // "is a pointer", i.e. { // "has a more recent revision" - /* ... unless it is only a GCFLAG_NURSERY_MOVED, which may - only come from my thread's nursery; then look at the - moved-out object instead */ + /* ... unless it is a GCFLAG_STOLEN object */ abort();//XXX - if (R->h_tid & GCFLAG_NURSERY_MOVED) + if (R->h_tid & GCFLAG_STOLEN) { assert(is_young(R)); assert(!is_young((gcptr)v)); @@ -572,6 +577,7 @@ gcptr R = item->addr; revision_t v; retry: + assert(R->h_tid & GCFLAG_OLD); v = ACCESS_ONCE(R->h_revision); if (!(v & 1)) // "is a pointer", i.e. { // "has a more recent revision" @@ -642,6 +648,7 @@ assert(!(L->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)); assert(!(L->h_tid & GCFLAG_PREBUILT_ORIGINAL)); assert(!(L->h_tid & GCFLAG_NURSERY_MOVED)); + assert(!(L->h_tid & GCFLAG_STOLEN)); assert(L->h_revision != localrev); /* modified by AcquireLocks() */ #ifdef DUMP_EXTRA @@ -673,6 +680,7 @@ assert(!(R->h_tid & GCFLAG_PRIVATE_COPY)); assert(R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE); assert(!(R->h_tid & GCFLAG_NURSERY_MOVED)); + assert(!(R->h_tid & GCFLAG_STOLEN)); assert(!is_young(R)); assert(R->h_revision != localrev); @@ -757,6 +765,7 @@ UpdateChainHeads(d, cur_time, localrev); + stmgc_committed_transaction(d); d->num_commits++; d->active = 0; stm_stop_sharedlock(); diff --git a/c3/et.h b/c3/et.h --- a/c3/et.h +++ b/c3/et.h @@ -54,6 +54,9 @@ * GCFLAG_NURSERY_MOVED is used temporarily during minor collections. * * GCFLAG_OLD is set on old objects. + * + * GCFLAG_STOLEN is set of protected objects after we notice that they + * have been stolen. */ #define GCFLAG_PRIVATE_COPY (STM_FIRST_GCFLAG << 0) #define GCFLAG_VISITED (STM_FIRST_GCFLAG << 1) @@ -62,6 +65,7 @@ #define GCFLAG_WRITE_BARRIER (STM_FIRST_GCFLAG << 4) #define GCFLAG_NURSERY_MOVED (STM_FIRST_GCFLAG << 5) #define GCFLAG_OLD (STM_FIRST_GCFLAG << 6) +#define GCFLAG_STOLEN (STM_FIRST_GCFLAG << 7) /* this value must be reflected in PREBUILT_FLAGS in stmgc.h */ #define GCFLAG_PREBUILT (GCFLAG_VISITED | \ @@ -75,6 +79,7 @@ "WRITE_BARRIER", \ "NURSERY_MOVED", \ "OLD", \ + "STOLEN", \ NULL } /************************************************************/ diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -557,9 +557,9 @@ */ thread_descriptor = d; stm_local_revision = *d->local_revision_ref; - assert(stmgc_nursery_hiding(d, 0)); + assert(stmgc_nursery_hiding(0)); stmgc_minor_collect_no_abort(); - assert(stmgc_nursery_hiding(d, 1)); + assert(stmgc_nursery_hiding(1)); } } thread_descriptor = saved; diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -63,6 +63,8 @@ assert((obj->h_tid & GCFLAG_OLD) == 0); else assert((obj->h_tid & GCFLAG_OLD) == GCFLAG_OLD); + if (e != K_PROTECTED) + assert(!(obj->h_tid & GCFLAG_STOLEN)); return e; not_found: @@ -169,6 +171,14 @@ return localobj; } +static revision_t fetch_extra_word(gcptr L) +{ + size_t size = stmcb_size(L); + revision_t extra_word = *(revision_t *)(((char*)L) + size); + assert(extra_word & 1); /* "is not a pointer", should be a rev number */ + return extra_word; +} + void stmgc_start_transaction(struct tx_descriptor *d) { assert(!gcptrlist_size(&d->protected_with_private_copy)); @@ -179,6 +189,7 @@ } static void fix_new_public_to_protected_references(struct tx_descriptor *d); +static void normalize_stolen_objects(struct tx_descriptor *d); void stmgc_stop_transaction(struct tx_descriptor *d) { @@ -189,13 +200,19 @@ fix_new_public_to_protected_references(d); spinlock_acquire(d->collection_lock); + d->collection_lock = 'C'; /* Committing */ + if (gcptrlist_size(&d->stolen_objects) > 0) - abort(); //XXX XXX also is it fine if stolen_objects grows just after - spinlock_release(d->collection_lock); + normalize_stolen_objects(d); fprintf(stderr, "stop transaction\n"); } +void stmgc_committed_transaction(struct tx_descriptor *d) +{ + spinlock_release(d->collection_lock); +} + void stmgc_abort_transaction(struct tx_descriptor *d) { /* cancel the change to the h_revision done in LocalizeProtected() */ @@ -209,20 +226,22 @@ other thread is busy stealing (which includes reading the extra word immediately after private objects). */ - spinlock_acquire(d->collection_lock); + if (d->collection_lock != 'C') + spinlock_acquire(d->collection_lock); for (i = 0; i < size; i++) { gcptr R = items[i]; assert(dclassify(R) == K_PROTECTED); assert(!(R->h_revision & 1)); /* "is a pointer" */ gcptr L = (gcptr)R->h_revision; + + if (R->h_tid & GCFLAG_STOLEN) { /* ignore stolen objects */ + assert(dclassify(L) == K_PUBLIC); + continue; + } assert(dclassify(L) == K_PRIVATE); - size_t size = stmcb_size(R); - revision_t extra_word = *(revision_t *)(((char*)L) + size); - - assert(extra_word & 1); - R->h_revision = extra_word; + R->h_revision = fetch_extra_word(L); abort();//XXX } gcptrlist_clear(&d->protected_with_private_copy); @@ -251,8 +270,7 @@ # define recdump1(msg, obj) /* removed */ #endif -static inline gcptr create_old_object_copy(struct tx_descriptor *d, gcptr obj - _REASON(char *reason)) +static inline gcptr create_old_object_copy(gcptr obj _REASON(char *reason)) { assert(!(obj->h_tid & GCFLAG_NURSERY_MOVED)); assert(!(obj->h_tid & GCFLAG_VISITED)); @@ -335,7 +353,7 @@ } } /* case C */ - fresh_old_copy = create_old_object_copy(d, obj _REASON("visit")); + fresh_old_copy = create_old_object_copy(obj _REASON("visit")); obj->h_tid |= GCFLAG_NURSERY_MOVED; obj->h_revision = (revision_t)fresh_old_copy; @@ -410,14 +428,15 @@ assert(dclassify(R) == K_PROTECTED); assert(!(R->h_revision & 1)); /* "is a pointer" */ gcptr L = (gcptr)R->h_revision; + + if (R->h_tid & GCFLAG_STOLEN) { /* ignore stolen objects */ + assert(dclassify(L) == K_PUBLIC); + continue; + } assert(dclassify(L) == K_PRIVATE); /* we first detach the link, restoring the original R->h_revision */ - size_t size = stmcb_size(R); - revision_t extra_word = *(revision_t *)(((char*)L) + size); - - assert(extra_word & 1); - R->h_revision = extra_word; + R->h_revision = fetch_extra_word(L); /* then we turn the protected object in a public one */ R = young_object_becomes_old(d, R @@ -601,7 +620,7 @@ else { /* second case */ abort();//XXX - /* ... check + /* ABRT_COLLECT_MINOR ... check for stolen object */ } } @@ -686,6 +705,9 @@ /* acquire the "collection lock" first */ setup_minor_collect(d); + if (gcptrlist_size(&d->stolen_objects) > 0) + normalize_stolen_objects(d); + mark_protected_with_private_copy(d); mark_public_to_young(d); @@ -775,9 +797,10 @@ gcptrlist_insert(&d->private_old_pointing_to_young, obj); } -int stmgc_nursery_hiding(struct tx_descriptor *d, int hide) +int stmgc_nursery_hiding(int hide) { #ifdef _GC_DEBUG + struct tx_descriptor *d = thread_descriptor; if (hide) { stm_dbgmem_not_used(d->nursery, GC_NURSERY, 1); } @@ -808,101 +831,165 @@ /************************************************************/ -static gcptr extract_from_foreign_nursery(struct tx_descriptor *source_d, - gcptr L) +static gcptr extract_from_foreign_nursery(gcptr R) { - /* "Stealing": this function follows a chain of protected objects - in the foreign nursery of the thread 'source_d'. It copies the - last one outside the nursery, and return it. */ - gcptr L2, N; + /* "Stealing": this function follows a chain of protected objects in + the foreign nursery of the thread temporarily in + 'thread_descriptor'. It copies the last one outside the nursery, + and return it. */ + gcptr R2, N; revision_t source_local_rev, v; - source_local_rev = ACCESS_ONCE(*source_d->local_revision_ref); - v = ACCESS_ONCE(L->h_revision); + source_local_rev = stm_local_revision; + v = ACCESS_ONCE(R->h_revision); - /* check that L is a protected object */ - assert(!(L->h_tid & GCFLAG_OLD)); + /* check that R is a protected object */ + assert(!(R->h_tid & GCFLAG_OLD)); assert(v != source_local_rev); /* walk to the head of the chain in the foreign nursery */ while (!(v & 1)) { /* "is a pointer" */ - L2 = (gcptr)v; - v = ACCESS_ONCE(L2->h_revision); + R2 = (gcptr)v; + v = ACCESS_ONCE(R2->h_revision); if (v == source_local_rev) { - /* L->h_revision is a pointer, but the target is a private - object. We ignore private objects, so we stay at L; but - have to fetch L's real revision off-line from the extra - word that follows L2 */ - size_t size = stmcb_size(L2); - v = *(revision_t *)(((char*)L2) + size); - assert(v & 1); /* "is not a pointer" */ + /* R->h_revision is a pointer, but the target is a private + object. We ignore private objects, so we stay at R; but + have to fetch R's real revision off-line from the extra + word that follows R2 */ + v = fetch_extra_word(R2); break; } - else if (L2->h_tid & GCFLAG_OLD) { + else if (R2->h_tid & GCFLAG_OLD) { /* we find a public object again: easy case, just return it */ - return L2; + return R2; } else { /* the chain continues with another protected object, go on */ - L = L2; + R = R2; } } - /* L is now the protected object to move outside, with revision v. */ - N = create_old_object_copy(source_d, L _REASON("stolen copy")); + /* R is now the protected object to move outside, with revision v. */ + N = create_old_object_copy(R _REASON("stolen copy")); N->h_revision = v; - gcptrlist_insert2(&source_d->stolen_objects, L, N); + gcptrlist_insert2(&thread_descriptor->stolen_objects, R, N); - smp_wmb(); + /* there might be references in N going to protected objects. We + must fix them with stubs. */ + stmcb_trace(N, &create_yo_stubs); return N; } -void stmgc_public_to_foreign_protected(gcptr R) +void stmgc_public_to_foreign_protected(gcptr P) { - /* R is a public object, which contains in h_revision a pointer to a + /* P is a public object, which contains in h_revision a pointer to a protected object --- but it is protectd by another thread, i.e. it likely lives in a foreign nursery. We have to copy the object out ourselves. This is necessary: we can't simply wait for the other thread to do a minor collection, because it might be blocked in a system call or whatever. */ struct tx_descriptor *my_d = thread_descriptor; + revision_t my_local_rev = stm_local_revision; /* repeat the checks in the caller, to avoid passing more than one argument here */ - revision_t v = ACCESS_ONCE(R->h_revision); + revision_t v = ACCESS_ONCE(P->h_revision); assert(!(v & 1)); /* "is a pointer" */ if (!(v & 2)) return; /* changed already, retry */ - gcptr L = (gcptr)(v & ~2); + gcptr R = (gcptr)(v & ~2); /* We need to look up which thread it belongs to and lock this thread's minor collection lock. This also prevents several threads from getting on each other's toes trying to extract objects from the same nursery */ - struct tx_descriptor *source_d = stm_find_thread_containing_pointer(L); + struct tx_descriptor *source_d = stm_find_thread_containing_pointer(R); assert(source_d != my_d); spinlock_acquire(source_d->collection_lock); - /* now that we have the lock, check again that R->h_revision was not + /* now that we have the lock, check again that P->h_revision was not modified in the meantime. If it did change, we do nothing and will retry. */ - if (R->h_revision == v) { + if (P->h_revision == v) { + /* temporarily take the identity of source_d */ + thread_descriptor = source_d; + stm_local_revision = *source_d->local_revision_ref; + /* debugging support: "activate" the foreign nursery */ int was_active = stm_dbgmem_is_active(source_d->nursery, 0); - if (!was_active) assert(stmgc_nursery_hiding(source_d, 0)); + if (!was_active) assert(stmgc_nursery_hiding(0)); - gcptr N = extract_from_foreign_nursery(source_d, L); - ACCESS_ONCE(R->h_revision) = (revision_t)N; + /* copy the protected source object */ + gcptr N = extract_from_foreign_nursery(R); + + /* make sure the copy N is visible to other threads before we + change P->h_revision */ + smp_wmb(); + + /* do the change to P->h_revision */ + ACCESS_ONCE(P->h_revision) = (revision_t)N; fprintf(stderr, "STEALING: %p->h_revision changed from %p to %p\n", - R, L, N); + P, R, N); /* debugging support: "deactivate" the foreign nursery again */ - if (!was_active) assert(stmgc_nursery_hiding(source_d, 1)); + if (!was_active) assert(stmgc_nursery_hiding(1)); + + /* restore my own identity */ + stm_local_revision = my_local_rev; + thread_descriptor = my_d; } spinlock_release(source_d->collection_lock); } + +static void normalize_stolen_objects(struct tx_descriptor *d) +{ + /* d->stolen_objects lists pairs (R, N) with R being a protected + object, and N a public object at the _same_ revision (and with + identical content). The protected object R can have a private + copy, but it cannot have another already-committed 'h_revision'. + */ + long i, size = d->stolen_objects.size; + gcptr *items = d->stolen_objects.items; + + for (i = 0; i < size; i += 2) { + gcptr R = items[i]; + gcptr N = items[i + 1]; + + assert(dclassify(R) == K_PROTECTED); + assert(dclassify(N) == K_PUBLIC); + + revision_t v = R->h_revision; + R->h_tid |= GCFLAG_STOLEN; + R->h_revision = (revision_t)N; + + if (!(v & 1)) { /* "is a pointer" */ + gcptr L = (gcptr)v; + assert(dclassify(L) == K_PRIVATE); + + /* R has got a private copy L. This means that R is listed + in protected_with_private_copy. Where? We don't know. + The other places that scan protected_with_private_copy + must carefully ignore GCFLAG_STOLEN entries. */ + + /* we re-insert L as a private copy of the public object N */ + N->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE; + g2l_insert(&d->public_to_private, N, L); + gcptrlist_insert(&d->public_to_young, N); + } + } + gcptrlist_clear(&d->stolen_objects); + abort();//XXX +} + +void stmgc_normalize_stolen_objects(void) +{ + struct tx_descriptor *d = thread_descriptor; + spinlock_acquire(d->collection_lock); + normalize_stolen_objects(d); + spinlock_release(d->collection_lock); +} diff --git a/c3/nursery.h b/c3/nursery.h --- a/c3/nursery.h +++ b/c3/nursery.h @@ -35,6 +35,7 @@ gcptr stmgc_duplicate(gcptr, revision_t); void stmgc_start_transaction(struct tx_descriptor *); void stmgc_stop_transaction(struct tx_descriptor *); +void stmgc_committed_transaction(struct tx_descriptor *); void stmgc_abort_transaction(struct tx_descriptor *); void stmgc_init_tls(void); void stmgc_done_tls(void); @@ -45,7 +46,8 @@ enum protection_class_t stmgc_classify(gcptr); int stmgc_is_young_in(struct tx_descriptor *, gcptr); void stmgc_public_to_foreign_protected(gcptr); -int stmgc_nursery_hiding(struct tx_descriptor *, int); +int stmgc_nursery_hiding(int); +void stmgc_normalize_stolen_objects(void); #ifdef _GC_DEBUG int is_young(gcptr); diff --git a/c3/stmsync.c b/c3/stmsync.c --- a/c3/stmsync.c +++ b/c3/stmsync.c @@ -236,12 +236,12 @@ { int err = pthread_rwlock_rdlock(&rwlock_shared); assert(err == 0); - assert(stmgc_nursery_hiding(thread_descriptor, 0)); + assert(stmgc_nursery_hiding(0)); } void stm_stop_sharedlock(void) { - assert(stmgc_nursery_hiding(thread_descriptor, 1)); + assert(stmgc_nursery_hiding(1)); int err = pthread_rwlock_unlock(&rwlock_shared); assert(err == 0); } From noreply at buildbot.pypy.org Sun May 26 12:09:46 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 12:09:46 +0200 (CEST) Subject: [pypy-commit] stmgc default: Passes the first test. Message-ID: <20130526100946.9F23B1C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r9:0bbbb9fe2350 Date: 2013-05-26 12:09 +0200 http://bitbucket.org/pypy/stmgc/changeset/0bbbb9fe2350/ Log: Passes the first test. diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -481,7 +481,7 @@ Normally set, except if R was stolen */ L = (gcptr)(v & ~2); assert(dclassify(L) == K_PROTECTED); - visit_if_young(&L _REASON("public.h_revision -> PROTECTED")); + visit_if_young(&L _REASON("public.h_rev=PROTECTED")); /* The new value of L is the previously-protected object moved outside. We can't store it immediately in R->h_revision! We have to wait until the end of the minor collection. See @@ -538,7 +538,7 @@ /* use visit_if_young() again to find the final newly-public object */ - visit_if_young(&L _REASON("public.h_revision -> FETCH PUBLIC")); + visit_if_young(&L _REASON("public.h_rev=FETCH PUBLIC")); assert(dclassify(L) == K_PUBLIC); /* Note that although R is public, its h_revision cannot be @@ -980,10 +980,11 @@ N->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE; g2l_insert(&d->public_to_private, N, L); gcptrlist_insert(&d->public_to_young, N); + abort();//XXX } + recdump1("STOLEN", R); } gcptrlist_clear(&d->stolen_objects); - abort();//XXX } void stmgc_normalize_stolen_objects(void) From noreply at buildbot.pypy.org Sun May 26 12:52:13 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 12:52:13 +0200 (CEST) Subject: [pypy-commit] stmgc default: Add a test and tweak tweak tweak Message-ID: <20130526105213.0F0491C1293@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r10:ee48768dd5e6 Date: 2013-05-26 12:52 +0200 http://bitbucket.org/pypy/stmgc/changeset/ee48768dd5e6/ Log: Add a test and tweak tweak tweak diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -360,7 +360,6 @@ if (!(v & 1)) // "is a pointer", i.e. { // "has a more recent revision" /* ... unless it is a GCFLAG_STOLEN object */ - abort();//XXX if (R->h_tid & GCFLAG_STOLEN) { assert(is_young(R)); diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -980,7 +980,6 @@ N->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE; g2l_insert(&d->public_to_private, N, L); gcptrlist_insert(&d->public_to_young, N); - abort();//XXX } recdump1("STOLEN", R); } diff --git a/c3/test/support.py b/c3/test/support.py --- a/c3/test/support.py +++ b/c3/test/support.py @@ -298,6 +298,8 @@ self.step = 0 self.steplocks = {0: thread.allocate_lock()} self.settinglock = thread.allocate_lock() + self.parallel_locks = (thread.allocate_lock(), thread.allocate_lock()) + self.parallel_locks[0].acquire() self.resulting_exception = None locks = [] for fn in fns: @@ -368,6 +370,31 @@ except thread.error: pass + def wait_while_in_parallel(self): + # parallel_locks[0] is acquired, parallel_locks[1] is released + res = self.parallel_locks[1].acquire(False) + assert res + # parallel_locks[0] is acquired, parallel_locks[1] is acquired + print 'wait_while_in_parallel enter' + self.parallel_locks[0].release() + self.parallel_locks[1].acquire() + print 'wait_while_in_parallel leave' + # parallel_locks[0] is acquired, parallel_locks[1] is acquired + self.parallel_locks[1].release() + res = self.parallel_locks[0].acquire(False) + assert not res + # parallel_locks[0] is acquired, parallel_locks[1] is released + + def enter_in_parallel(self): + print 'enter_in_parallel: waiting...' + # wait for parallel_locks[0] + self.parallel_locks[0].acquire() + print 'enter_in_parallel' + + def leave_in_parallel(self): + print 'leave_in_parallel' + self.parallel_locks[1].release() + # ____________________________________________________________ def oalloc(size): diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -252,3 +252,31 @@ assert not lib.in_nursery(p2) r.set(3) run_parallel(f1, f2) + +def test_access_foreign_nursery_with_private_copy_1(): + # this version should not cause conflicts + pg = palloc(HDR + WORD) + lib.rawsetlong(pg, 0, 420063) + seen = [] + def f1(r): + p1 = lib.stm_write_barrier(pg) + assert lib.in_nursery(p1) + lib.rawsetlong(p1, 0, 9387987) + def cb(c): + assert c == 0 + p4 = lib.stm_write_barrier(p1) + assert lib.rawgetlong(p4, 0) == 9387987 + lib.rawsetlong(p4, 0, -6666) + r.wait_while_in_parallel() + perform_transaction(cb) + def f2(r): + def cb(c): + assert c == 0 + r.enter_in_parallel() + p2 = lib.stm_read_barrier(pg) + assert not lib.in_nursery(p2) + assert lib.rawgetlong(p2, 0) == 9387987 + perform_transaction(cb) + r.leave_in_parallel() + run_parallel(f1, f2) + assert lib.getlong(pg, 0) == -6666 From noreply at buildbot.pypy.org Sun May 26 13:07:35 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 13:07:35 +0200 (CEST) Subject: [pypy-commit] stmgc default: A simpler failing test Message-ID: <20130526110735.ABD811C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r11:cf227a57babe Date: 2013-05-26 13:01 +0200 http://bitbucket.org/pypy/stmgc/changeset/cf227a57babe/ Log: A simpler failing test diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -620,7 +620,6 @@ gcptr R = item->addr; #ifdef DUMP_EXTRA fprintf(stderr, "%p->h_revision = %p (CancelLocks)\n", R, (gcptr)v); - abort();//XXX #endif ACCESS_ONCE(R->h_revision) = v; diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -186,6 +186,9 @@ assert(!gcptrlist_size(&d->private_old_pointing_to_young)); d->num_read_objects_known_old = 0; d->num_public_to_protected = gcptrlist_size(&d->public_to_young); + + if (gcptrlist_size(&d->stolen_objects) > 0) + stmgc_normalize_stolen_objects(); } static void fix_new_public_to_protected_references(struct tx_descriptor *d); diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -235,6 +235,13 @@ perform_transaction(cb) run_parallel(f1, f1, f1) +def test_many_versions(): + p1 = nalloc(HDR) + for i in range(10): + lib.stm_commit_transaction() + lib.stm_begin_inevitable_transaction() + p1 = lib.stm_write_barrier(p1) + def test_access_foreign_nursery(): pg = palloc(HDR) seen = [] From noreply at buildbot.pypy.org Sun May 26 13:07:36 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 13:07:36 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix the test simply by killing GCFLAG_PRIVATE_COPY, which was not used Message-ID: <20130526110736.CE7061C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r12:78d0be847b9a Date: 2013-05-26 13:06 +0200 http://bitbucket.org/pypy/stmgc/changeset/78d0be847b9a/ Log: Fix the test simply by killing GCFLAG_PRIVATE_COPY, which was not used any more. diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -641,7 +641,6 @@ G2L_LOOP_FORWARD(d->public_to_private, item) { gcptr L = item->val; - assert(L->h_tid & GCFLAG_PRIVATE_COPY); assert(!(L->h_tid & GCFLAG_VISITED)); assert(!(L->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)); assert(!(L->h_tid & GCFLAG_PREBUILT_ORIGINAL)); @@ -653,7 +652,6 @@ fprintf(stderr, "%p->h_revision = %p (UpdateChainHeads)\n", L, (gcptr)new_revision); #endif - L->h_tid &= ~GCFLAG_PRIVATE_COPY; L->h_revision = new_revision; if (is_young(L)) @@ -675,7 +673,6 @@ gcptr R = item->addr; revision_t v = (revision_t)item->val; - assert(!(R->h_tid & GCFLAG_PRIVATE_COPY)); assert(R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE); assert(!(R->h_tid & GCFLAG_NURSERY_MOVED)); assert(!(R->h_tid & GCFLAG_STOLEN)); diff --git a/c3/et.h b/c3/et.h --- a/c3/et.h +++ b/c3/et.h @@ -33,8 +33,7 @@ * young | [ protected objects | private objects (--> grows) ] * (nursery)| * - * GCFLAG_PRIVATE_COPY is set on a private object that is a "private copy", - * i.e. is the newer version of some pre-existing non-private object. + * GCFLAG_OLD is set on old objects. * * GCFLAG_VISITED is used temporarily during major collections. * @@ -53,32 +52,28 @@ * * GCFLAG_NURSERY_MOVED is used temporarily during minor collections. * - * GCFLAG_OLD is set on old objects. - * * GCFLAG_STOLEN is set of protected objects after we notice that they * have been stolen. */ -#define GCFLAG_PRIVATE_COPY (STM_FIRST_GCFLAG << 0) +#define GCFLAG_OLD (STM_FIRST_GCFLAG << 0) #define GCFLAG_VISITED (STM_FIRST_GCFLAG << 1) #define GCFLAG_PUBLIC_TO_PRIVATE (STM_FIRST_GCFLAG << 2) #define GCFLAG_PREBUILT_ORIGINAL (STM_FIRST_GCFLAG << 3) #define GCFLAG_WRITE_BARRIER (STM_FIRST_GCFLAG << 4) #define GCFLAG_NURSERY_MOVED (STM_FIRST_GCFLAG << 5) -#define GCFLAG_OLD (STM_FIRST_GCFLAG << 6) -#define GCFLAG_STOLEN (STM_FIRST_GCFLAG << 7) +#define GCFLAG_STOLEN (STM_FIRST_GCFLAG << 6) /* this value must be reflected in PREBUILT_FLAGS in stmgc.h */ #define GCFLAG_PREBUILT (GCFLAG_VISITED | \ GCFLAG_PREBUILT_ORIGINAL | \ GCFLAG_OLD) -#define GC_FLAG_NAMES { "PRIVATE_COPY", \ +#define GC_FLAG_NAMES { "OLD", \ "VISITED", \ "PUBLIC_TO_PRIVATE", \ "PREBUILT_ORIGINAL", \ "WRITE_BARRIER", \ "NURSERY_MOVED", \ - "OLD", \ "STOLEN", \ NULL } diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -159,14 +159,12 @@ memcpy(localobj, globalobj, size); - assert(!(localobj->h_tid & GCFLAG_PRIVATE_COPY)); assert(!(localobj->h_tid & GCFLAG_NURSERY_MOVED)); localobj->h_tid &= ~(GCFLAG_VISITED | GCFLAG_PUBLIC_TO_PRIVATE | GCFLAG_PREBUILT_ORIGINAL | GCFLAG_WRITE_BARRIER | GCFLAG_OLD); - localobj->h_tid |= GCFLAG_PRIVATE_COPY; localobj->h_revision = stm_local_revision; return localobj; } @@ -214,6 +212,7 @@ void stmgc_committed_transaction(struct tx_descriptor *d) { spinlock_release(d->collection_lock); + gcptrlist_clear(&d->protected_with_private_copy); } void stmgc_abort_transaction(struct tx_descriptor *d) diff --git a/c3/stmgc.h b/c3/stmgc.h --- a/c3/stmgc.h +++ b/c3/stmgc.h @@ -21,7 +21,7 @@ #define STM_SIZE_OF_USER_TID (sizeof(revision_t) / 2) /* in bytes */ #define STM_FIRST_GCFLAG (1L << (8 * STM_SIZE_OF_USER_TID)) #define STM_USER_TID_MASK (STM_FIRST_GCFLAG - 1) -#define PREBUILT_FLAGS (STM_FIRST_GCFLAG * (2 + 8 + 64)) +#define PREBUILT_FLAGS (STM_FIRST_GCFLAG * (1 + 2 + 8)) #define PREBUILT_REVISION 1 diff --git a/c3/test/support.py b/c3/test/support.py --- a/c3/test/support.py +++ b/c3/test/support.py @@ -90,7 +90,6 @@ /* some constants normally private that are useful in the tests */ #define WORD ... #define GC_PAGE_SIZE ... - #define GCFLAG_PRIVATE_COPY ... #define GCFLAG_VISITED ... #define GCFLAG_PUBLIC_TO_PRIVATE ... #define GCFLAG_PREBUILT_ORIGINAL ... @@ -469,7 +468,6 @@ def make_global(p1): assert p1.h_revision == lib.get_local_revision() - assert not (p1.h_tid & GCFLAG_PRIVATE_COPY) p1.h_revision = (lib.stm_global_cur_time() | 1) - 2 def delegate(p1, p2): From noreply at buildbot.pypy.org Sun May 26 13:17:24 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 13:17:24 +0200 (CEST) Subject: [pypy-commit] stmgc default: fix Message-ID: <20130526111724.22F8F1C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r13:e27d375c4a29 Date: 2013-05-26 13:17 +0200 http://bitbucket.org/pypy/stmgc/changeset/e27d375c4a29/ Log: fix diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -701,13 +701,13 @@ case -1: fprintf(stderr, " (unmanaged)"); break; default: fprintf(stderr, "\n CANNOT ACCESS MEMORY!\n"); abort(); } - fprintf(stderr, "\n tid\t%16lx ", (unsigned long)obj->h_tid); + fprintf(stderr, "\n tid\t%16lx", (unsigned long)obj->h_tid); count++; pp = gc_flag_names; for (i = STM_FIRST_GCFLAG; *pp != NULL; pp++, i <<= 1) { if (obj->h_tid & i) { - fprintf(stderr, " %s", *pp); + fprintf(stderr, " %s", *pp); } } fprintf(stderr, "\n rev\t%16lx (%ld)\n", diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -378,7 +378,10 @@ previous_obj = NULL; } obj = (gcptr)obj->h_revision; - assert(stmgc_classify(obj) != K_PRIVATE); + /* nb. don't use stmgc_classify() here, because some objects trigger + an assert at this point: young non-nursery objects which just + grew the flag GCFLAG_OLD */ + assert(obj->h_revision != stm_local_revision); /* not a private object */ PATCH_ROOT_WITH(obj); goto retry; } From noreply at buildbot.pypy.org Sun May 26 13:21:42 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 13:21:42 +0200 (CEST) Subject: [pypy-commit] stmgc default: Use _GC_DEBUG=2 to enable DUMP_EXTRA. Do it from the tests but not from Message-ID: <20130526112142.BE7CC1C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r14:279a2e235032 Date: 2013-05-26 13:21 +0200 http://bitbucket.org/pypy/stmgc/changeset/279a2e235032/ Log: Use _GC_DEBUG=2 to enable DUMP_EXTRA. Do it from the tests but not from the Makefile. diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -258,7 +258,7 @@ extern void recdump(gcptr obj); /* in gcpage.c */ -static void recdump1(char *msg, gcptr obj) +void recdump1(char *msg, gcptr obj) { fprintf(stderr, "\n<--------------------%s--------------------> ", msg); recdump(obj); diff --git a/c3/stmimpl.h b/c3/stmimpl.h --- a/c3/stmimpl.h +++ b/c3/stmimpl.h @@ -12,7 +12,11 @@ # endif #endif -#define DUMP_EXTRA +#ifdef _GC_DEBUG +# if _GC_DEBUG >= 2 +# define DUMP_EXTRA +# endif +#endif #include #include diff --git a/c3/test/support.py b/c3/test/support.py --- a/c3/test/support.py +++ b/c3/test/support.py @@ -251,7 +251,7 @@ '''.lstrip(), include_dirs=[parent_dir], undef_macros=['NDEBUG'], define_macros=[('GC_NURSERY', '(16 * sizeof(void *))'), - ('_GC_DEBUG', '1'), + ('_GC_DEBUG', '2'), ('GC_PAGE_SIZE', '1000'), ('GC_MIN', '200000'), ('GC_EXPAND', '90000'), From noreply at buildbot.pypy.org Sun May 26 15:02:00 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 15:02:00 +0200 (CEST) Subject: [pypy-commit] stmgc default: Test, covering another "abort(); //XXX". Message-ID: <20130526130200.25BBC1C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r15:1bcd5a031e38 Date: 2013-05-26 13:39 +0200 http://bitbucket.org/pypy/stmgc/changeset/1bcd5a031e38/ Log: Test, covering another "abort();//XXX". diff --git a/c3/et.h b/c3/et.h --- a/c3/et.h +++ b/c3/et.h @@ -54,6 +54,9 @@ * * GCFLAG_STOLEN is set of protected objects after we notice that they * have been stolen. + * + * GCFLAG_STUB is used for debugging: it's set on stub objects made by + * create_yo_stubs() */ #define GCFLAG_OLD (STM_FIRST_GCFLAG << 0) #define GCFLAG_VISITED (STM_FIRST_GCFLAG << 1) @@ -62,6 +65,7 @@ #define GCFLAG_WRITE_BARRIER (STM_FIRST_GCFLAG << 4) #define GCFLAG_NURSERY_MOVED (STM_FIRST_GCFLAG << 5) #define GCFLAG_STOLEN (STM_FIRST_GCFLAG << 6) +#define GCFLAG_STUB (STM_FIRST_GCFLAG << 7) /* debugging */ /* this value must be reflected in PREBUILT_FLAGS in stmgc.h */ #define GCFLAG_PREBUILT (GCFLAG_VISITED | \ @@ -75,6 +79,7 @@ "WRITE_BARRIER", \ "NURSERY_MOVED", \ "STOLEN", \ + "STUB", \ NULL } /************************************************************/ diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -716,10 +716,16 @@ pobj = (gcptr *)(obj + 1); _recdump_first = pobj; memset(_recdump_isptr, 0, sizeof _recdump_isptr); - stmcb_trace(obj, &_recdump_visit); - n = stmcb_size(obj) - sizeof(*obj); - n = (n + sizeof(WORD) - 1) / sizeof(WORD); + if ((obj->h_tid & GCFLAG_STUB) == 0) { + stmcb_trace(obj, &_recdump_visit); + + n = stmcb_size(obj) - sizeof(*obj); + n = (n + sizeof(WORD) - 1) / sizeof(WORD); + } + else { + n = 0; + } for (i = 0; i < n; i++) { fprintf(stderr, " [%lu]\t%16lx (%ld)\n", i, (unsigned long)*pobj, (long)*pobj); diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -667,10 +667,9 @@ /* xxx try to avoid duplicate stubs for the same object */ gcptr stub = stmgcpage_malloc(sizeof(*stub)); - stub->h_tid = 0; /* no flags */ + stub->h_tid = GCFLAG_OLD | GCFLAG_STUB; /* with type_id == 0 */ stub->h_revision = ((revision_t)obj) | 2; *pobj = stub; - abort();//XXX } static void fix_new_public_to_protected_references(struct tx_descriptor *d) diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -287,3 +287,26 @@ r.leave_in_parallel() run_parallel(f1, f2) assert lib.getlong(pg, 0) == -6666 + +def test_access_foreign_nursery_use_stubs(): + pg = palloc_refs(1) + def f1(r): + q1 = nalloc(HDR + WORD) + lib.setlong(q1, 0, 424242) + p1 = lib.stm_write_barrier(pg) + lib.setptr(p1, 0, q1) + assert lib.in_nursery(p1) + assert lib.in_nursery(q1) + r.set(2) + r.wait(3) + p3 = lib.stm_read_barrier(pg) + assert not lib.in_nursery(p3) + def f2(r): + r.wait(2) + p2 = lib.stm_read_barrier(pg) + assert not lib.in_nursery(p2) + assert p2 + q2 = lib.getptr(p2, 0) + assert lib.getlong(q2, 0) == 424242 + r.set(3) + run_parallel(f1, f2) From noreply at buildbot.pypy.org Sun May 26 15:02:01 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 15:02:01 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix stmgc_nursery_hiding(): use a real refcount and locking policy now, Message-ID: <20130526130201.4E30B1C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r16:8cfb3a9e834d Date: 2013-05-26 15:01 +0200 http://bitbucket.org/pypy/stmgc/changeset/8cfb3a9e834d/ Log: Fix stmgc_nursery_hiding(): use a real refcount and locking policy now, which avoids races when stealing. diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -217,10 +217,6 @@ void stmgc_abort_transaction(struct tx_descriptor *d) { - /* cancel the change to the h_revision done in LocalizeProtected() */ - long i, size = d->protected_with_private_copy.size; - gcptr *items = d->protected_with_private_copy.items; - /* Note that the thrown-away private objects are kept around. It may possibly be a small optimization to reuse the part of the nursery that contains them. To be on the safe "future-proof" @@ -231,6 +227,10 @@ if (d->collection_lock != 'C') spinlock_acquire(d->collection_lock); + /* cancel the change to the h_revision done in LocalizeProtected() */ + long i, size = d->protected_with_private_copy.size; + gcptr *items = d->protected_with_private_copy.items; + for (i = 0; i < size; i++) { gcptr R = items[i]; assert(dclassify(R) == K_PROTECTED); @@ -805,30 +805,51 @@ { #ifdef _GC_DEBUG struct tx_descriptor *d = thread_descriptor; + wlog_t *item; + revision_t count; + + /* 'd->debug_nursery_access' works like a refcount: when it is 0, + no-one should be accessing young objects of 'd'. We ensure that + it is the case using mprotect. */ + while (1) { + count = ACCESS_ONCE(d->debug_nursery_access); + if (count == (revision_t)-1) { + spinloop(); + continue; + } + if (bool_cas(&d->debug_nursery_access, count, (revision_t)-1)) + break; + } + if (hide) { - stm_dbgmem_not_used(d->nursery, GC_NURSERY, 1); + /* decrement the "refcount" */ + assert(count > 0); + count--; + if (count == 0) { + stm_dbgmem_not_used(d->nursery, GC_NURSERY, 1); + + G2L_LOOP_FORWARD(d->young_objects_outside_nursery, item) { + gcptr obj = item->addr; + size_t size = stmcb_size(obj); + stm_dbgmem_not_used(obj, size, 0); + } G2L_LOOP_END; + } } else { - stm_dbgmem_used_again(d->nursery, - d->nursery_current - d->nursery, 1); + if (count == 0) { + stm_dbgmem_used_again(d->nursery, + d->nursery_current - d->nursery, 1); + G2L_LOOP_FORWARD(d->young_objects_outside_nursery, item) { + gcptr obj = item->addr; + stm_dbgmem_used_again(obj, sizeof(*obj), 0); + size_t size = stmcb_size(obj); + stm_dbgmem_used_again(obj, size, 0); + } G2L_LOOP_END; + } + count++; } - - wlog_t *item; - - G2L_LOOP_FORWARD(d->young_objects_outside_nursery, item) { - - gcptr obj = item->addr; - if (hide) { - size_t size = stmcb_size(obj); - stm_dbgmem_not_used(obj, size, 0); - } - else { - stm_dbgmem_used_again(obj, sizeof(gcptr *), 0); - size_t size = stmcb_size(obj); - stm_dbgmem_used_again(obj, size, 0); - } - - } G2L_LOOP_END; + smp_wmb(); + ACCESS_ONCE(d->debug_nursery_access) = count; #endif return 1; } @@ -924,9 +945,10 @@ thread_descriptor = source_d; stm_local_revision = *source_d->local_revision_ref; + fprintf(stderr, "STEALING: %p->h_revision points to %p\n", P, R); + /* debugging support: "activate" the foreign nursery */ - int was_active = stm_dbgmem_is_active(source_d->nursery, 0); - if (!was_active) assert(stmgc_nursery_hiding(0)); + assert(stmgc_nursery_hiding(0)); /* copy the protected source object */ gcptr N = extract_from_foreign_nursery(R); @@ -941,7 +963,7 @@ P, R, N); /* debugging support: "deactivate" the foreign nursery again */ - if (!was_active) assert(stmgc_nursery_hiding(1)); + assert(stmgc_nursery_hiding(1)); /* restore my own identity */ stm_local_revision = my_local_rev; diff --git a/c3/nursery.h b/c3/nursery.h --- a/c3/nursery.h +++ b/c3/nursery.h @@ -14,7 +14,7 @@ gcptr **shadowstack_end_ref; \ gcptr *thread_local_obj_ref; \ \ - revision_t collection_lock; \ + revision_t collection_lock, debug_nursery_access; \ struct G2L young_objects_outside_nursery; \ struct GcPtrList old_objects_to_trace; \ long num_read_objects_known_old; \ From noreply at buildbot.pypy.org Sun May 26 15:13:20 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 15:13:20 +0200 (CEST) Subject: [pypy-commit] stmgc default: Test for one extra "abort();//XXX". Message-ID: <20130526131320.700481C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r17:ce7dcafc00aa Date: 2013-05-26 15:11 +0200 http://bitbucket.org/pypy/stmgc/changeset/ce7dcafc00aa/ Log: Test for one extra "abort();//XXX". diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -244,7 +244,6 @@ assert(dclassify(L) == K_PRIVATE); R->h_revision = fetch_extra_word(L); - abort();//XXX } gcptrlist_clear(&d->protected_with_private_copy); spinlock_release(d->collection_lock); @@ -613,7 +612,7 @@ continue; } /* The listed object was not visited. Either it's because it - because really unreachable (in which case it cannot possibly + is really unreachable (in which case it cannot possibly be modified any more, and the current transaction cannot abort because of it) or it's because it was already modified. */ diff --git a/c3/test/test_abort.py b/c3/test/test_abort.py --- a/c3/test/test_abort.py +++ b/c3/test/test_abort.py @@ -89,3 +89,19 @@ abort_and_retry() else: major_collect() + +def test_abort_protected_to_private(): + pg = palloc(HDR + WORD) + p1 = lib.stm_write_barrier(pg) + lib.setlong(p1, 0, 32128247) + # + @perform_transaction + def run(retry_counter): + assert lib.getlong(pg, 0) == 32128247 + if retry_counter == 0: + lib.setlong(pg, 0, 4737372) + abort_and_retry() + else: + lib.setlong(pg, 0, 838311) + # + assert lib.getlong(pg, 0) == 838311 From noreply at buildbot.pypy.org Sun May 26 16:50:54 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 26 May 2013 16:50:54 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: figure stuff out - this fixes test_recusrive on llgraph backend Message-ID: <20130526145054.15D901C0134@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64567:7d4b2887e29f Date: 2013-05-26 16:49 +0200 http://bitbucket.org/pypy/pypy/changeset/7d4b2887e29f/ Log: figure stuff out - this fixes test_recusrive on llgraph backend diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -2473,7 +2473,7 @@ virtualizable_box = self.virtualizable_boxes[-1] virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box) if vinfo.is_token_nonnull_gcref(virtualizable): - vinfo.clear_vable_token(virtualizable) + vinfo.reset_token_gcref(virtualizable) # fill the virtualizable with the local boxes self.synchronize_virtualizable() # diff --git a/rpython/jit/metainterp/resume.py b/rpython/jit/metainterp/resume.py --- a/rpython/jit/metainterp/resume.py +++ b/rpython/jit/metainterp/resume.py @@ -1216,17 +1216,8 @@ return len(numb.nums) index = len(numb.nums) - 1 virtualizable = self.decode_ref(numb.nums[index]) - if self.resume_after_guard_not_forced == 1: - # in the middle of handle_async_forcing() - assert vinfo.is_token_nonnull_gcref(virtualizable) - vinfo.reset_token_gcref(virtualizable) - else: - # just jumped away from assembler (case 4 in the comment in - # virtualizable.py) into tracing (case 2); we might have non-forced - # virtualizable here, in case it comes from somewhere strange, just - # force it - if vinfo.is_token_nonnull_gcref(virtualizable): - vinfo.clear_vable_token(virtualizable) + # just reset the token, we'll force it later + vinfo.reset_token_gcref(virtualizable) return vinfo.write_from_resume_data_partial(virtualizable, self, numb) def load_value_of_type(self, TYPE, tagged): diff --git a/rpython/jit/metainterp/virtualizable.py b/rpython/jit/metainterp/virtualizable.py --- a/rpython/jit/metainterp/virtualizable.py +++ b/rpython/jit/metainterp/virtualizable.py @@ -275,6 +275,10 @@ virtualizable.vable_token = TOKEN_NONE self.reset_token_gcref = reset_token_gcref + def reset_vable_token(virtualizable): + virtualizable.vable_token = TOKEN_NONE + self.reset_vable_token = reset_vable_token + def _freeze_(self): return True From noreply at buildbot.pypy.org Sun May 26 16:54:44 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 16:54:44 +0200 (CEST) Subject: [pypy-commit] stmgc default: Change again: don't pretend to have the identity of the stolen-from Message-ID: <20130526145444.BC53B1C1293@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r18:ab86b5cb7472 Date: 2013-05-26 16:12 +0200 http://bitbucket.org/pypy/stmgc/changeset/ab86b5cb7472/ Log: Change again: don't pretend to have the identity of the stolen-from thread. This doesn't work correctly with the calls to stmgcpage_malloc(). diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -301,6 +301,7 @@ not_found:; gcptr L = stmgc_duplicate(R, 0); + assert(L->h_revision == stm_local_revision); g2l_insert(&d->public_to_private, R, L); gcptrlist_insert(&d->public_to_young, R); AddInReadSet(d, R); @@ -746,11 +747,9 @@ gcptrlist_clear(&d->list_of_read_objects); fprintf(stderr, "\n" - "***************************************************************\n" - "***************************************************************\n" - "************************************* %ld\n" - "***************************************************************\n" - "***************************************************************\n", + "*************************************\n" + "************************************** committed %ld\n" + "*************************************\n", (long)cur_time); revision_t localrev = stm_local_revision; diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -557,9 +557,9 @@ */ thread_descriptor = d; stm_local_revision = *d->local_revision_ref; - assert(stmgc_nursery_hiding(0)); + assert(stmgc_nursery_hiding(d, 0)); stmgc_minor_collect_no_abort(); - assert(stmgc_nursery_hiding(1)); + assert(stmgc_nursery_hiding(d, 1)); } } thread_descriptor = saved; diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -179,6 +179,8 @@ void stmgc_start_transaction(struct tx_descriptor *d) { + assert(!d->collection_lock); /* with no protected objects so far, no + other thread can be stealing */ assert(!gcptrlist_size(&d->protected_with_private_copy)); assert(!g2l_any_entry(&d->public_to_private)); assert(!gcptrlist_size(&d->private_old_pointing_to_young)); @@ -457,6 +459,7 @@ /* then we record the dependency in the dictionary 'public_to_private' */ + assert(L->h_revision == stm_local_revision); g2l_insert(&d->public_to_private, R, L); /*mark*/ } @@ -657,11 +660,7 @@ static void create_yo_stubs(gcptr *pobj) { gcptr obj = *pobj; - if (obj == NULL) - return; - - struct tx_descriptor *d = thread_descriptor; - if (!stmgc_is_young_in(d, obj)) + if (obj == NULL || (obj->h_tid & GCFLAG_OLD) != 0) return; /* xxx try to avoid duplicate stubs for the same object */ @@ -800,10 +799,9 @@ gcptrlist_insert(&d->private_old_pointing_to_young, obj); } -int stmgc_nursery_hiding(int hide) +int stmgc_nursery_hiding(struct tx_descriptor *d, int hide) { #ifdef _GC_DEBUG - struct tx_descriptor *d = thread_descriptor; wlog_t *item; revision_t count; @@ -855,16 +853,16 @@ /************************************************************/ -static gcptr extract_from_foreign_nursery(gcptr R) +static gcptr extract_from_foreign_nursery(struct tx_descriptor *source_d, + gcptr R) { /* "Stealing": this function follows a chain of protected objects in - the foreign nursery of the thread temporarily in - 'thread_descriptor'. It copies the last one outside the nursery, - and return it. */ + the foreign nursery of the thread 'source_d'. It copies the last + one outside the nursery, and return it. */ gcptr R2, N; revision_t source_local_rev, v; - source_local_rev = stm_local_revision; + source_local_rev = *source_d->local_revision_ref; v = ACCESS_ONCE(R->h_revision); /* check that R is a protected object */ @@ -895,9 +893,9 @@ } /* R is now the protected object to move outside, with revision v. */ - N = create_old_object_copy(R _REASON("stolen copy")); + N = create_old_object_copy(R _REASON("**stolen copy")); N->h_revision = v; - gcptrlist_insert2(&thread_descriptor->stolen_objects, R, N); + gcptrlist_insert2(&source_d->stolen_objects, R, N); /* there might be references in N going to protected objects. We must fix them with stubs. */ @@ -915,7 +913,6 @@ for the other thread to do a minor collection, because it might be blocked in a system call or whatever. */ struct tx_descriptor *my_d = thread_descriptor; - revision_t my_local_rev = stm_local_revision; /* repeat the checks in the caller, to avoid passing more than one argument here */ @@ -940,33 +937,30 @@ retry. */ if (P->h_revision == v) { - /* temporarily take the identity of source_d */ - thread_descriptor = source_d; - stm_local_revision = *source_d->local_revision_ref; - + /* careful here: all 'thread_descriptor' accesses will continue + to get the current thread (needed e.g. for stmgcpage_malloc()) + which is different from 'source_d', the source thread out of + which we are stealing. */ fprintf(stderr, "STEALING: %p->h_revision points to %p\n", P, R); /* debugging support: "activate" the foreign nursery */ - assert(stmgc_nursery_hiding(0)); + assert(stmgc_nursery_hiding(source_d, 0)); /* copy the protected source object */ - gcptr N = extract_from_foreign_nursery(R); + gcptr N = extract_from_foreign_nursery(source_d, R); /* make sure the copy N is visible to other threads before we change P->h_revision */ smp_wmb(); /* do the change to P->h_revision */ + assert(bool_cas(&P->h_revision, ((revision_t)R) | 2, (revision_t)N)); ACCESS_ONCE(P->h_revision) = (revision_t)N; fprintf(stderr, "STEALING: %p->h_revision changed from %p to %p\n", P, R, N); /* debugging support: "deactivate" the foreign nursery again */ - assert(stmgc_nursery_hiding(1)); - - /* restore my own identity */ - stm_local_revision = my_local_rev; - thread_descriptor = my_d; + assert(stmgc_nursery_hiding(source_d, 1)); } spinlock_release(source_d->collection_lock); } @@ -980,6 +974,7 @@ */ long i, size = d->stolen_objects.size; gcptr *items = d->stolen_objects.items; + assert(d == thread_descriptor); for (i = 0; i < size; i += 2) { gcptr R = items[i]; @@ -1003,6 +998,7 @@ /* we re-insert L as a private copy of the public object N */ N->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE; + assert(L->h_revision == stm_local_revision); g2l_insert(&d->public_to_private, N, L); gcptrlist_insert(&d->public_to_young, N); } diff --git a/c3/nursery.h b/c3/nursery.h --- a/c3/nursery.h +++ b/c3/nursery.h @@ -46,7 +46,7 @@ enum protection_class_t stmgc_classify(gcptr); int stmgc_is_young_in(struct tx_descriptor *, gcptr); void stmgc_public_to_foreign_protected(gcptr); -int stmgc_nursery_hiding(int); +int stmgc_nursery_hiding(struct tx_descriptor *, int); void stmgc_normalize_stolen_objects(void); #ifdef _GC_DEBUG diff --git a/c3/stmsync.c b/c3/stmsync.c --- a/c3/stmsync.c +++ b/c3/stmsync.c @@ -236,12 +236,12 @@ { int err = pthread_rwlock_rdlock(&rwlock_shared); assert(err == 0); - assert(stmgc_nursery_hiding(0)); + assert(stmgc_nursery_hiding(thread_descriptor, 0)); } void stm_stop_sharedlock(void) { - assert(stmgc_nursery_hiding(1)); + assert(stmgc_nursery_hiding(thread_descriptor, 1)); int err = pthread_rwlock_unlock(&rwlock_shared); assert(err == 0); } diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -272,9 +272,13 @@ def cb(c): assert c == 0 p4 = lib.stm_write_barrier(p1) + assert lib.in_nursery(p4) + assert p4 != p1 and p4 != pg assert lib.rawgetlong(p4, 0) == 9387987 + print "changing p4=%r to contain -6666" % (p4,) lib.rawsetlong(p4, 0, -6666) r.wait_while_in_parallel() + assert seen == ["ok"] perform_transaction(cb) def f2(r): def cb(c): @@ -284,6 +288,7 @@ assert not lib.in_nursery(p2) assert lib.rawgetlong(p2, 0) == 9387987 perform_transaction(cb) + seen.append("ok") r.leave_in_parallel() run_parallel(f1, f2) assert lib.getlong(pg, 0) == -6666 From noreply at buildbot.pypy.org Sun May 26 16:54:45 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 16:54:45 +0200 (CEST) Subject: [pypy-commit] stmgc default: progress Message-ID: <20130526145445.E02D81C1293@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r19:a16db24e402f Date: 2013-05-26 16:54 +0200 http://bitbucket.org/pypy/stmgc/changeset/a16db24e402f/ Log: progress diff --git a/c3/atomic_ops.h b/c3/atomic_ops.h --- a/c3/atomic_ops.h +++ b/c3/atomic_ops.h @@ -109,8 +109,8 @@ } -#define spinlock_acquire(lock) \ - do { if (bool_cas(&(lock), 0, 1)) break; \ +#define spinlock_acquire(lock, targetvalue) \ + do { if (bool_cas(&(lock), 0, (targetvalue))) break; \ do { spinloop(); } while (ACCESS_ONCE(lock)); \ } while (1) diff --git a/c3/demo1.c b/c3/demo1.c --- a/c3/demo1.c +++ b/c3/demo1.c @@ -11,7 +11,7 @@ #define UPPER_BOUND 2500 -#define NUMTHREADS 1 /* XXX temporary! should be 4 */ +#define NUMTHREADS 2 #define GCTID_STRUCT_NODE 123 diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -617,6 +617,7 @@ revision_t v = L->h_revision; if (v == stm_local_revision) break; /* done */ + L->h_revision = stm_local_revision; gcptr R = item->addr; #ifdef DUMP_EXTRA diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -179,8 +179,10 @@ void stmgc_start_transaction(struct tx_descriptor *d) { - assert(!d->collection_lock); /* with no protected objects so far, no - other thread can be stealing */ + /* with no protected objects so far, no other thread can be stealing; + but we can't simply assert that d->collection_lock == 0, because + we might still view it as non-zero for a short time. */ + assert(d->collection_lock != 'M' && d->collection_lock != 'C'); assert(!gcptrlist_size(&d->protected_with_private_copy)); assert(!g2l_any_entry(&d->public_to_private)); assert(!gcptrlist_size(&d->private_old_pointing_to_young)); @@ -202,8 +204,7 @@ if (gcptrlist_size(&d->private_old_pointing_to_young) > 0) fix_new_public_to_protected_references(d); - spinlock_acquire(d->collection_lock); - d->collection_lock = 'C'; /* Committing */ + spinlock_acquire(d->collection_lock, 'C'); /* committing */ if (gcptrlist_size(&d->stolen_objects) > 0) normalize_stolen_objects(d); @@ -226,8 +227,10 @@ other thread is busy stealing (which includes reading the extra word immediately after private objects). */ - if (d->collection_lock != 'C') - spinlock_acquire(d->collection_lock); + assert(d->collection_lock != 'M'); /* don't abort when minor-collecting */ + assert(d->collection_lock != 'N'); /* don't abort when normalizing */ + if (d->collection_lock != 'C') /* don't double-acquire the lock */ + spinlock_acquire(d->collection_lock, 'C'); /* cancel the change to the h_revision done in LocalizeProtected() */ long i, size = d->protected_with_private_copy.size; @@ -248,7 +251,8 @@ R->h_revision = fetch_extra_word(L); } gcptrlist_clear(&d->protected_with_private_copy); - spinlock_release(d->collection_lock); + + spinlock_release(d->collection_lock); /* release the lock */ g2l_clear(&d->public_to_private); gcptrlist_clear(&d->private_old_pointing_to_young); @@ -637,7 +641,7 @@ static void setup_minor_collect(struct tx_descriptor *d) { - spinlock_acquire(d->collection_lock); + spinlock_acquire(d->collection_lock, 'M'); /* minor-collecting */ assert(gcptrlist_size(&d->old_objects_to_trace) == 0); } @@ -880,6 +884,7 @@ have to fetch R's real revision off-line from the extra word that follows R2 */ v = fetch_extra_word(R2); + assert(v != source_local_rev); break; } else if (R2->h_tid & GCFLAG_OLD) { @@ -912,7 +917,6 @@ object out ourselves. This is necessary: we can't simply wait for the other thread to do a minor collection, because it might be blocked in a system call or whatever. */ - struct tx_descriptor *my_d = thread_descriptor; /* repeat the checks in the caller, to avoid passing more than one argument here */ @@ -928,9 +932,9 @@ threads from getting on each other's toes trying to extract objects from the same nursery */ struct tx_descriptor *source_d = stm_find_thread_containing_pointer(R); - assert(source_d != my_d); + assert(source_d != thread_descriptor); - spinlock_acquire(source_d->collection_lock); + spinlock_acquire(source_d->collection_lock, 'S'); /* stealing */ /* now that we have the lock, check again that P->h_revision was not modified in the meantime. If it did change, we do nothing and will @@ -1010,7 +1014,7 @@ void stmgc_normalize_stolen_objects(void) { struct tx_descriptor *d = thread_descriptor; - spinlock_acquire(d->collection_lock); + spinlock_acquire(d->collection_lock, 'N'); /* normalizing */ normalize_stolen_objects(d); spinlock_release(d->collection_lock); } From noreply at buildbot.pypy.org Sun May 26 17:12:51 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 26 May 2013 17:12:51 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: implement missing pieces on x86 backend Message-ID: <20130526151251.AF7831C0134@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64568:cf108e905352 Date: 2013-05-26 17:12 +0200 http://bitbucket.org/pypy/pypy/changeset/cf108e905352/ Log: implement missing pieces on x86 backend diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -79,6 +79,7 @@ allblocks) self.target_tokens_currently_compiling = {} self.frame_depth_to_patch = [] + self._finish_gcmap = lltype.nullptr(jitframe.GCMAP) def teardown(self): self.pending_guard_tokens = None @@ -1806,7 +1807,11 @@ self.mov(fail_descr_loc, RawEbpLoc(ofs)) arglist = op.getarglist() if arglist and arglist[0].type == REF: - gcmap = self.gcmap_for_finish + if self._finish_gcmap: + self._finish_gcmap[0] |= r_uint(1) # rax + gcmap = self._finish_gcmap + else: + gcmap = self.gcmap_for_finish self.push_gcmap(self.mc, gcmap, store=True) else: # note that the 0 here is redundant, but I would rather @@ -2230,6 +2235,15 @@ assert 0 < offset <= 127 self.mc.overwrite(jmp_location - 1, chr(offset)) + def store_force_descr(self, op, fail_locs, frame_depth): + guard_token = self.implement_guard_recovery(op.opnum, + op.getdescr(), + op.getfailargs(), + fail_locs, frame_depth) + self._finish_gcmap = guard_token.gcmap + self._store_force_index(op) + self.store_info_on_descr(0, guard_token) + def force_token(self, reg): # XXX kill me assert isinstance(reg, RegLoc) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1336,6 +1336,11 @@ #if jump_op is not None and jump_op.getdescr() is descr: # self._compute_hint_frame_locations_from_descr(descr) + def consider_guard_not_forced(self, op): + self.rm.before_call([], save_all_regs=True) + fail_locs = [self.loc(v) for v in op.getfailargs()] + self.assembler.store_force_descr(op, fail_locs, + self.fm.get_frame_depth()) def consider_keepalive(self, op): pass From noreply at buildbot.pypy.org Sun May 26 17:16:01 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 26 May 2013 17:16:01 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: rpython fix Message-ID: <20130526151601.735581C0134@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64569:9f037799f1ab Date: 2013-05-26 17:15 +0200 http://bitbucket.org/pypy/pypy/changeset/9f037799f1ab/ Log: rpython fix diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1761,6 +1761,7 @@ if (self.jitdriver_sd.virtualizable_info is not None or self.jitdriver_sd.greenfield_info is not None): virtualizable_boxes = self.virtualizable_boxes + saved_pc = 0 if self.framestack: frame = self.framestack[-1] saved_pc = frame.pc From noreply at buildbot.pypy.org Sun May 26 17:19:41 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 26 May 2013 17:19:41 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: more rpython Message-ID: <20130526151941.A15081C0134@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64570:5464db3b9088 Date: 2013-05-26 17:18 +0200 http://bitbucket.org/pypy/pypy/changeset/5464db3b9088/ Log: more rpython 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 @@ -2,7 +2,7 @@ from rpython.jit.backend.llsupport.memcpy import memcpy_fn from rpython.jit.backend.llsupport.symbolic import WORD from rpython.jit.metainterp.history import (INT, REF, FLOAT, JitCellToken, - ConstInt, BoxInt) + 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, @@ -24,6 +24,7 @@ class GuardToken(object): def __init__(self, cpu, gcmap, faildescr, failargs, fail_locs, exc, frame_depth, is_guard_not_invalidated, is_guard_not_forced): + assert isinstance(faildescr, AbstractFailDescr) self.cpu = cpu self.faildescr = faildescr self.failargs = failargs From noreply at buildbot.pypy.org Sun May 26 17:22:19 2013 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 26 May 2013 17:22:19 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: fix for tests Message-ID: <20130526152219.CA4701C0134@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64571:1aed55951cb9 Date: 2013-05-26 17:21 +0200 http://bitbucket.org/pypy/pypy/changeset/1aed55951cb9/ Log: fix for tests diff --git a/rpython/jit/backend/model.py b/rpython/jit/backend/model.py --- a/rpython/jit/backend/model.py +++ b/rpython/jit/backend/model.py @@ -305,7 +305,8 @@ def bh_force_virtualizable(self, v, descr): vinfo = descr.get_vinfo() - vinfo.clear_vable_token(v) + if vinfo is not None: + vinfo.clear_vable_token(v) class CompiledLoopToken(object): asmmemmgr_blocks = None From noreply at buildbot.pypy.org Sun May 26 18:31:18 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 18:31:18 +0200 (CEST) Subject: [pypy-commit] stmgc default: Two failing tests Message-ID: <20130526163118.D1D4B1C1464@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r20:76c127339cc1 Date: 2013-05-26 17:58 +0200 http://bitbucket.org/pypy/stmgc/changeset/76c127339cc1/ Log: Two failing tests diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -315,3 +315,56 @@ assert lib.getlong(q2, 0) == 424242 r.set(3) run_parallel(f1, f2) + +def test_stubs_are_public_to_young_collect(): + pg = palloc_refs(1) + # + p1 = lib.stm_write_barrier(pg) + assert lib.in_nursery(p1) + lib.stm_push_root(p1) + minor_collect() + p1 = lib.stm_pop_root() + assert not lib.in_nursery(p1) + q1 = nalloc(HDR + WORD) + lib.setlong(q1, 0, 424242) + lib.setptr(p1, 0, q1) + assert not lib.in_nursery(p1) + assert lib.in_nursery(q1) + # + lib.stm_commit_transaction() + lib.stm_begin_inevitable_transaction() + # + assert not lib.in_nursery(p1) # public + assert lib.in_nursery(q1) # protected + lib.stm_push_root(p1) + minor_collect() + p1b = lib.stm_pop_root() + assert p1b == p1 + q1b = lib.getptr(p1, 0) + assert not lib.in_nursery(q1b) + assert lib.getlong(q1b, 0) == 424242 + +def test_stubs_are_public_to_young_steal(): + pg = palloc_refs(1) + seen = [] + def f1(r): + q1 = nalloc(HDR + WORD) + lib.setlong(q1, 0, 424242) + p1 = lib.stm_write_barrier(pg) + lib.setptr(p1, 0, q1) + assert lib.in_nursery(p1) + assert lib.in_nursery(q1) + r.set(2) + r.wait(3) + minor_collect() + p4 = lib.getptr(pg, 0) + assert not lib.in_nursery(p4) # the stub + assert lib.getlong(p4, 0) == 424242 + def f2(r): + r.wait(2) + p2 = lib.stm_read_barrier(pg) # foreign nursery -> old + assert not lib.in_nursery(p2) + assert p2 + # don't read getptr(p2, 0) here, so that it remains as a stub + r.set(3) + run_parallel(f1, f2) From noreply at buildbot.pypy.org Sun May 26 18:31:20 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 18:31:20 +0200 (CEST) Subject: [pypy-commit] stmgc default: Kill CFENCE. Message-ID: <20130526163120.08F8D1C1464@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r21:0ffe3584a6d9 Date: 2013-05-26 18:31 +0200 http://bitbucket.org/pypy/stmgc/changeset/0ffe3584a6d9/ Log: Kill CFENCE. diff --git a/c3/atomic_ops.h b/c3/atomic_ops.h --- a/c3/atomic_ops.h +++ b/c3/atomic_ops.h @@ -13,16 +13,12 @@ #define UNLIKELY(test) __builtin_expect(test, 0) -/* "compiler fence" for preventing reordering of loads/stores to - non-volatiles. Should not be used any more. */ -#define CFENCE asm volatile ("":::"memory") - #if defined(__amd64__) || defined(__i386__) -# define smp_wmb() CFENCE -# define smp_spinloop() asm volatile ("pause") +# define smp_wmb() asm volatile ("":::"memory") +# define smp_spinloop() asm volatile ("pause":::"memory") #elif defined(__powerpc__) # define smp_wmb() asm volatile ("lwsync":::"memory") -# define smp_spinloop() /* fill me? */ +# define smp_spinloop() asm volatile ("":::"memory") /* fill me? */ #else # error "Define smp_wmb() for your architecture" #endif @@ -100,18 +96,9 @@ #endif -static inline void spinloop(void) -{ - smp_spinloop(); - /* use "memory" here to make sure that gcc will reload the - relevant data from memory after the spinloop */ - CFENCE; -} - - #define spinlock_acquire(lock, targetvalue) \ do { if (bool_cas(&(lock), 0, (targetvalue))) break; \ - do { spinloop(); } while (ACCESS_ONCE(lock)); \ + do { smp_spinloop(); } while (ACCESS_ONCE(lock)); \ } while (1) #define spinlock_release(lock) \ diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -404,7 +404,7 @@ assert(d->active >= 1); assert(num < SPINLOOP_REASONS); d->num_spinloops[num]++; - spinloop(); + smp_spinloop(); } #if 0 diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -815,7 +815,7 @@ while (1) { count = ACCESS_ONCE(d->debug_nursery_access); if (count == (revision_t)-1) { - spinloop(); + smp_spinloop(); continue; } if (bool_cas(&d->debug_nursery_access, count, (revision_t)-1)) From noreply at buildbot.pypy.org Sun May 26 18:56:52 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 18:56:52 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix the two previous tests. Message-ID: <20130526165652.4913D1C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r22:1dd1331ec33e Date: 2013-05-26 18:56 +0200 http://bitbucket.org/pypy/stmgc/changeset/1dd1331ec33e/ Log: Fix the two previous tests. diff --git a/c3/lists.c b/c3/lists.c --- a/c3/lists.c +++ b/c3/lists.c @@ -22,6 +22,19 @@ memset(g2l, 0, sizeof(struct G2L)); } +struct G2L *g2l_malloc(void) +{ + struct G2L *g2l = malloc(sizeof(struct G2L)); + memset(g2l, 0, sizeof(struct G2L)); + return g2l; +} + +void g2l_free(struct G2L *g2l) +{ + free(g2l->raw_start); + free(g2l); +} + wlog_t *_g2l_find(char *entry, gcptr addr) { revision_t key = (revision_t)addr; @@ -172,6 +185,16 @@ gcptrlist->size = i + 3; } +void gcptrlist_insert_at_index(struct GcPtrList *gcptrlist, long index, + gcptr newitem) +{ + long lastitem = gcptrlist->size; + assert(index <= lastitem); + gcptrlist_insert(gcptrlist, NULL); + gcptrlist->items[lastitem] = gcptrlist->items[index]; + gcptrlist->items[index] = newitem; +} + void gcptrlist_merge(struct GcPtrList *gcptrlist, struct GcPtrList *gcptrlist_source) { diff --git a/c3/lists.h b/c3/lists.h --- a/c3/lists.h +++ b/c3/lists.h @@ -35,6 +35,8 @@ void g2l_clear(struct G2L *g2l); void g2l_delete(struct G2L *g2l); +struct G2L *g2l_malloc(void); +void g2l_free(struct G2L *g2l); static inline int g2l_any_entry(struct G2L *g2l) { return g2l->raw_current != g2l->raw_start; @@ -133,14 +135,20 @@ void gcptrlist_insert3(struct GcPtrList *gcptrlist, gcptr newitem1, gcptr newitem2, gcptr newitem3); -static inline void gcptrlist_insert(struct GcPtrList *gcptrlist, gcptr newitem) { +/* items[size++] = items[index]; items[index] = newitem; */ +void gcptrlist_insert_at_index(struct GcPtrList *gcptrlist, long index, + gcptr newitem); + +static inline void gcptrlist_insert(struct GcPtrList *gcptrlist, gcptr newitem) +{ if (UNLIKELY(gcptrlist->size == gcptrlist->alloc)) _gcptrlist_grow(gcptrlist); gcptrlist->items[gcptrlist->size++] = newitem; } -static inline void gcptrlist_reduce_size(struct GcPtrList *gcptrlist, long newsize) { - gcptrlist->size = newsize; +static inline void gcptrlist_reduce_size(struct GcPtrList *gcptrlist, long nsz) +{ + gcptrlist->size = nsz; } static inline long gcptrlist_size(struct GcPtrList *gcptrlist) diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -661,19 +661,54 @@ spinlock_release(d->collection_lock); } +static __thread struct G2L *yo_stubs; /* { protected: public_stub } */ + static void create_yo_stubs(gcptr *pobj) { - gcptr obj = *pobj; + gcptr stub, obj = *pobj; if (obj == NULL || (obj->h_tid & GCFLAG_OLD) != 0) return; - /* xxx try to avoid duplicate stubs for the same object */ - gcptr stub = stmgcpage_malloc(sizeof(*stub)); + /* we use 'yo_stubs', a dictionary, in order to try to avoid + duplicate stubs for the same object */ + if (yo_stubs == NULL) { + yo_stubs = g2l_malloc(); + } + else { + wlog_t *item; + G2L_FIND(*yo_stubs, obj, item, goto not_found); + /* found already */ + stub = item->val; + assert(stub->h_revision == (((revision_t)obj) | 2)); + *pobj = stub; + return; + } + + not_found: + stub = stmgcpage_malloc(sizeof(*stub)); stub->h_tid = GCFLAG_OLD | GCFLAG_STUB; /* with type_id == 0 */ stub->h_revision = ((revision_t)obj) | 2; + g2l_insert(yo_stubs, obj, stub); *pobj = stub; } +static long done_creating_yo_stubs(struct GcPtrList *add_to_list, long index) +{ + wlog_t *item; + struct G2L *stubs = yo_stubs; + if (stubs == NULL) + return index; + + G2L_LOOP_FORWARD(*stubs, item) { + gcptrlist_insert_at_index(add_to_list, index, item->val); + index++; + } G2L_LOOP_END; + + g2l_free(stubs); + yo_stubs = NULL; + return index; +} + static void fix_new_public_to_protected_references(struct tx_descriptor *d) { long i, size = d->private_old_pointing_to_young.size; @@ -683,6 +718,8 @@ stmcb_trace(items[i], &create_yo_stubs); } gcptrlist_clear(&d->private_old_pointing_to_young); + d->num_public_to_protected = done_creating_yo_stubs( + &d->public_to_young, d->num_public_to_protected); } static void free_unvisited_young_objects_outside_nursery( @@ -900,12 +937,20 @@ /* R is now the protected object to move outside, with revision v. */ N = create_old_object_copy(R _REASON("**stolen copy")); N->h_revision = v; - gcptrlist_insert2(&source_d->stolen_objects, R, N); + gcptrlist_insert3(&source_d->stolen_objects, R, N, NULL); /* there might be references in N going to protected objects. We must fix them with stubs. */ stmcb_trace(N, &create_yo_stubs); + /* Cannot insert them here into the 'public_to_young' list, because + it might be accessed concurrently by the thread 'source_d'. + Instead we put them into stolen_objects. They are inserted + at position 'size - 1', which means just before the final NULL + that was already pushed by the above gcptrlist_insert3(). */ + done_creating_yo_stubs(&source_d->stolen_objects, + source_d->stolen_objects.size - 1); + return N; } @@ -980,7 +1025,7 @@ gcptr *items = d->stolen_objects.items; assert(d == thread_descriptor); - for (i = 0; i < size; i += 2) { + for (i = 0; i < size; ) { gcptr R = items[i]; gcptr N = items[i + 1]; @@ -1007,6 +1052,17 @@ gcptrlist_insert(&d->public_to_young, N); } recdump1("STOLEN", R); + + /* then all items from i+2 up to the first NULL are new stubs + that must be added to d->public_to_young, in the first part + (i.e. before d->num_public_to_protected) */ + i += 2; + long ptp = d->num_public_to_protected; + while ((N = items[i++]) != NULL) { + gcptrlist_insert_at_index(&d->public_to_young, ptp, N); + ptp++; + } + d->num_public_to_protected = ptp; } gcptrlist_clear(&d->stolen_objects); } From noreply at buildbot.pypy.org Sun May 26 18:58:43 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 18:58:43 +0200 (CEST) Subject: [pypy-commit] stmgc default: Demo1 passes (slowly) with multiple threads! Yay. Message-ID: <20130526165843.E91BD1C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r23:0da44e8495d9 Date: 2013-05-26 18:58 +0200 http://bitbucket.org/pypy/stmgc/changeset/0da44e8495d9/ Log: Demo1 passes (slowly) with multiple threads! Yay. diff --git a/c3/demo1.c b/c3/demo1.c --- a/c3/demo1.c +++ b/c3/demo1.c @@ -10,8 +10,8 @@ #include "stmgc.h" -#define UPPER_BOUND 2500 -#define NUMTHREADS 2 +#define UPPER_BOUND 250 +#define NUMTHREADS 4 #define GCTID_STRUCT_NODE 123 From noreply at buildbot.pypy.org Sun May 26 19:10:54 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 19:10:54 +0200 (CEST) Subject: [pypy-commit] stmgc default: A "mark" and a test checking for that mark. Message-ID: <20130526171054.061941C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r24:2360127bd31b Date: 2013-05-26 19:10 +0200 http://bitbucket.org/pypy/stmgc/changeset/2360127bd31b/ Log: A "mark" and a test checking for that mark. diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -681,6 +681,7 @@ stub = item->val; assert(stub->h_revision == (((revision_t)obj) | 2)); *pobj = stub; + /*mark*/ return; } diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -317,7 +317,7 @@ run_parallel(f1, f2) def test_stubs_are_public_to_young_collect(): - pg = palloc_refs(1) + pg = palloc_refs(2) # p1 = lib.stm_write_barrier(pg) assert lib.in_nursery(p1) @@ -328,6 +328,7 @@ q1 = nalloc(HDR + WORD) lib.setlong(q1, 0, 424242) lib.setptr(p1, 0, q1) + lib.setptr(p1, 1, q1) assert not lib.in_nursery(p1) assert lib.in_nursery(q1) # @@ -341,6 +342,7 @@ p1b = lib.stm_pop_root() assert p1b == p1 q1b = lib.getptr(p1, 0) + assert q1b == lib.getptr(p1, 1) assert not lib.in_nursery(q1b) assert lib.getlong(q1b, 0) == 424242 From noreply at buildbot.pypy.org Sun May 26 19:38:47 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 19:38:47 +0200 (CEST) Subject: [pypy-commit] stmgc default: Give more explanations. Message-ID: <20130526173847.62FC51C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r25:052abdf72589 Date: 2013-05-26 19:34 +0200 http://bitbucket.org/pypy/stmgc/changeset/052abdf72589/ Log: Give more explanations. diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -377,7 +377,13 @@ return; } - /* then check if 'obj' was visited at all, and remove it if not */ + /* on the other hand, if we see a non-visited object in the read + list, then we need to remove it --- it's wrong to just abort. + Consider the following case: the transaction is inevitable, + and since it started, it popped objects out of its shadow + stack. Some popped objects might become free even if they + have been read from. We must not abort such transactions + (and cannot anyway: they are inevitable!). */ if (!(obj->h_tid & GCFLAG_VISITED)) { items[i] = items[--d->list_of_read_objects.size]; } diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -624,7 +624,9 @@ abort because of it) or it's because it was already modified. */ if (obj->h_revision & 1) { - /* first case: untrack it */ + /* first case: untrack it. Note that this case can occur + without aborting the transaction. See gcpage's + cleanup_for_thread() for an explanation how. */ abort();//XXX items[i] = items[--d->list_of_read_objects.size]; } @@ -719,8 +721,10 @@ stmcb_trace(items[i], &create_yo_stubs); } gcptrlist_clear(&d->private_old_pointing_to_young); - d->num_public_to_protected = done_creating_yo_stubs( - &d->public_to_young, d->num_public_to_protected); + + i = d->num_public_to_protected; + i = done_creating_yo_stubs(&d->public_to_young, i); + d->num_public_to_protected = i; } static void free_unvisited_young_objects_outside_nursery( From noreply at buildbot.pypy.org Sun May 26 19:38:48 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 19:38:48 +0200 (CEST) Subject: [pypy-commit] stmgc default: A test for this "abort();//XXX". Message-ID: <20130526173848.9DA671C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r26:16ed97ae9fa2 Date: 2013-05-26 19:38 +0200 http://bitbucket.org/pypy/stmgc/changeset/16ed97ae9fa2/ Log: A test for this "abort();//XXX". diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -627,8 +627,8 @@ /* first case: untrack it. Note that this case can occur without aborting the transaction. See gcpage's cleanup_for_thread() for an explanation how. */ - abort();//XXX items[i] = items[--d->list_of_read_objects.size]; + /*mark*/ } else { /* second case */ diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -370,3 +370,17 @@ # don't read getptr(p2, 0) here, so that it remains as a stub r.set(3) run_parallel(f1, f2) + +def test_remove_from_list_of_read_objects(): + p1 = nalloc(HDR) + # + lib.stm_push_root(p1) + lib.stm_commit_transaction() + lib.stm_begin_inevitable_transaction() + p1 = lib.stm_pop_root() + # + assert lib.in_nursery(p1) + p2 = lib.stm_read_barrier(p1) + assert p2 == p1 + # but now, p1 is no longer a root + minor_collect() From noreply at buildbot.pypy.org Sun May 26 19:43:30 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 19:43:30 +0200 (CEST) Subject: [pypy-commit] stmgc default: A bug found by demo2 Message-ID: <20130526174330.EB6641C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r27:996b6b7bd70e Date: 2013-05-26 19:43 +0200 http://bitbucket.org/pypy/stmgc/changeset/996b6b7bd70e/ Log: A bug found by demo2 diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -730,8 +730,10 @@ if (cur_time & 1) { // there is another inevitable transaction CancelLocks(d); + stmgc_suspend_commit_transaction(d); inev_mutex_acquire(); // wait until released inev_mutex_release(); + stmgc_stop_transaction(d); AcquireLocks(d); continue; } diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -212,6 +212,13 @@ fprintf(stderr, "stop transaction\n"); } +void stmgc_suspend_commit_transaction(struct tx_descriptor *d) +{ + /* used only when commit is suspended by another thread being + inevitable. Later stmgc_stop_transaction() will be called again. */ + spinlock_release(d->collection_lock); +} + void stmgc_committed_transaction(struct tx_descriptor *d) { spinlock_release(d->collection_lock); diff --git a/c3/nursery.h b/c3/nursery.h --- a/c3/nursery.h +++ b/c3/nursery.h @@ -35,6 +35,7 @@ gcptr stmgc_duplicate(gcptr, revision_t); void stmgc_start_transaction(struct tx_descriptor *); void stmgc_stop_transaction(struct tx_descriptor *); +void stmgc_suspend_commit_transaction(struct tx_descriptor *d); void stmgc_committed_transaction(struct tx_descriptor *); void stmgc_abort_transaction(struct tx_descriptor *); void stmgc_init_tls(void); From noreply at buildbot.pypy.org Sun May 26 19:50:23 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 19:50:23 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix an assert statement Message-ID: <20130526175024.018651C1000@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r28:73bbd9d06ac6 Date: 2013-05-26 19:50 +0200 http://bitbucket.org/pypy/stmgc/changeset/73bbd9d06ac6/ Log: Fix an assert statement diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -403,7 +403,10 @@ G2L_LOOP_FORWARD(d->public_to_private, item) { assert(stmgc_classify(item->addr) == K_PUBLIC); - assert(stmgc_classify(item->val) == K_PRIVATE); + /*..rt(stmgc_classify(item->val) == K_PRIVATE); but in the + other thread, which becomes: */ + assert(item->val->h_revision == *d->local_revision_ref); + item->addr->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE; } G2L_LOOP_END; From noreply at buildbot.pypy.org Sun May 26 20:07:57 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 20:07:57 +0200 (CEST) Subject: [pypy-commit] stmgc default: Split these two cases into three, and implement one more. Message-ID: <20130526180757.459671C1000@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r29:09c8f542c33d Date: 2013-05-26 20:07 +0200 http://bitbucket.org/pypy/stmgc/changeset/09c8f542c33d/ Log: Split these two cases into three, and implement one more. diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -625,10 +625,15 @@ /*mark*/ continue; } - /* The listed object was not visited. Either it's because it - is really unreachable (in which case it cannot possibly - be modified any more, and the current transaction cannot - abort because of it) or it's because it was already modified. + /* The listed object was not visited. Three cases: + + 1. it is really unreachable (in which case it cannot possibly + be modified any more, and the current transaction cannot + abort because of it) + + 2. it is a stolen object + + 3. it is not visited because it has already been modified. */ if (obj->h_revision & 1) { /* first case: untrack it. Note that this case can occur @@ -637,8 +642,15 @@ items[i] = items[--d->list_of_read_objects.size]; /*mark*/ } + else if (obj->h_tid & GCFLAG_STOLEN) { + /* second case: 'obj' was stolen. Just replace it in the + list with its new copy, which should be identical + (and public, so no more processing it needed). */ + assert(dclassify((gcptr)obj->h_revision) == K_PUBLIC); + items[i] = (gcptr)obj->h_revision; + } else { - /* second case */ + /* third case */ abort();//XXX /* ABRT_COLLECT_MINOR ... check for stolen object */ diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -384,3 +384,22 @@ assert p2 == p1 # but now, p1 is no longer a root minor_collect() + +def test_read_from_stolen_object(): + pg = palloc(HDR + WORD) + def f1(r): + lib.setlong(pg, 0, 519833) + def cb(c): + assert c == 0 + p1 = lib.stm_read_barrier(pg) + r.wait_while_in_parallel() + minor_collect() + perform_transaction(cb) + def f2(r): + def cb(c): + assert c == 0 + r.enter_in_parallel() + assert lib.getlong(pg, 0) == 519833 # steal object + perform_transaction(cb) + r.leave_in_parallel() + run_parallel(f1, f2) From noreply at buildbot.pypy.org Sun May 26 20:30:51 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 20:30:51 +0200 (CEST) Subject: [pypy-commit] stmgc default: Test and implementation of another "abort(); //XXX". Message-ID: <20130526183051.26EB11C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r30:d872b4ad04ef Date: 2013-05-26 20:30 +0200 http://bitbucket.org/pypy/stmgc/changeset/d872b4ad04ef/ Log: Test and implementation of another "abort();//XXX". diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -513,7 +513,7 @@ { if (d->active >= 0) { - assert(d->active == 1); + assert(d->active == 1); /* not 2, which means inevitable */ d->active = -reason; } assert(d->active < 0); @@ -523,7 +523,11 @@ { struct tx_descriptor *d = thread_descriptor; if (d->active < 0) - AbortTransaction(-d->active); + { + int reason = -d->active; + d->active = 1; + AbortTransaction(reason); + } } /************************************************************/ diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -634,6 +634,7 @@ 2. it is a stolen object 3. it is not visited because it has already been modified. + But this case cannot occur: the object is still protected */ if (obj->h_revision & 1) { /* first case: untrack it. Note that this case can occur @@ -643,17 +644,29 @@ /*mark*/ } else if (obj->h_tid & GCFLAG_STOLEN) { - /* second case: 'obj' was stolen. Just replace it in the - list with its new copy, which should be identical - (and public, so no more processing it needed). */ - assert(dclassify((gcptr)obj->h_revision) == K_PUBLIC); - items[i] = (gcptr)obj->h_revision; + /* second case: 'obj' was stolen. We check to see if + the public version was already outdated. If not, we + replace 'obj' in the list with this public version, + which should be identical. */ + gcptr P = (gcptr)obj->h_revision; + assert(dclassify(P) == K_PUBLIC); + + if (P->h_revision & 1) { /* "is not a pointer" */ + items[i] = P; + /*mark*/ + } + else { + /* P has already been changed. Mark as abort. */ + AbortTransactionAfterCollect(d, ABRT_COLLECT_MINOR); + /*mark*/ + gcptrlist_clear(&d->list_of_read_objects); + break; + } } else { - /* third case */ - abort();//XXX - /* ABRT_COLLECT_MINOR ... check - for stolen object */ + /* third case: impossible */ + assert(!"third case of fix_list_of_read_objects"); + abort(); } } d->num_read_objects_known_old = d->list_of_read_objects.size; diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -392,6 +392,7 @@ def cb(c): assert c == 0 p1 = lib.stm_read_barrier(pg) + assert lib.in_nursery(p1) r.wait_while_in_parallel() minor_collect() perform_transaction(cb) @@ -403,3 +404,28 @@ perform_transaction(cb) r.leave_in_parallel() run_parallel(f1, f2) + +def test_read_from_modified_stolen_object(): + pg = palloc(HDR + WORD) + seen = [] + def f1(r): + lib.setlong(pg, 0, 287221) + def cb(c): + if c == 0: + p1 = lib.stm_read_barrier(pg) + assert lib.in_nursery(p1) + r.wait_while_in_parallel() + seen.append("ok") + minor_collect() + raise AssertionError("we should not reach this!") + else: + assert seen == ["ok"] + perform_transaction(cb) + def f2(r): + def cb(c): + assert c == 0 + r.enter_in_parallel() + lib.setlong(pg, 0, -66666) # steal object + perform_transaction(cb) + r.leave_in_parallel() + run_parallel(f1, f2, max_aborts=1) From noreply at buildbot.pypy.org Sun May 26 20:52:41 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 20:52:41 +0200 (CEST) Subject: [pypy-commit] stmgc default: Redo _stm_nonrecord_barrier(), which lets test_random start, at least. Message-ID: <20130526185241.0391E1C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r31:fc3ea5414a31 Date: 2013-05-26 20:52 +0200 http://bitbucket.org/pypy/stmgc/changeset/fc3ea5414a31/ Log: Redo _stm_nonrecord_barrier(), which lets test_random start, at least. diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -171,7 +171,6 @@ return R; } -#if 0 static gcptr _latest_gcptr(gcptr R) { /* don't use, for tests only */ @@ -183,40 +182,46 @@ if (v & 2) { v &= ~2; - if (!is_young((gcptr)v)) - { - stmgc_follow_foreign(R); - goto retry; - } + if (!stmgc_is_young_in(thread_descriptor, (gcptr)v)) + return NULL; /* can't access */ } R = (gcptr)v; goto retry; } return R; } -#endif gcptr _stm_nonrecord_barrier(gcptr obj, int *result) { - abort();//XXX -#if 0 /* warning, this is for tests only, and it is not thread-safe! */ - if (obj->h_revision == stm_local_revision) + enum protection_class_t e = stmgc_classify(obj); + if (e == K_PRIVATE) { - *result = 2; /* 'obj' a local object to start with */ + *result = 2; /* 'obj' a private object to start with */ return obj; } obj = _latest_gcptr(obj); + if (obj == NULL) + { + assert(e == K_PUBLIC); + *result = 3; /* can't check anything: we'd need foreign access */ + return NULL; + } + if (stmgc_classify(obj) == K_PRIVATE) + { + *result = 1; + return obj; + } struct tx_descriptor *d = thread_descriptor; wlog_t *item; - G2L_LOOP_FORWARD(d->global_to_local, item) + G2L_LOOP_FORWARD(d->public_to_private, item) { gcptr R = item->addr; gcptr L = item->val; if (_latest_gcptr(R) == obj) { - /* 'obj' has a local version. The way we detect this lets us + /* 'obj' has a private version. The way we detect this lets us find it even if we already have a committed version that will cause conflict. */ *result = 1; @@ -226,17 +231,16 @@ if (obj->h_revision > d->start_time) { - /* 'obj' has no local version, and the global version was modified */ + /* 'obj' has no private version, and the public version was modified */ *result = -1; return NULL; } else { - /* 'obj' has only an up-to-date global version */ + /* 'obj' has only an up-to-date public version */ *result = 0; return obj; } -#endif } #if 0 diff --git a/c3/test/test_random.py b/c3/test/test_random.py --- a/c3/test/test_random.py +++ b/c3/test/test_random.py @@ -99,7 +99,7 @@ self.check(p) try: self.current_rev.write(r.obj, index, p.obj) - if not self.is_local(r.ptr): + if not self.is_private(r.ptr): self.current_rev.check_not_outdated(r.obj) except (model.Deleted, model.Conflict): # abort! try to reproduce with C code @@ -117,7 +117,7 @@ return emptypair try: pobj = self.current_rev.read(r.obj, index) - if not self.is_local(r.ptr): + if not self.is_private(r.ptr): self.current_rev.check_not_outdated(r.obj) except (model.Deleted, model.Conflict): # abort! try to reproduce with C code @@ -140,7 +140,7 @@ self.check(p) try: self.current_rev.read_barrier(p.obj) - if not self.is_local(p.ptr): + if not self.is_private(p.ptr): self.current_rev.check_not_outdated(p.obj) except (model.Deleted, model.Conflict): # abort! try to reproduce with C code @@ -159,7 +159,7 @@ self.check(p) try: self.current_rev.write_barrier(p.obj) - if not self.is_local(p.ptr): + if not self.is_private(p.ptr): self.current_rev.check_not_outdated(p.obj) except (model.Deleted, model.Conflict): # abort! try to reproduce with C code @@ -195,7 +195,7 @@ ptr = lib._stm_nonrecord_barrier(ptr, result) return ptr, result[0] - def is_local(self, ptr): + def is_private(self, ptr): return ptr.h_revision == lib.get_local_revision() def check_valid(self, lst): @@ -208,9 +208,11 @@ self.check(p) ptr, result = self.nonrecord_barrier(p.ptr) - has_local_copy = p.obj in self.current_rev.content - assert has_local_copy == (result >= 1) - if has_local_copy: + if ptr == ffi.NULL and result == 3: + continue # can't check anything: we'd need foreign access + has_private_copy = p.obj in self.current_rev.content + assert has_private_copy == (result >= 1) + if has_private_copy: content = self.current_rev.content[p.obj] else: try: From noreply at buildbot.pypy.org Sun May 26 21:07:41 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 21:07:41 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix an assert Message-ID: <20130526190741.891D91C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r32:43d9d5cfca8b Date: 2013-05-26 21:07 +0200 http://bitbucket.org/pypy/stmgc/changeset/43d9d5cfca8b/ Log: Fix an assert diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -48,16 +48,18 @@ if (is_in_nursery(d, obj)) { e = private ? K_PRIVATE : K_PROTECTED; } - else { - wlog_t *entry; - G2L_FIND(d->young_objects_outside_nursery, obj, entry, - goto not_found); - + else if (g2l_contains(&d->young_objects_outside_nursery, obj)) { if (obj->h_tid & GCFLAG_OLD) e = private ? K_OLD_PRIVATE : K_PUBLIC; else e = private ? K_PRIVATE : K_PROTECTED; } + else { + assert(stm_dbgmem_is_active(obj, 1)); + assert(obj->h_tid & GCFLAG_OLD); + return private ? K_OLD_PRIVATE : K_PUBLIC; + } + assert(stm_dbgmem_is_active(obj, 0)); if (e == K_PRIVATE || e == K_PROTECTED) assert((obj->h_tid & GCFLAG_OLD) == 0); @@ -66,13 +68,26 @@ if (e != K_PROTECTED) assert(!(obj->h_tid & GCFLAG_STOLEN)); return e; +} - not_found: - assert(stm_dbgmem_is_active(obj, 1)); - assert(obj->h_tid & GCFLAG_OLD); - return private ? K_OLD_PRIVATE : K_PUBLIC; +static enum protection_class_t dclassify_at_start_of_collection(gcptr obj) +{ + struct tx_descriptor *d = thread_descriptor; + + enum protection_class_t e = dclassify(obj); + + if (g2l_contains(&d->young_objects_outside_nursery, obj) && + (obj->h_tid & GCFLAG_OLD)) { + switch (e) { + case K_OLD_PRIVATE: e = K_PRIVATE; break; + case K_PUBLIC: e = K_PROTECTED; break; + default: abort(); + } + } + return e; } + void stmgc_init_tls(void) { struct tx_descriptor *d = thread_descriptor; @@ -498,7 +513,7 @@ if (v & 2) { /* a pointer with bit 2 set. Normally set, except if R was stolen */ L = (gcptr)(v & ~2); - assert(dclassify(L) == K_PROTECTED); + assert(dclassify_at_start_of_collection(L) == K_PROTECTED); visit_if_young(&L _REASON("public.h_rev=PROTECTED")); /* The new value of L is the previously-protected object moved outside. We can't store it immediately in R->h_revision! From noreply at buildbot.pypy.org Sun May 26 21:14:28 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 21:14:28 +0200 (CEST) Subject: [pypy-commit] stmgc default: progress Message-ID: <20130526191428.8C1731C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r33:34499de37f69 Date: 2013-05-26 21:14 +0200 http://bitbucket.org/pypy/stmgc/changeset/34499de37f69/ Log: progress diff --git a/c3/test/support.py b/c3/test/support.py --- a/c3/test/support.py +++ b/c3/test/support.py @@ -96,6 +96,7 @@ #define GCFLAG_WRITE_BARRIER ... #define GCFLAG_NURSERY_MOVED ... #define GCFLAG_OLD ... + #define GCFLAG_STUB ... #define ABRT_MANUAL ... typedef struct { ...; } page_header_t; ''') @@ -451,6 +452,12 @@ def minor_collect(): lib.stmgc_minor_collect() +STUB_TID = GCFLAG_STUB | GCFLAG_OLD | 0 # no user tid + +def is_stub(p): + assert lib.stm_dbgmem_is_active(p, 1) != 0 + return p.h_tid == STUB_TID + def check_not_free(p): assert lib.stm_dbgmem_is_active(p, 1) == 1 assert 42 < (p.h_tid & 0xFFFF) < 521 diff --git a/c3/test/test_random.py b/c3/test/test_random.py --- a/c3/test/test_random.py +++ b/c3/test/test_random.py @@ -78,7 +78,7 @@ def check(self, p): assert isinstance(p, Pair) - if p != emptypair: + if p != emptypair and not is_stub(p.ptr): self.check_not_free(p.ptr) pid = lib.rawgetptr(p.ptr, 2) assert pid == p.obj.identity @@ -387,7 +387,7 @@ if k1 == 82 and self.interruptible_transaction: self.dump('~~~~~~~~~~~~~~~~~~~~ ABORT ~~~~~~~~~~~~~~~~~~~~') self.expected_abort(manual=True) - lib.stm_abort_and_retry() + abort_and_retry() elif k == 12: # only do an stm_read_barrier p = self.read_barrier(p) self.dump('-') From noreply at buildbot.pypy.org Sun May 26 21:35:34 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Sun, 26 May 2013 21:35:34 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: fix ztranslation: try some fallbacks when we can't grab a space during tests Message-ID: <20130526193534.337671C0134@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64572:ef8b5a2f97b4 Date: 2013-05-26 12:27 -0700 http://bitbucket.org/pypy/pypy/changeset/ef8b5a2f97b4/ Log: fix ztranslation: try some fallbacks when we can't grab a space during tests diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -298,6 +298,17 @@ """ self._application_traceback = traceback +def _space_from_type(w_type): + """Grab a space if a W_TypeObject, or None""" + from pypy.objspace.std.typeobject import W_TypeObject + # HACK: isinstance(w_type, W_TypeObject) won't translate under the + # fake objspace, but w_type.__class__ is W_TypeObject does and short + # circuits to a False constant there, causing the isinstance to be + # ignored =[ + if (w_type is not None and w_type.__class__ is W_TypeObject and + isinstance(w_type, W_TypeObject)): + return w_type.space + # ____________________________________________________________ # optimization only: avoid the slowest operation -- the string # formatting with '%' -- in the common case were we don't @@ -305,7 +316,7 @@ _fmtcache = {} _fmtcache2 = {} -_FMTS = tuple('sdNT') +_FMTS = tuple('dsNT') def decompose_valuefmt(valuefmt): """Returns a tuple of string parts extracted from valuefmt, @@ -328,14 +339,24 @@ assert len(formats) > 0, "unsupported: no % command found" return tuple(parts), tuple(formats) -def _is_type(w_obj): - from pypy.objspace.std.typeobject import W_TypeObject - # HACK: isinstance(w_obj, W_TypeObject) won't translate under the - # fake objspace, but w_obj.__class__ is W_TypeObject does and short - # circuits to a False constant there, causing the isinstance to be - # ignored =[ - return (w_obj is not None and w_obj.__class__ is W_TypeObject and - isinstance(w_obj, W_TypeObject)) +def _format_NT(space, fmt, w_value): + """Process operationerrfmt's %N/T formats""" + if space is not None: + if fmt == 'T': + w_value = space.type(w_value) + return w_value.getname(space) + elif not we_are_translated(): + # may not be able to grab space due to testing environments, + # fallback + if fmt == 'T': + tp = type(w_value) + typedef = getattr(tp, 'typedef', None) + return tp.__name__ if typedef is None else typedef.name + for attr in 'name', '__name__': + name = getattr(w_value, attr, None) + if name is not None: + return name + return '?' def get_operrcls2(valuefmt): strings, formats = decompose_valuefmt(valuefmt) @@ -355,21 +376,16 @@ for i, _, attr in entries: setattr(self, attr, args[i]) assert w_type is not None - # space may be None during tests - self.space = w_type.space if _is_type(w_type) else None def _compute_value(self): - space = self.space lst = [None] * (len(formats) + len(formats) + 1) for i, fmt, attr in entries: string = self.xstrings[i] value = getattr(self, attr) lst[i+i] = string - if fmt == 'T': - type_ = type if space is None else space.type - value = type_(value) - if fmt in 'NT' and space is not None: - lst[i+i+1] = value.getname(space) + if fmt in 'NT': + lst[i+i+1] = _format_NT(_space_from_type(self.w_type), + fmt, value) else: lst[i+i+1] = str(value) lst[-1] = self.xstrings[-1] @@ -391,10 +407,10 @@ More efficient in the (common) case where the value is not actually needed. - Also supports the following extra format characters: + Supports the standard %s and %d formats, plus the following: - %N - The result of arg.getname(space) - %T - The result of space.type(arg).getname(space) + %N - The result of w_arg.getname(space) + %T - The result of space.type(w_arg).getname(space) """ OpErrFmt, strings = get_operationerr_class(valuefmt) diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -38,16 +38,28 @@ "'%T' object has no attribute '%s'", space.wrap('foo'), 'foo') assert operr._compute_value() == "'str' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%T' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value() == "'str' object has no attribute 'foo'" def test_operationerrfmt_N(space): operr = operationerrfmt(space.w_AttributeError, "'%N' object has no attribute '%s'", space.type(space.wrap('foo')), 'foo') assert operr._compute_value() == "'str' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%N' object has no attribute '%s'", + space.type(space.wrap('foo')), 'foo') + assert operr._compute_value() == "'str' object has no attribute 'foo'" operr = operationerrfmt(space.w_AttributeError, "'%N' object has no attribute '%s'", space.wrap('foo'), 'foo') assert operr._compute_value() == "'?' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%N' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value() == "'?' object has no attribute 'foo'" def test_operationerrfmt_empty(): py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") From noreply at buildbot.pypy.org Sun May 26 21:36:15 2013 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 26 May 2013 21:36:15 +0200 (CEST) Subject: [pypy-commit] stmgc default: A passing test Message-ID: <20130526193615.9E6971C0134@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r34:06cf903b575b Date: 2013-05-26 21:28 +0200 http://bitbucket.org/pypy/stmgc/changeset/06cf903b575b/ Log: A passing test diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -429,3 +429,22 @@ perform_transaction(cb) r.leave_in_parallel() run_parallel(f1, f2, max_aborts=1) + +def test_private_copy_and_collect(): + p1 = nalloc(HDR + WORD) + lib.rawsetlong(p1, 0, 999) + lib.stm_push_root(p1) + i = 1000 + while True: + lib.stm_commit_transaction() + lib.stm_begin_inevitable_transaction() + p2 = lib.stm_write_barrier(p1) + lib.rawsetlong(p2, 0, i) + if not lib.in_nursery(p2): # at some point the nursery is full + break + p1 = p2 + i += 1 + minor_collect() + p1 = lib.stm_pop_root() + assert lib.rawgetlong(p1, 0) == i - 1 + assert lib.getlong(p1, 0) == i From noreply at buildbot.pypy.org Sun May 26 23:17:31 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 26 May 2013 23:17:31 +0200 (CEST) Subject: [pypy-commit] pypy default: fix tests for 32 bit Message-ID: <20130526211731.7BD031C13E5@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r64573:af17470a3036 Date: 2013-05-26 23:52 +0300 http://bitbucket.org/pypy/pypy/changeset/af17470a3036/ Log: fix tests for 32 bit diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -786,7 +786,7 @@ def test_create_subarrays(self): from numpypy import dtype - d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + d = dtype([("x", "float", (2,)), ("y", "int64", (2,))]) assert d.itemsize == 32 assert d.name == "void256" keys = d.fields.keys() diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2715,7 +2715,7 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") @@ -2735,7 +2735,7 @@ def test_multidim_subarray(self): from numpypy import dtype, array - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") From noreply at buildbot.pypy.org Sun May 26 23:17:32 2013 From: noreply at buildbot.pypy.org (mattip) Date: Sun, 26 May 2013 23:17:32 +0200 (CEST) Subject: [pypy-commit] pypy default: make zjit tests not fail for subarrays (they now skip like before) Message-ID: <20130526211732.B250C1C13E5@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r64574:a3b2d7c354c6 Date: 2013-05-27 00:16 +0300 http://bitbucket.org/pypy/pypy/changeset/a3b2d7c354c6/ Log: make zjit tests not fail for subarrays (they now skip like before) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -254,6 +254,8 @@ descr__new__, _get_dtype = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): + _attrs_ = ['ofs', 'dtype', 'arr'] + _immutable_fields_ = ['ofs'] def __init__(self, arr, ofs, dtype): self.arr = arr # we have to keep array alive self.ofs = ofs diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1705,8 +1705,10 @@ def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match + from interp_dtype import W_Dtype items_w = space.fixedview(w_items) subdtype = dtype.subdtype + assert isinstance(subdtype, W_Dtype) itemtype = subdtype.itemtype if len(shape) <= 1: for i in range(len(items_w)): From noreply at buildbot.pypy.org Mon May 27 08:32:29 2013 From: noreply at buildbot.pypy.org (andrewsmedina) Date: Mon, 27 May 2013 08:32:29 +0200 (CEST) Subject: [pypy-commit] lang-js default: fixed get attribute indexes for indexOf and lastIndexOf. Message-ID: <20130527063229.60D031C0189@cobra.cs.uni-duesseldorf.de> Author: Andrews Medina Branch: Changeset: r395:7a721786be34 Date: 2013-05-27 01:31 -0300 http://bitbucket.org/pypy/lang-js/changeset/7a721786be34/ Log: fixed get attribute indexes for indexOf and lastIndexOf. diff --git a/js/builtins/array.py b/js/builtins/array.py --- a/js/builtins/array.py +++ b/js/builtins/array.py @@ -56,12 +56,9 @@ o = this.ToObject() from_index = get_arg(args, 0).ToUInt32() to_index = get_arg(args, 1).ToUInt32() - n = [] - for k in xrange(from_index, to_index): n.append(o.get(unicode(str(k)))) - return _w(n) @@ -221,7 +218,7 @@ from js.jsobj import W_IntNumber for i in xrange(from_index, -1, -1): - y = obj.get(unicode(i)) + y = obj.get(unicode(str(i))) if elem == y: return W_IntNumber(i) return W_IntNumber(-1) @@ -236,7 +233,7 @@ from js.jsobj import W_IntNumber for i in xrange(from_index, length): - y = obj.get(unicode(i)) + y = obj.get(unicode(str(i))) if elem == y: return W_IntNumber(i) return W_IntNumber(-1) From noreply at buildbot.pypy.org Mon May 27 09:42:29 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 09:42:29 +0200 (CEST) Subject: [pypy-commit] stmgc default: Test and fix. Message-ID: <20130527074229.CFB5E1C13E5@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r35:2566855246b2 Date: 2013-05-27 09:42 +0200 http://bitbucket.org/pypy/stmgc/changeset/2566855246b2/ Log: Test and fix. diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -103,8 +103,15 @@ /* we update R_prev->h_revision as a shortcut */ /* XXX check if this really gives a worse performance than only doing this write occasionally based on a counter in d */ + R = (gcptr)v; + if (R->h_revision == stm_local_revision) + { + /* must not update an older h_revision to go directly to + the private copy at the end of a chain of protected + objects! */ + return R; + } R_prev->h_revision = v; - R = (gcptr)v; goto retry; } } diff --git a/c3/test/test_nursery.py b/c3/test/test_nursery.py --- a/c3/test/test_nursery.py +++ b/c3/test/test_nursery.py @@ -448,3 +448,19 @@ p1 = lib.stm_pop_root() assert lib.rawgetlong(p1, 0) == i - 1 assert lib.getlong(p1, 0) == i + +def test_dont_update_revision_to_point_to_private(): + p1 = nalloc(HDR) + for i in range(50): + pstart = p1 + lib.stm_push_root(pstart) + while True: + lib.stm_commit_transaction() + lib.stm_begin_inevitable_transaction() + p1 = lib.stm_write_barrier(p1) + if not lib.in_nursery(p1): + break + for i in range(10): + lib.stm_read_barrier(pstart) # compress the chain + minor_collect() + p1 = lib.stm_pop_root() From noreply at buildbot.pypy.org Mon May 27 09:57:00 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 27 May 2013 09:57:00 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: merge default Message-ID: <20130527075700.8FB251C13EB@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64575:3b08d6880292 Date: 2013-05-27 09:22 +0200 http://bitbucket.org/pypy/pypy/changeset/3b08d6880292/ Log: merge default diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -166,8 +166,7 @@ if self is StructOrUnion: return if '_fields_' not in self.__dict__: - self._fields_ = [] - _set_shape(self, [], self._is_union) + self._fields_ = [] # As a side-effet, this also sets the ffishape. __setattr__ = struct_setattr diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -163,6 +163,9 @@ $ genreflex MyClass.h $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex +Next, make sure that the library can be found through the dynamic lookup path +(the ``LD_LIBRARY_PATH`` environment variable on Linux, ``PATH`` on Windows), +for example by adding ".". Now you're ready to use the bindings. Since the bindings are designed to look pythonistic, it should be straightforward:: diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,14 +124,21 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - if space.config.objspace.usemodules.thread: - os_thread.setup_threads(space) - rffi.aroundstate.before() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - if space.config.objspace.usemodules.thread: - rthread.gc_thread_start() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + os_thread.bootstrapper.acquire(space, None, None) + rthread.gc_thread_start() + os_thread.bootstrapper.nbthreads += 1 + os_thread.bootstrapper.release() + rffi.aroundstate.before() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -16,6 +16,11 @@ else: return space.int_w(w_size) +def unsupported(space, message): + w_exc = space.getattr(space.getbuiltinmodule('_io'), + space.wrap('UnsupportedOperation')) + return OperationError(w_exc, space.wrap(message)) + # May be called with any object def check_readable_w(space, w_obj): if not space.is_true(space.call_method(w_obj, 'readable')): @@ -86,6 +91,9 @@ # attribute as returned by whatever subclass. return self.__IOBase_closed + def _unsupportedoperation(self, space, message): + raise unsupported(space, message) + def _check_closed(self, space, message=None): if message is None: message = "I/O operation on closed file" @@ -111,9 +119,18 @@ space.w_ValueError, space.wrap("I/O operation on closed file")) + def seek_w(self, space, w_offset, w_whence=None): + self._unsupportedoperation(space, "seek") + def tell_w(self, space): return space.call_method(self, "seek", space.wrap(0), space.wrap(1)) + def truncate_w(self, space, w_size=None): + self._unsupportedoperation(space, "truncate") + + def fileno_w(self, space): + self._unsupportedoperation(space, "fileno") + def enter_w(self, space): self._check_closed(space) return space.wrap(self) @@ -248,11 +265,15 @@ next = interp2app(W_IOBase.next_w), close = interp2app(W_IOBase.close_w), flush = interp2app(W_IOBase.flush_w), + seek = interp2app(W_IOBase.seek_w), tell = interp2app(W_IOBase.tell_w), + truncate = interp2app(W_IOBase.truncate_w), + fileno = interp2app(W_IOBase.fileno_w), isatty = interp2app(W_IOBase.isatty_w), readable = interp2app(W_IOBase.readable_w), writable = interp2app(W_IOBase.writable_w), seekable = interp2app(W_IOBase.seekable_w), + _checkReadable = interp2app(check_readable_w), _checkWritable = interp2app(check_writable_w), _checkSeekable = interp2app(check_seekable_w), diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -196,11 +196,6 @@ def __init__(self, space): W_IOBase.__init__(self, space) - def _unsupportedoperation(self, space, message): - w_exc = space.getattr(space.getbuiltinmodule('_io'), - space.wrap('UnsupportedOperation')) - raise OperationError(w_exc, space.wrap(message)) - def read_w(self, space, w_size=None): self._unsupportedoperation(space, "read") diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -43,6 +43,13 @@ import _io e = _io.UnsupportedOperation("seek") + def test_default_implementations(self): + import _io + file = _io._IOBase() + raises(_io.UnsupportedOperation, file.seek, 0, 1) + raises(_io.UnsupportedOperation, file.fileno) + raises(_io.UnsupportedOperation, file.truncate) + def test_blockingerror(self): import _io try: diff --git a/pypy/module/_io/test/test_textio.py b/pypy/module/_io/test/test_textio.py --- a/pypy/module/_io/test/test_textio.py +++ b/pypy/module/_io/test/test_textio.py @@ -26,6 +26,14 @@ assert t.readable() assert t.seekable() + def test_default_implementations(self): + import _io + file = _io._TextIOBase() + raises(_io.UnsupportedOperation, file.read) + raises(_io.UnsupportedOperation, file.seek, 0) + raises(_io.UnsupportedOperation, file.readline) + raises(_io.UnsupportedOperation, file.detach) + def test_unreadable(self): import _io class UnReadable(_io.BytesIO): diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -46,11 +46,11 @@ self.name = name class FakeSpace(object): - w_ValueError = "ValueError" - w_TypeError = "TypeError" - w_IndexError = "IndexError" - w_OverflowError = "OverflowError" - w_NotImplementedError = "NotImplementedError" + w_ValueError = W_TypeObject("ValueError") + w_TypeError = W_TypeObject("TypeError") + w_IndexError = W_TypeObject("IndexError") + w_OverflowError = W_TypeObject("OverflowError") + w_NotImplementedError = W_TypeObject("NotImplementedError") w_None = None w_bool = W_TypeObject("bool") diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -254,6 +254,8 @@ descr__new__, _get_dtype = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): + _attrs_ = ['ofs', 'dtype', 'arr'] + _immutable_fields_ = ['ofs'] def __init__(self, arr, ofs, dtype): self.arr = arr # we have to keep array alive self.ofs = ofs diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -275,7 +275,7 @@ from numpypy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) - if self.ptr_size == 8: + if self.ptr_size == 8: assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0)) else: assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0)) @@ -786,7 +786,7 @@ def test_create_subarrays(self): from numpypy import dtype - d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + d = dtype([("x", "float", (2,)), ("y", "int64", (2,))]) assert d.itemsize == 32 assert d.name == "void256" keys = d.fields.keys() diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2715,7 +2715,7 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") @@ -2735,7 +2735,7 @@ def test_multidim_subarray(self): from numpypy import dtype, array - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1704,28 +1704,11 @@ T = lltype.Char def _coerce(self, space, arr, ofs, dtype, w_items, shape): - items_w = space.fixedview(w_items) - for i in range(len(items_w)): - subdtype = dtype.subdtype - itemtype = subdtype.itemtype - if space.len_w(shape) <= 1: - w_box = itemtype.coerce(space, dtype.subdtype, items_w[i]) - itemtype.store(arr, 0, ofs, w_box) - ofs += itemtype.get_element_size() - else: - size = 1 - for dimension in shape[1:]: - size *= dimension - size *= itemtype.get_element_size() - for w_item in items_w: - self._coerce(space, arr, ofs, dtype, w_items, shape[1:]) - ofs += size - return arr - - def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match + from interp_dtype import W_Dtype items_w = space.fixedview(w_items) subdtype = dtype.subdtype + assert isinstance(subdtype, W_Dtype) itemtype = subdtype.itemtype if len(shape) <= 1: for i in range(len(items_w)): diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -105,7 +105,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -142,7 +141,6 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) - guard_not_invalidated(descr=...) i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -339,7 +339,6 @@ loop, = log.loops_by_filename(self.filepath) # the int strategy is used here assert loop.match_by_id('append', """ - guard_not_invalidated(descr=...) i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) # Will be killed by the backend @@ -487,7 +486,6 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) - guard_not_invalidated(descr=...) i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -587,6 +585,7 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' + guard_not_invalidated(descr=...) i1 = force_token() ''') diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -239,6 +239,9 @@ pass pos = POSITION(1, 2) assert (pos.x, pos.y) == (1, 2) + # Try a second time, result may be different (cf. issue1498) + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) def test_invalid_field_types(self): 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 @@ -73,6 +73,11 @@ rename_pypy_c += '.exe' binaries = [(pypy_c, rename_pypy_c)] # + builddir = udir.ensure("build", dir=True) + pypydir = builddir.ensure(name, dir=True) + includedir = basedir.join('include') + pypydir.ensure('include', dir=True) + if sys.platform == 'win32': #Don't include a mscvrXX.dll, users should get their own. #Instructions are provided on the website. @@ -85,12 +90,22 @@ p = pypy_c.dirpath().join(extra) if not p.check(): p = py.path.local.sysfind(extra) - assert p, "%s not found" % (extra,) + if not p: + print "%s not found, expect trouble if this is a shared build" % (extra,) + continue print "Picking %s" % p binaries.append((p, p.basename)) - # - builddir = udir.ensure("build", dir=True) - pypydir = builddir.ensure(name, dir=True) + if pypy_c.dirpath().join("libpypy-c.lib").check(): + shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), + str(pypydir.join('include/python27.lib'))) + print "Picking %s as %s" % (pypy_c.dirpath().join("libpypy-c.lib"), + pypydir.join('include/python27.lib')) + else: + pass + # XXX users will complain that they cannot compile cpyext + # modules for windows, has the lib moved or are there no + # exported functions in the dll so no import library is created? + # Careful: to copy lib_pypy, copying just the svn-tracked files # would not be enough: there are also ctypes_config_cache/_*_cache.py. shutil.copytree(str(basedir.join('lib-python').join(STDLIB_VER)), @@ -102,15 +117,10 @@ '*.c', '*.o')) for file in ['LICENSE', 'README.rst']: shutil.copy(str(basedir.join(file)), str(pypydir)) - pypydir.ensure('include', dir=True) - if sys.platform == 'win32': - shutil.copyfile(str(pypy_c.dirpath().join("libpypy-c.lib")), - str(pypydir.join('include/python27.lib'))) - # we want to put there all *.h and *.inl from trunk/include - # and from pypy/_interfaces - includedir = basedir.join('include') headers = includedir.listdir('*.h') + includedir.listdir('*.inl') for n in headers: + # we want to put there all *.h and *.inl from trunk/include + # and from pypy/_interfaces shutil.copy(str(n), str(pypydir.join('include'))) # spdir = pypydir.ensure('site-packages', dir=True) diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -85,7 +85,7 @@ # exported_state is clear by optimizeopt when the short preamble is # constrcucted. if that did not happen the label should not show up # in a trace that will be used - assert descr.exported_state is None + assert descr.exported_state is None if not we_are_translated(): op._descr_wref = weakref.ref(op._descr) op.cleardescr() # clear reference to prevent the history.Stats @@ -819,7 +819,7 @@ # The history contains new operations to attach as the code for the # failure of 'resumekey.guard_op'. - # + # # Attempt to use optimize_bridge(). This may return None in case # it does not work -- i.e. none of the existing old_loop_tokens match. new_trace = create_empty_loop(metainterp) From noreply at buildbot.pypy.org Mon May 27 10:35:40 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 10:35:40 +0200 (CEST) Subject: [pypy-commit] stmgc default: Raah, can't seem to get this right: force_minor_collections() Message-ID: <20130527083540.EB84B1C13EB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r36:c658753ace12 Date: 2013-05-27 10:35 +0200 http://bitbucket.org/pypy/stmgc/changeset/c658753ace12/ Log: Raah, can't seem to get this right: force_minor_collections() diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -774,6 +774,8 @@ revision_t newrev = -(cur_time + 1); assert(newrev & 1); ACCESS_ONCE(stm_local_revision) = newrev; + fprintf(stderr, "%p: stm_local_revision = %ld\n", d, newrev); + assert(d->local_revision_ref = &stm_local_revision); UpdateChainHeads(d, cur_time, localrev); diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -373,6 +373,9 @@ revision_t v = obj->h_revision; if (!(v & 1)) { // "is a pointer" /* i.e. has a more recent revision. Oups. */ + fprintf(stderr, + "ABRT_COLLECT_MAJOR: %p was read but modified already\n", + obj); AbortTransactionAfterCollect(d, ABRT_COLLECT_MAJOR); return; } @@ -537,23 +540,12 @@ /***** Major collections: forcing minor collections *****/ -static void check_different_local_revs(void) -{ -#ifdef _GC_DEBUG - struct tx_descriptor *d, *d2; - for (d = tx_head; d; d = d->tx_next) { - for (d2 = d->tx_next; d2; d2 = d2->tx_next) { - assert(*d->local_revision_ref != *d2->local_revision_ref); - } - } -#endif -} - void force_minor_collections(void) { + struct tx_descriptor *d; struct tx_descriptor *saved = thread_descriptor; - revision_t saved_local_rev = *saved->local_revision_ref; - struct tx_descriptor *d; + revision_t saved_local_rev = stm_local_revision; + assert(saved_local_rev == *saved->local_revision_ref); for (d = tx_head; d; d = d->tx_next) { /* Force a minor collection to run in the thread 'd'. @@ -569,11 +561,10 @@ assert(stmgc_nursery_hiding(d, 0)); stmgc_minor_collect_no_abort(); assert(stmgc_nursery_hiding(d, 1)); + thread_descriptor = saved; + stm_local_revision = saved_local_rev; } } - thread_descriptor = saved; - stm_local_revision = saved_local_rev; - check_different_local_revs(); } From noreply at buildbot.pypy.org Mon May 27 11:41:38 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 11:41:38 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix Message-ID: <20130527094138.4EFF21C1293@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r37:a93569a5c25a Date: 2013-05-27 11:41 +0200 http://bitbucket.org/pypy/stmgc/changeset/a93569a5c25a/ Log: Fix diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -354,6 +354,11 @@ } } +static struct stm_object_s dead_object_stub = { + GCFLAG_PREBUILT | GCFLAG_STUB, + (revision_t)&dead_object_stub +}; + static void cleanup_for_thread(struct tx_descriptor *d) { long i; @@ -376,8 +381,14 @@ fprintf(stderr, "ABRT_COLLECT_MAJOR: %p was read but modified already\n", obj); - AbortTransactionAfterCollect(d, ABRT_COLLECT_MAJOR); - return; + if (d->max_aborts != 0) { /* normal path */ + AbortTransactionAfterCollect(d, ABRT_COLLECT_MAJOR); + return; + } + else { /* for tests */ + items[i] = &dead_object_stub; + continue; + } } /* on the other hand, if we see a non-visited object in the read diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -665,17 +665,19 @@ which should be identical. */ gcptr P = (gcptr)obj->h_revision; assert(dclassify(P) == K_PUBLIC); + items[i] = P; - if (P->h_revision & 1) { /* "is not a pointer" */ - items[i] = P; - /*mark*/ - } - else { + if (!(P->h_revision & 1)) { /* "is a pointer" */ /* P has already been changed. Mark as abort. */ - AbortTransactionAfterCollect(d, ABRT_COLLECT_MINOR); - /*mark*/ - gcptrlist_clear(&d->list_of_read_objects); - break; + fprintf(stderr, + "ABRT_COLLECT_MINOR: %p was read but modified already\n", + P); + if (d->max_aborts != 0) { /* normal path */ + AbortTransactionAfterCollect(d, ABRT_COLLECT_MINOR); + /*mark*/ + gcptrlist_clear(&d->list_of_read_objects); + break; + } } } else { From noreply at buildbot.pypy.org Mon May 27 12:30:56 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 27 May 2013 12:30:56 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: use a different guard name, so the optimizer does not get confused. Saves Message-ID: <20130527103056.79EBF1C3357@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64576:7c4ed9c84edd Date: 2013-05-27 12:30 +0200 http://bitbucket.org/pypy/pypy/changeset/7c4ed9c84edd/ Log: use a different guard name, so the optimizer does not get confused. Saves some hacks, but is definitely not pretty diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -787,6 +787,7 @@ saved_data = self.forced_deadframe._saved_data self.fail_guard(descr, saved_data) self.force_guard_op = self.current_op + execute_guard_not_forced_2 = execute_guard_not_forced def execute_guard_not_invalidated(self, descr): if self.lltrace.invalid: @@ -922,6 +923,16 @@ # # Emulate the fast path # + faildescr = self.cpu.get_latest_descr(pframe) + if faildescr == self.cpu.done_with_this_frame_descr_int: + return self.cpu.get_int_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_ref: + return self.cpu.get_ref_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_float: + return self.cpu.get_float_value(pframe, 0) + elif faildescr == self.cpu.done_with_this_frame_descr_void: + return None + assembler_helper_ptr = jd.assembler_helper_adr.ptr # fish try: result = assembler_helper_ptr(pframe, vable) diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1336,7 +1336,7 @@ #if jump_op is not None and jump_op.getdescr() is descr: # self._compute_hint_frame_locations_from_descr(descr) - def consider_guard_not_forced(self, op): + def consider_guard_not_forced_2(self, op): self.rm.before_call([], save_all_regs=True) fail_locs = [self.loc(v) for v in op.getfailargs()] self.assembler.store_force_descr(op, fail_locs, diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -5102,6 +5102,15 @@ } self.optimize_loop(ops, expected, call_pure_results) + def test_guard_not_forced_2_virtual(self): + ops = """ + [i0] + p0 = new_array(3, descr=arraydescr) + guard_not_forced_2() [p0] + finish(p0) + """ + self.optimize_loop(ops, ops) + class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin): pass diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -481,6 +481,8 @@ class OptVirtualize(optimizer.Optimization): "Virtualize objects until they escape." + _last_guard_not_forced = None + def new(self): return OptVirtualize() @@ -524,6 +526,18 @@ return self.emit_operation(op) + def optimize_GUARD_NOT_FORCED_2(self, op): + self._last_guard_not_forced = op + + def optimize_FINISH(self, op): + if self._last_guard_not_forced is not None: + guard_op = self._last_guard_not_forced + self.emit_operation(op) + guard_op = self.optimizer.store_final_boxes_in_guard(guard_op) + self.optimizer._newoperations.insert(-1, guard_op) + else: + self.emit_operation(op) + def optimize_FORCE_VIRTUALIZABLE(self, op): val = self.getvalue(op.getarg(0)) if val.is_virtual(): diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1741,7 +1741,7 @@ else: moreargs = list(extraargs) metainterp_sd = self.staticdata - if opnum == rop.GUARD_NOT_FORCED: + if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2: resumedescr = compile.ResumeGuardForcedDescr(metainterp_sd, self.jitdriver_sd) elif opnum == rop.GUARD_NOT_INVALIDATED: @@ -2281,7 +2281,7 @@ self.history.record(rop.FORCE_TOKEN, [], force_token_box) self.history.record(rop.SETFIELD_GC, [vbox, force_token_box], None, descr=vinfo.vable_token_descr) - self.generate_guard(rop.GUARD_NOT_FORCED, None) + self.generate_guard(rop.GUARD_NOT_FORCED_2, None) def compile_exit_frame_with_exception(self, valuebox): self.store_token_in_vable() diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -395,6 +395,7 @@ 'GUARD_NO_OVERFLOW/0d', 'GUARD_OVERFLOW/0d', 'GUARD_NOT_FORCED/0d', # may be called with an exception currently set + 'GUARD_NOT_FORCED_2/0d', # same as GUARD_NOT_FORCED, but for finish() 'GUARD_NOT_INVALIDATED/0d', '_GUARD_LAST', # ----- end of guard operations ----- From noreply at buildbot.pypy.org Mon May 27 12:46:05 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 27 May 2013 12:46:05 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: rpython Message-ID: <20130527104605.7E8151C3357@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64577:77738f844bc4 Date: 2013-05-27 12:45 +0200 http://bitbucket.org/pypy/pypy/changeset/77738f844bc4/ Log: rpython diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -534,7 +534,9 @@ guard_op = self._last_guard_not_forced self.emit_operation(op) guard_op = self.optimizer.store_final_boxes_in_guard(guard_op) - self.optimizer._newoperations.insert(-1, guard_op) + i = len(self.optimizer._newoperations) - 1 + assert i >= 0 + self.optimizer._newoperations.insert(i, guard_op) else: self.emit_operation(op) From noreply at buildbot.pypy.org Mon May 27 14:24:19 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 27 May 2013 14:24:19 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: (kasal) typo Message-ID: <20130527122419.950741C1293@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r441:6d05f7139d01 Date: 2013-05-27 14:08 +0200 http://bitbucket.org/pypy/pypy.org/changeset/6d05f7139d01/ Log: (kasal) typo diff --git a/numpydonate.html b/numpydonate.html --- a/numpydonate.html +++ b/numpydonate.html @@ -80,8 +80,8 @@ become the de-facto standard for doing any kinds of computations that involve n-dimensional arrays. Please consult the NumPy website for more details.

    -
    -

    Why does NumPy on PyPy makes sense?

    +
    +

    Why does NumPy on PyPy make sense?

    NumPy on PyPy makes sense for a couple of reasons: Firstly, it is by far the most requested feature from PyPy. Secondly, PyPy performs well on numerical loads already. Therefore bringing NumPy into the diff --git a/source/numpydonate.txt b/source/numpydonate.txt --- a/source/numpydonate.txt +++ b/source/numpydonate.txt @@ -45,7 +45,7 @@ become the de-facto standard for doing any kinds of computations that involve n-dimensional arrays. Please consult the NumPy website for more details. -Why does NumPy on PyPy makes sense? +Why does NumPy on PyPy make sense? ----------------------------------- NumPy on PyPy makes sense for a couple of reasons: Firstly, it is by From noreply at buildbot.pypy.org Mon May 27 14:24:21 2013 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 27 May 2013 14:24:21 +0200 (CEST) Subject: [pypy-commit] pypy.org extradoc: merge Message-ID: <20130527122421.1D3621C1293@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: extradoc Changeset: r442:a21fa8ed4bef Date: 2013-05-27 14:10 +0200 http://bitbucket.org/pypy/pypy.org/changeset/a21fa8ed4bef/ Log: merge diff --git a/archive.html b/archive.html --- a/archive.html +++ b/archive.html @@ -15,7 +15,6 @@ - diff --git a/compat.html b/compat.html --- a/compat.html +++ b/compat.html @@ -15,7 +15,6 @@ - diff --git a/contact.html b/contact.html --- a/contact.html +++ b/contact.html @@ -15,7 +15,6 @@ - diff --git a/css/site.css b/css/site.css --- a/css/site.css +++ b/css/site.css @@ -353,6 +353,7 @@ #menu-follow { float: right; + margin-top: 17px; } #menu-follow div { @@ -379,6 +380,11 @@ font-size: 1em; padding-bottom: 10px; text-align: center; + line-height:1.75em; +} + +#menu-sub a{ + white-space: nowrap; } .menu-sub-sep { diff --git a/download.html b/download.html --- a/download.html +++ b/download.html @@ -15,7 +15,6 @@ - @@ -51,9 +50,10 @@ performance improvements. Note that the OS X nightly builds (but not the release) are slightly miscompiled due to buildslave being old. Contributions are welcomed.

    -

    Here are the binaries of the current release — PyPy 2.0 — (what's -new in PyPy 2.0?) for x86 Linux, Mac OS/X, Windows. ARM support in -2.0 is alpha-level.

    +

    Here are the binaries of the current release — PyPy 2.0.2 — +(what's new in PyPy 2.0?, fixes of PyPy 2.0.1, fix of PyPy +2.0.2) for x86 Linux, Mac OS/X, Windows. The support for ARM in +2.0(.2) is alpha-level.

    • Download
      • Default (with a JIT Compiler)
      • @@ -71,29 +71,42 @@ x86 CPUs that have the SSE2 instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain stackless extensions, like greenlets. -(This is the official release 2.0; +(This is the official release 2.0.2; for the most up-to-date version see below.)

    -

    2.0

    -

    Note that linux binaries are dynamically linked and might not be usable due -to a sad story of linux binary compatibility. We recommend either building from +

    2.0.2

    +

    Note that Linux binaries are dynamically linked, as is usual, and thus might +not be usable due to the sad story of linux binary compatibility. This means +that Linux binaries are only usable on the distributions written next to +them unless you're ready to hack your system by adding symlinks to the +libraries it tries to open. In general, we recommend either building from source or downloading your PyPy from your release vendor. Ubuntu (PPA), -Debian, Homebrew, +Debian, Homebrew, MacPorts, Fedora, Gentoo and Arch are known to package PyPy, with various degrees of being up-to-date. If you feel -like trying a statically linked binary (which we do not recommend using -in production due to potential future security issues), you can find -32bit Linux and 64bit Linux.

    +like trying a more statically linked binary (which we do not recommend using +in production due to potential future security issues), you can find the +older 32bit Linux and 64bit Linux at an earlier time of release 2.0.

    +

    If your CPU is really old, it may not have SSE2. In this case, you need +to translate yourself with the option --jit-backend=x86-without-sse2.

    +

    [1]: stating it again: the Linux binaries are provided for the +distributions listed here. If your distribution is not exactly this +one, it won't work, likely: pypy: error while loading shared +libraries: …. You need to hack a lot – or you need to translate +your own version from source – or you need to wait until your +distribution adds a package, see above – or you can try the statically +linked versions listed above.

    2.0 for ARM alpha

    @@ -103,8 +116,6 @@
  • Linux binary (32bit, armhf)
  • Linux deb for raspbian (raspberry pi)
  • -

    If your CPU is really old, it may not have SSE2. In this case, you need -to translate yourself with the option --jit-backend=x86-without-sse2.

    Other versions

    @@ -118,15 +129,13 @@ sandboxing and the JIT compiler, although as the JIT is relatively complicated, this reduces a bit the level of confidence we can put in the result.) Note that the sandboxed binary needs a full pypy checkout -to work. Consult the sandbox docs for details
    -

    These versions are not officially part of the releases, which focuses -on the JIT. You can find prebuilt binaries for them on our -nightly build, or translate them yourself.

    Installing

    @@ -134,7 +143,7 @@ uncompressed, they run in-place. For now you can uncompress them either somewhere in your home directory or, say, in /opt, and if you want, put a symlink from somewhere like -/usr/local/bin/pypy to /path/to/pypy-2.0/bin/pypy. Do +/usr/local/bin/pypy to /path/to/pypy-2.0.2/bin/pypy. Do not move or copy the executable pypy outside the tree – put a symlink to it, otherwise it will not find its libraries.

    @@ -144,8 +153,8 @@
  • Get the source code. The following packages contain the source at the same revision as the above binaries:

    Or you can checkout the current trunk using Mercurial (the trunk usually works and is of course more up-to-date):

    @@ -212,28 +221,28 @@

    Checksums

    Here are the checksums for each of the downloads (md5 and sha1):

    -756d738d8f35924357150fe1b6d33f86  pypy-2.0-linux64.tar.bz2
    -267c46ed8c591da19b6091aa90fa9acf  pypy-2.0-linux.tar.bz2
    -39837722da4a03ca03eda187aafa13bb  pypy-2.0-osx64.tar.bz2
    -f0d051c2b612b64dff496a6c0f3654fb  pypy-2.0-win32.zip
    +51ac0aa37a8255acbc71eca23ea29609  pypy-2.0.2-linux.tar.bz2
    +9d9f512ab2f114bfb4f165c71181a511  pypy-2.0.2-linux64.tar.bz2
    +a7da45a3161c198de6f662e3c40629ff  pypy-2.0.2-osx64.tar.bz2
    +3e51dce7ecfc8fb069d65d95e8de6fb2  pypy-2.0.2-win32.zip
     b9c36b99296c85a590c3e480b05d5a13  pypy-2.0-alpha-arm-armel.tar.bz2
     2565ce68b4032eb306d998e722495694  pypy-2.0-alpha-arm-armhf.tar.bz2
     b39d98de75f4948bfd2d606a8263ac1f  pypy-upstream_2.0~alpha+arm_armhf.deb
     2c9f0054f3b93a6473f10be35277825a  pypy-1.8-sandbox-linux64.tar.bz2
     009c970b5fa75754ae4c32a5d108a8d4  pypy-1.8-sandbox-linux.tar.bz2
    -4dc82e2240dd2b5be313119672988538  pypy-2.0-src.tar.bz2
    -f965b50bc34c97891af77e6b743038f2  pypy-2.0-src.zip
    -88aacc21c6c552b3ff3a157a7575a9dca7e4a7c3  pypy-2.0-linux64.tar.bz2
    -b2e64ca5e38a59c3402185cca08ca5a4d507ff7e  pypy-2.0-linux.tar.bz2
    -65ecb2ba570f05691978c64469cfe3e76bfd8e01  pypy-2.0-osx64.tar.bz2
    -cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc  pypy-2.0-win32.zip
    +c26662e348159b460057548ddaf35333  pypy-2.0.2-src.tar.bz2
    +4da8c6dfbe7d2044d892c9bc20a649b0  pypy-2.0.2-src.zip
    +c8ec9872fe823f4f7574620a5303c5b0f4576393  pypy-2.0.2-linux.tar.bz2
    +3d045ab7871bc478604cf1f16a3c4ec46c950e70  pypy-2.0.2-linux64.tar.bz2
    +a53de7bc88b9caa635d9d679c6e63813881ea7e9  pypy-2.0.2-osx64.tar.bz2
    +4ae8a35dd8043312199aacdbe3abb1a666fc9312  pypy-2.0.2-win32.zip
     dc09a293b85ab4f0032f6943815aaf5bbbceb645  pypy-2.0-alpha-arm-armel.tar.bz2
     0971c4b668bfd2fcd52aa35087aa995e03bd5842  pypy-2.0-alpha-arm-armhf.tar.bz2
     91910eb654ffbe0509bec2a7aeb460984acf8d82  pypy-upstream_2.0~alpha+arm_armhf.deb
     895aaf7bba5787dd30adda5cc0e0e7fc297c0ca7  pypy-1.8-sandbox-linux64.tar.bz2
     be94460bed8b2682880495435c309b6611ae2c31  pypy-1.8-sandbox-linux.tar.bz2
    -d694824eeaa6169bce8d112149c9a5c7897534ed  pypy-2.0-src.tar.bz2
    -dc44cc9141a729ccc39b98432062bbe29c938432  pypy-2.0-src.zip
    +49e0af6e57bd2738cd3eb09c3246c69a3dc01319  pypy-2.0.2-src.tar.bz2
    +bfb23e7ea17cf9f2e9bf7f2211c6df3aeeafed32  pypy-2.0.2-src.zip
     
  • diff --git a/features.html b/features.html --- a/features.html +++ b/features.html @@ -15,7 +15,6 @@ - @@ -46,7 +45,7 @@

    Features

    -

    PyPy 2.0 implements Python 2.7.3 and runs on Intel +

    PyPy 2.0.2 implements Python 2.7.3 and runs on Intel x86 (IA-32) , x86_64 and ARM platforms (alpha), with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/howtohelp.html b/howtohelp.html --- a/howtohelp.html +++ b/howtohelp.html @@ -15,7 +15,6 @@ - diff --git a/index.html b/index.html --- a/index.html +++ b/index.html @@ -15,7 +15,6 @@ - @@ -64,7 +63,7 @@

  • As well as other features.
  • -

    Download and try out the PyPy release 2.0!

    +

    Download and try out the PyPy release 2.0.2!

    Want to know more? A good place to start is our detailed speed and compatibility reports!

    diff --git a/js/detect.js b/js/detect.js deleted file mode 100644 --- a/js/detect.js +++ /dev/null @@ -1,25 +0,0 @@ - -$(document).ready(function() { - var download_url, download_text; - var base = 'https://bitbucket.org/pypy/pypy/downloads/'; - if (navigator.platform.indexOf('Linux') != -1) { - if (navigator.platform.indexOf('64') != -1) { - download_url = base + 'pypy-1.7-linux64.tar.bz2'; - download_text = 'Download linux x86-64 bin'; - } else { - download_url = base + 'pypy-1.7-linux.tar.bz2'; - download_text = 'Download linux x86 bin (32 bit)'; - } - } else if (navigator.platform.indexOf('Win') != -1) { - download_url = base + 'pypy-1.7-win32.zip'; - download_text = 'Download Windows x86 bin (BETA)'; - } else if (navigator.platform.indexOf('Mac') != 1) { - download_url = base + 'pypy-1.7-osx64.tar.bz2'; - download_text = 'Download Mac OS X 10.6 bin (64 bit)'; - } else { - download_url = "download.html"; - download_text = "Download page"; - } - $("#main_download").attr('href', download_url); - $("#main_download").text(download_text); -}); diff --git a/js/script2.js b/js/script2.js --- a/js/script2.js +++ b/js/script2.js @@ -1,28 +1,21 @@ +function set_sidebar_html(html) { + $("#sidebar").html(html); +} function py3k_donate() { - $.get("don1.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don1.html", set_sidebar_html); } function stm_donate() { - $.get("don4.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don4.html", set_sidebar_html); } function general_donate() { - $.get("don2.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don2.html", set_sidebar_html); } function numpy_donate() { - $.get("don3.html#", function (html) { - $("#sidebar").html(html); - }); + $.get("don3.html", set_sidebar_html); } -$(document).ready(function() { - stm_donate(); -}); \ No newline at end of file +$(document).ready(stm_donate); diff --git a/numpydonate.html b/numpydonate.html --- a/numpydonate.html +++ b/numpydonate.html @@ -15,7 +15,6 @@ - @@ -66,7 +65,7 @@ at the latest, we will try our best to make PyPy support NumPy anyway. We however reserve the right to shift any unused funds to other PyPy activities when that date is reached. Of course, since the Conservancy is a -501(c)(3) charitable organization incorporated in NY, USA, all funds will, +501©(3) charitable organization incorporated in NY, USA, all funds will, regardless of their use, be spent in a way that benefits the general public, the advancement of Open Source and Free Software, and in particular the PyPy community and the PyPy codebase.

    diff --git a/people.html b/people.html --- a/people.html +++ b/people.html @@ -15,7 +15,6 @@ - diff --git a/performance.html b/performance.html --- a/performance.html +++ b/performance.html @@ -15,7 +15,6 @@ - diff --git a/py3donate.html b/py3donate.html --- a/py3donate.html +++ b/py3donate.html @@ -15,7 +15,6 @@ - @@ -75,7 +74,7 @@ at the latest, we will try our best to make PyPy support Python 3 anyway. We however reserve the right to shift any unused funds to other PyPy activities when that date is reached. Of course, since the Conservancy is a -501(c)(3) charitable organization incorporated in NY, USA, all funds will, +501©(3) charitable organization incorporated in NY, USA, all funds will, regardless of their use, be spent in a way that benefits the general public, the advancement of Open Source and Free Software, and in particular the PyPy community and the PyPy codebase.

    diff --git a/source/_layouts/site.genshi b/source/_layouts/site.genshi --- a/source/_layouts/site.genshi +++ b/source/_layouts/site.genshi @@ -46,7 +46,6 @@ diff --git a/source/download.txt b/source/download.txt --- a/source/download.txt +++ b/source/download.txt @@ -14,11 +14,14 @@ (but not the release) are slightly miscompiled due to buildslave being old. Contributions are welcomed**. -Here are the binaries of the current release — **PyPy 2.0** — (`what's -new in PyPy 2.0?`_) for x86 Linux, Mac OS/X, Windows. ARM support in -2.0 is alpha-level. +Here are the binaries of the current release — **PyPy 2.0.2** — +(`what's new in PyPy 2.0?`_, `fixes of PyPy 2.0.1`_, `fix of PyPy +2.0.2`_) for x86 Linux, Mac OS/X, Windows. The support for ARM in +2.0(.2) is alpha-level. .. _what's new in PyPy 2.0?: http://doc.pypy.org/en/latest/release-2.0.0.html +.. _fixes of PyPy 2.0.1: http://doc.pypy.org/en/latest/release-2.0.1.html +.. _fix of PyPy 2.0.2: http://doc.pypy.org/en/latest/release-2.0.2.html .. class:: download_menu @@ -42,21 +45,24 @@ x86 CPUs that have the SSE2_ instruction set (most of them do, nowadays), or on x86-64 CPUs. They also contain `stackless`_ extensions, like `greenlets`_. -(This is the official release 2.0; +(This is the official release 2.0.2; for the most up-to-date version see below.) -2.0 ---- +2.0.2 +----- -Note that linux binaries are dynamically linked and might not be usable due -to a sad story of linux binary compatibility. We recommend either building from +Note that Linux binaries are dynamically linked, as is usual, and thus might +not be usable due to the sad story of linux binary compatibility. This means +that **Linux binaries are only usable on the distributions written next to +them** unless you're ready to hack your system by adding symlinks to the +libraries it tries to open. In general, we recommend either building from source or downloading your PyPy from your release vendor. `Ubuntu`_ (`PPA`_), -`Debian`_, `Homebrew`_, +`Debian`_, `Homebrew`_, MacPorts, `Fedora`_, `Gentoo`_ and `Arch`_ are known to package PyPy, with various degrees of being up-to-date. If you feel -like trying a statically linked binary (which we do not recommend using -in production due to potential future security issues), you can find -`32bit Linux`_ and `64bit Linux`_. +like trying a more statically linked binary (which we do not recommend using +in production due to potential future security issues), you can find the +older `32bit Linux`_ and `64bit Linux`_ at an earlier time of release 2.0. .. _`Ubuntu`: http://packages.ubuntu.com/raring/pypy .. _`PPA`: https://launchpad.net/~pypy/+archive/ppa @@ -68,21 +74,34 @@ .. _`32bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux.tar.bz2 .. _`64bit Linux`: http://buildbot.pypy.org/nightly/release-2.0.x/pypy-c-jit-63916-eb5983d848f1-linux64.tar.bz2 -* `Linux binary (32bit)`__ -* `Linux binary (64bit) (libc 2.15)`__ +* `Linux binary (32bit, tar.bz2 built on Ubuntu 10.04.4 LTS)`__ (see ``[1]`` below) +* `Linux binary (64bit, tar.bz2 built on Ubuntu 12.04.2 LTS)`__ (see ``[1]`` below) * `Mac OS/X binary (64bit)`__ * `Windows binary (32bit)`__ (you might need the `VS 2008 runtime library installer vcredist_x86.exe`_.) -* `Source (unix line endings)`__ -* `Source (also unix line endings, sorry)`__ +* `Source (tar.bz2)`__ +* `Source (zip)`__ +* `All our downloads,`__ including previous versions -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-linux64.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-osx64.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-win32.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-linux64.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-osx64.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-win32.zip .. _`VS 2008 runtime library installer vcredist_x86.exe`: http://www.microsoft.com/en-us/download/details.aspx?id=5582 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.tar.bz2 -.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.tar.bz2 +.. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.zip +.. __: https://bitbucket.org/pypy/pypy/downloads/ + +If your CPU is really old, it may not have SSE2. In this case, you need +to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. + +``[1]:`` stating it again: the Linux binaries are provided for the +distributions listed here. **If your distribution is not exactly this +one, it won't work,** likely: ``pypy: error while loading shared +libraries: ...``. You need to hack a lot --- or you need to translate_ +your own version from source --- or you need to wait until your +distribution adds a package, see above --- or you can try the statically +linked versions listed above. 2.0 for ARM alpha ----------------- @@ -97,9 +116,6 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-alpha-arm-armhf.tar.bz2 .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-upstream_2.0~alpha+arm_armhf.deb -If your CPU is really old, it may not have SSE2. In this case, you need -to translate_ yourself with the option ``--jit-backend=x86-without-sse2``. - .. _`Other versions (without a JIT)`: Other versions @@ -116,7 +132,8 @@ sandboxing and the JIT compiler, although as the JIT is relatively complicated, this reduces a bit the level of confidence we can put in the result.) **Note that the sandboxed binary needs a full pypy checkout - to work**. Consult the `sandbox docs`_ for details + to work**. Consult the `sandbox docs`_ for details. (These are old, + PyPy 1.8.) * `Linux binary (64bit)`__ @@ -126,10 +143,6 @@ .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-1.8-sandbox-linux.tar.bz2 .. _`sandbox docs`: http://doc.pypy.org/en/latest/sandbox.html -These versions are not officially part of the releases, which focuses -on the JIT. You can find prebuilt binaries for them on our -`nightly build`_, or translate_ them yourself. - .. _`nightly build`: http://buildbot.pypy.org/nightly/trunk/ Installing @@ -139,7 +152,7 @@ uncompressed, they run in-place. For now you can uncompress them either somewhere in your home directory or, say, in ``/opt``, and if you want, put a symlink from somewhere like -``/usr/local/bin/pypy`` to ``/path/to/pypy-2.0/bin/pypy``. Do +``/usr/local/bin/pypy`` to ``/path/to/pypy-2.0.2/bin/pypy``. Do not move or copy the executable ``pypy`` outside the tree --- put a symlink to it, otherwise it will not find its libraries. @@ -152,11 +165,11 @@ 1. Get the source code. The following packages contain the source at the same revision as the above binaries: - * `pypy-2.0-src.tar.bz2`__ (sources, Unix line endings) - * `pypy-2.0-src.zip`__ (sources, Unix line endings too, sorry) + * `pypy-2.0.2-src.tar.bz2`__ (sources, Unix line endings) + * `pypy-2.0.2-src.zip`__ (sources, Unix line endings too, sorry) - .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.tar.bz2 - .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0-src.zip + .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.tar.bz2 + .. __: https://bitbucket.org/pypy/pypy/downloads/pypy-2.0.2-src.zip Or you can checkout the current trunk using Mercurial_ (the trunk usually works and is of course more up-to-date):: @@ -231,26 +244,26 @@ Here are the checksums for each of the downloads (md5 and sha1):: - 756d738d8f35924357150fe1b6d33f86 pypy-2.0-linux64.tar.bz2 - 267c46ed8c591da19b6091aa90fa9acf pypy-2.0-linux.tar.bz2 - 39837722da4a03ca03eda187aafa13bb pypy-2.0-osx64.tar.bz2 - f0d051c2b612b64dff496a6c0f3654fb pypy-2.0-win32.zip + 51ac0aa37a8255acbc71eca23ea29609 pypy-2.0.2-linux.tar.bz2 + 9d9f512ab2f114bfb4f165c71181a511 pypy-2.0.2-linux64.tar.bz2 + a7da45a3161c198de6f662e3c40629ff pypy-2.0.2-osx64.tar.bz2 + 3e51dce7ecfc8fb069d65d95e8de6fb2 pypy-2.0.2-win32.zip b9c36b99296c85a590c3e480b05d5a13 pypy-2.0-alpha-arm-armel.tar.bz2 2565ce68b4032eb306d998e722495694 pypy-2.0-alpha-arm-armhf.tar.bz2 b39d98de75f4948bfd2d606a8263ac1f pypy-upstream_2.0~alpha+arm_armhf.deb 2c9f0054f3b93a6473f10be35277825a pypy-1.8-sandbox-linux64.tar.bz2 009c970b5fa75754ae4c32a5d108a8d4 pypy-1.8-sandbox-linux.tar.bz2 - 4dc82e2240dd2b5be313119672988538 pypy-2.0-src.tar.bz2 - f965b50bc34c97891af77e6b743038f2 pypy-2.0-src.zip + c26662e348159b460057548ddaf35333 pypy-2.0.2-src.tar.bz2 + 4da8c6dfbe7d2044d892c9bc20a649b0 pypy-2.0.2-src.zip - 88aacc21c6c552b3ff3a157a7575a9dca7e4a7c3 pypy-2.0-linux64.tar.bz2 - b2e64ca5e38a59c3402185cca08ca5a4d507ff7e pypy-2.0-linux.tar.bz2 - 65ecb2ba570f05691978c64469cfe3e76bfd8e01 pypy-2.0-osx64.tar.bz2 - cc3b37b5d59b88cf340c72aaae13dd2bb0337bcc pypy-2.0-win32.zip + c8ec9872fe823f4f7574620a5303c5b0f4576393 pypy-2.0.2-linux.tar.bz2 + 3d045ab7871bc478604cf1f16a3c4ec46c950e70 pypy-2.0.2-linux64.tar.bz2 + a53de7bc88b9caa635d9d679c6e63813881ea7e9 pypy-2.0.2-osx64.tar.bz2 + 4ae8a35dd8043312199aacdbe3abb1a666fc9312 pypy-2.0.2-win32.zip dc09a293b85ab4f0032f6943815aaf5bbbceb645 pypy-2.0-alpha-arm-armel.tar.bz2 0971c4b668bfd2fcd52aa35087aa995e03bd5842 pypy-2.0-alpha-arm-armhf.tar.bz2 91910eb654ffbe0509bec2a7aeb460984acf8d82 pypy-upstream_2.0~alpha+arm_armhf.deb 895aaf7bba5787dd30adda5cc0e0e7fc297c0ca7 pypy-1.8-sandbox-linux64.tar.bz2 be94460bed8b2682880495435c309b6611ae2c31 pypy-1.8-sandbox-linux.tar.bz2 - d694824eeaa6169bce8d112149c9a5c7897534ed pypy-2.0-src.tar.bz2 - dc44cc9141a729ccc39b98432062bbe29c938432 pypy-2.0-src.zip + 49e0af6e57bd2738cd3eb09c3246c69a3dc01319 pypy-2.0.2-src.tar.bz2 + bfb23e7ea17cf9f2e9bf7f2211c6df3aeeafed32 pypy-2.0.2-src.zip diff --git a/source/features.txt b/source/features.txt --- a/source/features.txt +++ b/source/features.txt @@ -6,7 +6,7 @@ PyPy features =========================================================== -**PyPy 2.0** implements **Python 2.7.3** and runs on Intel +**PyPy 2.0.2** implements **Python 2.7.3** and runs on Intel `x86 (IA-32)`_ , `x86_64`_ and `ARM`_ platforms (alpha), with PPC being underway. It supports all of the core language, passing the Python test suite (with minor modifications that were already accepted in the main python diff --git a/source/index.txt b/source/index.txt --- a/source/index.txt +++ b/source/index.txt @@ -26,7 +26,7 @@ .. class:: download -`Download and try out the PyPy release 2.0!`__ +`Download and try out the PyPy release 2.0.2!`__ .. __: download.html diff --git a/sponsor.html b/sponsor.html --- a/sponsor.html +++ b/sponsor.html @@ -15,7 +15,6 @@ - diff --git a/success.html b/success.html --- a/success.html +++ b/success.html @@ -15,7 +15,6 @@ - diff --git a/tmdonate.html b/tmdonate.html --- a/tmdonate.html +++ b/tmdonate.html @@ -15,7 +15,6 @@ - From noreply at buildbot.pypy.org Mon May 27 14:52:29 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 27 May 2013 14:52:29 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: add raw stack location tests Message-ID: <20130527125229.1122C1C0189@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64578:2174f2660a2d Date: 2013-05-27 07:42 -0500 http://bitbucket.org/pypy/pypy/changeset/2174f2660a2d/ Log: add raw stack location tests diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -1038,7 +1038,7 @@ self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) if not is_imm and save: self.mc.POP([temp.value], cond=cond) - elif loc.is_raw_sp(): + elif loc.is_raw_sp() and loc.type != FLOAT: temp, save = self.get_tmp_reg([prev_loc]) assert not save self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) @@ -1064,6 +1064,8 @@ helper, save = self.get_tmp_reg() save_helper = not is_imm and save elif loc.is_raw_sp(): + assert (loc.type == prev_loc.type == FLOAT + or (loc.type != FLOAT and prev_loc.type != FLOAT)) tmp = loc if loc.is_float(): loc = r.vfp_ip @@ -1093,10 +1095,10 @@ self.load_reg(self.mc, loc, helper, 0, cond=cond) if save_helper: self.mc.POP([helper.value], cond=cond) - elif loc.is_stack(): + elif loc.is_stack() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - elif loc.is_raw_sp(): + elif loc.is_raw_sp() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) else: @@ -1113,6 +1115,8 @@ is_imm = check_imm_arg(offset) self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) elif loc.is_raw_sp(): + assert loc.type == FLOAT, 'trying to store to an \ + incompatible location from a float register' self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -1,9 +1,10 @@ from rpython.rlib.objectmodel import instantiate from rpython.jit.backend.arm.assembler import AssemblerARM -from rpython.jit.backend.arm.locations import imm, ConstFloatLoc,\ - RegisterLocation, StackLocation, \ - VFPRegisterLocation, get_fp_offset -from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip +from rpython.jit.backend.arm.locations import imm, ConstFloatLoc +from rpython.jit.backend.arm.locations import RegisterLocation, StackLocation +from rpython.jit.backend.arm.locations import VFPRegisterLocation, get_fp_offset +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip, sp from rpython.jit.backend.arm.conditions import AL from rpython.jit.backend.arm.arch import WORD from rpython.jit.metainterp.history import FLOAT @@ -54,6 +55,12 @@ addr = int(value) # whatever return ConstFloatLoc(addr) +def raw_stack(i): + return RawSPStackLocation(i) + +def raw_stack_float(i): + return RawSPStackLocation(i, type=FLOAT) + class MockBuilder(object): def __init__(self): @@ -79,13 +86,13 @@ result = self.builder.instrs assert result == expected - -class TestRegallocMov(BaseMovTest): - def mov(self, a, b, expected=None): self.asm.regalloc_mov(a, b) self.validate(expected) + +class TestRegallocMov(BaseMovTest): + def test_mov_imm_to_reg(self): val = imm(123) reg = r(7) @@ -491,3 +498,79 @@ def test_unsupported(self): py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm(1))') py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm_float(1))') + +class TestRawStackLocs(BaseMovTest): + def test_unsupported(self): + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm_float(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), r(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), vfp(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(r(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), raw_stack_float(1))') + + def test_from_imm(self): + s = raw_stack(1024) + i = imm(999) + e = [ + mi('gen_load_int', lr.value, i.value, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', lr.value, sp.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_vfp_imm(self): + s = raw_stack_float(1024) + i = imm_float(999) + e = [ + mi('gen_load_int', ip.value, i.value, cond=AL), + mi('VLDR', vfp_ip.value, ip.value, cond=AL, imm=0), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_reg(self): + s = raw_stack(1024) + reg = r(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', reg.value, sp.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_reg(self): + s = raw_stack_float(1024) + reg = vfp(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', reg.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_stack(self): + s = raw_stack(1024) + reg = stack(10) + e = [mi('LDR_ri', ip.value, fp.value, imm=216, cond=AL), + mi('gen_load_int', lr.value, s.value, cond=AL), + mi('STR_rr', ip.value, sp.value, lr.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_stack(self): + s = raw_stack_float(1024) + reg = stack_float(10) + e = [mi('VLDR', vfp_ip.value, fp.value, imm=220, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) From noreply at buildbot.pypy.org Mon May 27 14:52:30 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 27 May 2013 14:52:30 +0200 (CEST) Subject: [pypy-commit] pypy emit-call-arm: close branch Message-ID: <20130527125230.65A471C0189@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: emit-call-arm Changeset: r64579:3ef7a3fe63ac Date: 2013-05-27 07:42 -0500 http://bitbucket.org/pypy/pypy/changeset/3ef7a3fe63ac/ Log: close branch From noreply at buildbot.pypy.org Mon May 27 14:52:32 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 27 May 2013 14:52:32 +0200 (CEST) Subject: [pypy-commit] pypy default: merge emit-call-arm Message-ID: <20130527125232.1E19A1C0189@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64580:9e31743395b4 Date: 2013-05-27 07:43 -0500 http://bitbucket.org/pypy/pypy/changeset/9e31743395b4/ Log: merge emit-call-arm diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT, VOID from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -27,6 +27,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.arm import callbuilder class AssemblerARM(ResOpAssembler): @@ -934,23 +935,6 @@ asm_math_operations[oopspecindex](self, op, arglocs, regalloc, fcond) return fcond - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 4: - return - if size == 1: - if not signed: # unsigned char - self.mc.AND_ri(resloc.value, resloc.value, 0xFF) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 24) - self.mc.ASR_ri(resloc.value, resloc.value, 24) - elif size == 2: - if not signed: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.LSR_ri(resloc.value, resloc.value, 16) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.ASR_ri(resloc.value, resloc.value, 16) - def patch_trace(self, faildescr, looptoken, bridge_addr, regalloc): b = InstrBuilder(self.cpu.cpuinfo.arch_version) patch_addr = faildescr._arm_failure_recovery_block @@ -1012,20 +996,32 @@ mc.gen_load_int(helper.value, ofs, cond=cond) mc.STR_rr(source.value, base.value, helper.value, cond=cond) + def get_tmp_reg(self, forbidden_regs=None): + if forbidden_regs is None: + return r.ip, False + for x in [r.ip, r.lr]: + if x not in forbidden_regs: + return x, False + # pick some reg, that we need to save + for x in r.all_regs: + if x not in forbidden_regs: + return x, True + assert 0 + def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL): - if not loc.is_reg() and not (loc.is_stack() and loc.type != FLOAT): + if loc.type == FLOAT: raise AssertionError("invalid target for move from imm value") if loc.is_reg(): new_loc = loc - elif loc.is_stack(): - self.mc.PUSH([r.lr.value], cond=cond) + elif loc.is_stack() or loc.is_raw_sp(): new_loc = r.lr else: raise AssertionError("invalid target for move from imm value") self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond) if loc.is_stack(): self.regalloc_mov(new_loc, loc) - self.mc.POP([r.lr.value], cond=cond) + elif loc.is_raw_sp(): + self.store_reg(self.mc, new_loc, r.sp, loc.value, cond=cond, helper=r.ip) def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_imm(): @@ -1034,60 +1030,77 @@ self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond) elif loc.is_stack() and loc.type != FLOAT: # spill a core register - if prev_loc is r.ip: - temp = r.lr - else: - temp = r.ip + temp, save = self.get_tmp_reg([prev_loc, loc]) offset = loc.value is_imm = check_imm_arg(offset, size=0xFFF) - if not is_imm: + if not is_imm and save: self.mc.PUSH([temp.value], cond=cond) self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) - if not is_imm: + if not is_imm and save: self.mc.POP([temp.value], cond=cond) + elif loc.is_raw_sp() and loc.type != FLOAT: + temp, save = self.get_tmp_reg([prev_loc]) + assert not save + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) else: assert 0, 'unsupported case' def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL): - # disabled for now, has side effects in combination with remap_frame_layout when called from a jump - helper = None # self._regalloc.get_free_reg() + helper = None + offset = prev_loc.value + tmp = None if loc.is_reg(): assert prev_loc.type != FLOAT, 'trying to load from an \ incompatible location into a core register' - assert loc is not r.lr, 'lr is not supported as a target \ - when moving from the stack' # unspill a core register - offset = prev_loc.value is_imm = check_imm_arg(offset, size=0xFFF) - helper = r.lr if helper is None else helper - save_helper = not is_imm and helper is r.lr + helper, save = self.get_tmp_reg([loc]) + save_helper = not is_imm and save elif loc.is_vfp_reg(): assert prev_loc.type == FLOAT, 'trying to load from an \ incompatible location into a float register' # load spilled value into vfp reg - offset = prev_loc.value is_imm = check_imm_arg(offset) - helper = r.ip if helper is None else helper - save_helper = not is_imm and helper is r.ip + helper, save = self.get_tmp_reg() + save_helper = not is_imm and save + elif loc.is_raw_sp(): + assert (loc.type == prev_loc.type == FLOAT + or (loc.type != FLOAT and prev_loc.type != FLOAT)) + tmp = loc + if loc.is_float(): + loc = r.vfp_ip + else: + loc, save_helper = self.get_tmp_reg() + assert not save_helper + helper, save_helper = self.get_tmp_reg([loc]) + assert not save_helper else: assert 0, 'unsupported case' + if save_helper: self.mc.PUSH([helper.value], cond=cond) self.load_reg(self.mc, loc, r.fp, offset, cond=cond, helper=helper) if save_helper: self.mc.POP([helper.value], cond=cond) + if tmp and tmp.is_raw_sp(): + self.store_reg(self.mc, loc, r.sp, tmp.value, cond=cond, helper=helper) + def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_vfp_reg(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond) - self.load_reg(self.mc, loc, r.ip, 0, cond=cond) - self.mc.POP([r.ip.value], cond=cond) - elif loc.is_stack(): - self.regalloc_push(r.vfp_ip) + helper, save_helper = self.get_tmp_reg([loc]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, prev_loc.getint(), cond=cond) + self.load_reg(self.mc, loc, helper, 0, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) + elif loc.is_stack() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - self.regalloc_pop(r.vfp_ip) + elif loc.is_raw_sp() and loc.type == FLOAT: + self.regalloc_mov(prev_loc, r.vfp_ip, cond) + self.regalloc_mov(r.vfp_ip, loc, cond) else: assert 0, 'unsupported case' @@ -1100,11 +1113,11 @@ # spill vfp register offset = loc.value is_imm = check_imm_arg(offset) - if not is_imm: - self.mc.PUSH([r.ip.value], cond=cond) - self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond) - if not is_imm: - self.mc.POP([r.ip.value], cond=cond) + self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) + elif loc.is_raw_sp(): + assert loc.type == FLOAT, 'trying to store to an \ + incompatible location from a float register' + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' @@ -1120,6 +1133,8 @@ self._mov_imm_float_to_loc(prev_loc, loc, cond) elif prev_loc.is_vfp_reg(): self._mov_vfp_reg_to_loc(prev_loc, loc, cond) + elif prev_loc.is_raw_sp(): + assert 0, 'raw sp locs are not supported as source loc' else: assert 0, 'unsupported case' mov_loc_loc = regalloc_mov @@ -1131,23 +1146,29 @@ if vfp_loc.is_vfp_reg(): self.mc.VMOV_rc(reg1.value, reg2.value, vfp_loc.value, cond=cond) elif vfp_loc.is_imm_float(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, vfp_loc.getint(), cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, vfp_loc.getint(), cond=cond) # we need to load one word to loc and one to loc+1 which are # two 32-bit core registers - self.mc.LDR_ri(reg1.value, r.ip.value, cond=cond) - self.mc.LDR_ri(reg2.value, r.ip.value, imm=WORD, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + self.mc.LDR_ri(reg1.value, helper.value, cond=cond) + self.mc.LDR_ri(reg2.value, helper.value, imm=WORD, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif vfp_loc.is_stack() and vfp_loc.type == FLOAT: # load spilled vfp value into two core registers offset = vfp_loc.value if not check_imm_arg(offset, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.LDR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.LDR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.LDR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.LDR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.LDR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.LDR_ri(reg2.value, r.fp.value, @@ -1165,12 +1186,15 @@ # move from two core registers to a float stack location offset = vfp_loc.value if not check_imm_arg(offset + WORD, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.STR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.STR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.STR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.STR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.STR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.STR_ri(reg2.value, r.fp.value, @@ -1417,6 +1441,26 @@ # return shiftsize + def simple_call(self, fnloc, arglocs, result_loc=r.r0): + if result_loc is None: + result_type = VOID + result_size = 0 + elif result_loc.is_vfp_reg(): + result_type = FLOAT + result_size = DOUBLE_WORD + else: + result_type = INT + result_size = WORD + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() + + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs) + cb.emit_no_collect() + + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/callbuilder.py @@ -0,0 +1,304 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT, REF +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.assembler import saved_registers +from rpython.jit.backend.arm.helper.regalloc import check_imm_arg + + +class ARMCallbuilder(AbstractCallBuilder): + def __init__(self, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) + self.current_sp = 0 + + def push_gcmap(self): + assert not self.is_call_release_gil + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r0], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + self.asm.pop_gcmap(self.mc) + + def emit_raw_call(self): + #the actual call + if self.fnloc.is_imm(): + self.mc.BL(self.fnloc.value) + return + if self.fnloc.is_stack(): + self.asm.mov_loc_loc(self.fnloc, r.ip) + self.fnloc = r.ip + assert self.fnloc.is_reg() + self.mc.BLX(self.fnloc.value) + + def restore_stack_pointer(self): + # readjust the sp in case we passed some args on the stack + assert self.current_sp % 8 == 0 # sanity check + if self.current_sp != 0: + self._adjust_sp(self.current_sp) + self.current_sp = 0 + + def _push_stack_args(self, stack_args, on_stack): + assert on_stack % 8 == 0 + self._adjust_sp(-on_stack) + self.current_sp = on_stack + ofs = 0 + for i, arg in enumerate(stack_args): + if arg is not None: + sp_loc = RawSPStackLocation(ofs, arg.type) + self.asm.regalloc_mov(arg, sp_loc) + ofs += sp_loc.width + else: # alignment word + ofs += WORD + + def _adjust_sp(self, n): + # adjust the current stack pointer by n bytes + if n > 0: + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value) + else: + n = abs(n) + if check_imm_arg(n): + self.mc.SUB_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value) + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + + def call_releasegil_addr_and_move_real_arguments(self): + assert not self.asm._is_asmgcc() + from rpython.jit.backend.arm.regalloc import CoreRegisterManager + with saved_registers(self.mc, + CoreRegisterManager.save_around_call_regs): + self.mc.BL(self.asm.releasegil_addr) + + if not we_are_translated(): # for testing: we should not access + self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got + assert not self.asm._is_asmgcc() + gpr_to_save, vfp_to_save = self.get_result_locs() + with saved_registers(self.mc, gpr_to_save, vfp_to_save): + self.mc.BL(self.asm.reacqgil_addr) + + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again + + # for shadowstack, done for us by _reload_frame_if_necessary() + + def get_result_locs(self): + raise NotImplementedError + + def _ensure_result_bit_extension(self, resloc, size, signed): + if size == 4: + return + if size == 1: + if not signed: # unsigned char + self.mc.AND_ri(resloc.value, resloc.value, 0xFF) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 24) + self.mc.ASR_ri(resloc.value, resloc.value, 24) + elif size == 2: + if not signed: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.LSR_ri(resloc.value, resloc.value, 16) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.ASR_ri(resloc.value, resloc.value, 16) + + + +class SoftFloatCallBuilder(ARMCallbuilder): + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [r.r0, r.r1], [] + assert self.resloc.is_reg() + return [r.r0], [] + + def load_result(self): + # ensure the result is wellformed and stored in the correct location + resloc = self.resloc + if resloc is None: + return + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + # move result to the allocated register + if resloc is not r.r0: + self.asm.mov_loc_loc(r.r0, resloc) + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + + def _collect_and_push_stack_args(self, arglocs): + n_args = len(arglocs) + reg_args = count_reg_args(arglocs) + # all arguments past the 4th go on the stack + # first we need to prepare the list so it stays aligned + stack_args = [] + count = 0 + on_stack = 0 + if n_args > reg_args: + for i in range(reg_args, n_args): + arg = arglocs[i] + if arg.type != FLOAT: + count += 1 + on_stack += 1 + else: + on_stack += 2 + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + if count % 2 != 0: + on_stack += 1 + stack_args.append(None) + if on_stack > 0: + self._push_stack_args(stack_args, on_stack*WORD) + + def prepare_arguments(self): + arglocs = self.arglocs + reg_args = count_reg_args(arglocs) + self._collect_and_push_stack_args(arglocs) + # collect variables that need to go in registers and the registers they + # will be stored in + num = 0 + count = 0 + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(reg_args): + arg = arglocs[i] + if arg.type == FLOAT and count % 2 != 0: + num += 1 + count = 0 + reg = r.caller_resp[num] + + if arg.type == FLOAT: + float_locs.append((arg, reg)) + else: + non_float_locs.append(arg) + non_float_regs.append(reg) + + if arg.type == FLOAT: + num += 2 + else: + num += 1 + count += 1 + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in r.argument_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + + for loc, reg in float_locs: + self.asm.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) + +class HardFloatCallBuilder(ARMCallbuilder): + + def prepare_arguments(self): + non_float_locs = [] + non_float_regs = [] + float_locs = [] + float_regs = [] + stack_args = [] + + arglocs = self.arglocs + argtypes = self.argtypes + + count = 0 # stack alignment counter + on_stack = 0 + for arg in arglocs: + if arg.type != FLOAT: + if len(non_float_regs) < len(r.argument_regs): + reg = r.argument_regs[len(non_float_regs)] + non_float_locs.append(arg) + non_float_regs.append(reg) + else: # non-float argument that needs to go on the stack + count += 1 + on_stack += 1 + stack_args.append(arg) + else: + if len(float_regs) < len(r.vfp_argument_regs): + reg = r.vfp_argument_regs[len(float_regs)] + float_locs.append(arg) + float_regs.append(reg) + else: # float argument that needs to go on the stack + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + on_stack += 2 + # align the stack + if count % 2 != 0: + stack_args.append(None) + on_stack += 1 + self._push_stack_args(stack_args, on_stack*WORD) + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + # remap values stored in vfp registers + remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip) + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None and resloc.is_reg(): + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [], [r.d0] + assert self.resloc.is_reg() + return [r.r0], [] + + +def get_callbuilder(cpu, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + if cpu.cpuinfo.hf_abi: + return HardFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) + else: + return SoftFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) diff --git a/rpython/jit/backend/arm/locations.py b/rpython/jit/backend/arm/locations.py --- a/rpython/jit/backend/arm/locations.py +++ b/rpython/jit/backend/arm/locations.py @@ -12,6 +12,9 @@ def is_stack(self): return False + def is_raw_sp(self): + return False + def is_reg(self): return False @@ -145,7 +148,27 @@ return self.position + 10000 def is_float(self): - return type == FLOAT + return self.type == FLOAT + +class RawSPStackLocation(AssemblerLocation): + _immutable_ = True + + def __init__(self, sp_offset, type=INT): + if type == FLOAT: + self.width = DOUBLE_WORD + else: + self.width = WORD + self.value = sp_offset + self.type = type + + def __repr__(self): + return 'SP(%s)+%d' % (self.type, self.value,) + + def is_raw_sp(self): + return True + + def is_float(self): + return self.type == FLOAT def imm(i): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -13,8 +13,7 @@ gen_emit_float_cmp_op, gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, - saved_registers, - count_reg_args) + saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout @@ -31,8 +30,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.arm import callbuilder class ArmGuardToken(GuardToken): @@ -339,217 +337,36 @@ return fcond def emit_op_call(self, op, arglocs, regalloc, fcond): - resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + return self._emit_call(op, arglocs, fcond=fcond) + + def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): + # args = [resloc, size, sign, args...] + from rpython.jit.backend.llsupport.descr import CallDescr + + cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3], arglocs[4:], arglocs[0]) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - cond = self._emit_call(adr, arglist, - fcond, resloc, (size, signed)) - return cond + assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[1] + assert sizeloc.is_imm() + cb.ressize = sizeloc.value + signloc = arglocs[2] + assert signloc.is_imm() + cb.ressign = signloc.value - def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None, - result_info=(-1, -1), - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True): - if self.cpu.cpuinfo.hf_abi: - stack_args, adr = self._setup_call_hf(adr, arglocs, fcond, - resloc, result_info) + if is_call_release_gil: + cb.emit_call_release_gil() else: - stack_args, adr = self._setup_call_sf(adr, arglocs, fcond, - resloc, result_info) - - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - #the actual call - if adr.is_imm(): - self.mc.BL(adr.value) - elif adr.is_stack(): - self.mov_loc_loc(adr, r.ip) - adr = r.ip - else: - assert adr.is_reg() - if adr.is_reg(): - self.mc.BLX(adr.value) - self._restore_sp(stack_args, fcond) - - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg() and not self.cpu.cpuinfo.hf_abi: - # move result to the allocated register - self.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg() and result_info != (-1, -1): - self._ensure_result_bit_extension(resloc, result_info[0], - result_info[1]) - if can_collect: - self._reload_frame_if_necessary(self.mc) - self.pop_gcmap(self.mc) + cb.emit() return fcond - def _restore_sp(self, stack_args, fcond): - # readjust the sp in case we passed some args on the stack - if len(stack_args) > 0: - n = 0 - for arg in stack_args: - if arg is None or arg.type != FLOAT: - n += WORD - else: - n += DOUBLE_WORD - self._adjust_sp(-n, fcond=fcond) - assert n % 8 == 0 # sanity check - - def _adjust_sp(self, n, cb=None, fcond=c.AL, base_reg=r.sp): - if cb is None: - cb = self.mc - if n < 0: - n = -n - rev = True - else: - rev = False - if n <= 0xFF and fcond == c.AL: - if rev: - cb.ADD_ri(r.sp.value, base_reg.value, n) - else: - cb.SUB_ri(r.sp.value, base_reg.value, n) - else: - cb.gen_load_int(r.ip.value, n, cond=fcond) - if rev: - cb.ADD_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - else: - cb.SUB_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - - - def _collect_stack_args_sf(self, arglocs): - n_args = len(arglocs) - reg_args = count_reg_args(arglocs) - # all arguments past the 4th go on the stack - # first we need to prepare the list so it stays aligned - stack_args = [] - count = 0 - if n_args > reg_args: - for i in range(reg_args, n_args): - arg = arglocs[i] - if arg.type != FLOAT: - count += 1 - else: - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - if count % 2 != 0: - stack_args.append(None) - return stack_args - - def _push_stack_args(self, stack_args): - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.regalloc_push(arg) - - def _setup_call_sf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - reg_args = count_reg_args(arglocs) - stack_args = self._collect_stack_args_sf(arglocs) - self._push_stack_args(stack_args) - # collect variables that need to go in registers and the registers they - # will be stored in - num = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - for i in range(reg_args): - arg = arglocs[i] - if arg.type == FLOAT and count % 2 != 0: - num += 1 - count = 0 - reg = r.caller_resp[num] - - if arg.type == FLOAT: - float_locs.append((arg, reg)) - else: - non_float_locs.append(arg) - non_float_regs.append(reg) - - if arg.type == FLOAT: - num += 2 - else: - num += 1 - count += 1 - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - - for loc, reg in float_locs: - self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) - return stack_args, adr - - def _setup_call_hf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - count = 0 # stack alignment counter - for arg in arglocs: - if arg.type != FLOAT: - if len(non_float_regs) < len(r.argument_regs): - reg = r.argument_regs[len(non_float_regs)] - non_float_locs.append(arg) - non_float_regs.append(reg) - else: # non-float argument that needs to go on the stack - count += 1 - stack_args.append(arg) - else: - if len(float_regs) < len(r.vfp_argument_regs): - reg = r.vfp_argument_regs[len(float_regs)] - float_locs.append(arg) - float_regs.append(reg) - else: # float argument that needs to go on the stack - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - # align the stack - if count % 2 != 0: - stack_args.append(None) - self._push_stack_args(stack_args) - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - # remap values stored in vfp registers - remap_frame_layout(self, float_locs, float_regs, r.vfp_ip) - - return stack_args, adr - def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs - self.mov_loc_loc(argloc, resloc) + if argloc is not resloc: + self.mov_loc_loc(argloc, resloc) return fcond emit_op_cast_ptr_to_int = emit_op_same_as @@ -1037,9 +854,8 @@ length_loc = bytes_loc # call memcpy() regalloc.before_call() - self._emit_call(imm(self.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.simple_call_no_collect(imm(self.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.rm.possibly_free_var(length_box) regalloc.rm.possibly_free_var(dstaddr_box) regalloc.rm.possibly_free_var(srcaddr_box) @@ -1127,14 +943,14 @@ vloc = imm(0) self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op), guard_op.numargs()) + regalloc._prepare_guard(guard_op)) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self._emit_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], result_loc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self._emit_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, result_loc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') @@ -1213,20 +1029,14 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed)) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) + self._emit_call(op, callargs, fcond=fcond) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def _emit_guard_may_force(self, guard_op, arglocs, numargs): + def _emit_guard_may_force(self, guard_op, arglocs): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) @@ -1235,68 +1045,14 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): - + numargs = op.numargs() + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - # do the call - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed), - can_collect=False) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - self.pop_gcmap(self.mc) # remove the gcmap saved above - - self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) + self._emit_call(op, callargs, is_call_release_gil=True) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): - # Save caller saved registers and do the call - # NOTE: We assume that the floating point registers won't be modified. - assert gcrootmap.is_shadow_stack - with saved_registers(self.mc, regalloc.rm.save_around_call_regs): - self._emit_call(imm(self.releasegil_addr), [], - fcond, can_collect=False) - - def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): - # save the previous result into the stack temporarily, in case it is in - # a caller saved register. - # NOTE: like with call_release_gil(), we assume that we don't need to - # save vfp regs in this case. Besides the result location - regs_to_save = [] - vfp_regs_to_save = [] - if save_loc and save_loc in regalloc.rm.save_around_call_regs: - regs_to_save.append(save_loc) - regs_to_save.append(r.ip) # for alingment - elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs: - vfp_regs_to_save.append(save_loc) - assert gcrootmap.is_shadow_stack - # call the reopenstack() function (also reacquiring the GIL) - with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): - self._emit_call(imm(self.reacqgil_addr), [], fcond, - can_collect=False) - self._reload_frame_if_necessary(self.mc) - def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -34,6 +34,7 @@ from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr from rpython.rlib.rarithmetic import r_uint +from rpython.jit.backend.llsupport.descr import CallDescr # xxx hack: set a default value for TargetToken._ll_loop_code. If 0, we know @@ -555,9 +556,27 @@ return self._prepare_call(op) def _prepare_call(self, op, force_store=[], save_all_regs=False): - args = [None] * (op.numargs() + 1) + args = [None] * (op.numargs() + 3) + calldescr = op.getdescr() + assert isinstance(calldescr, CallDescr) + assert len(calldescr.arg_classes) == op.numargs() - 1 + for i in range(op.numargs()): - args[i + 1] = self.loc(op.getarg(i)) + args[i + 3] = self.loc(op.getarg(i)) + + size = calldescr.get_result_size() + sign = calldescr.is_result_signed() + if sign: + sign_loc = imm(1) + else: + sign_loc = imm(0) + args[1] = imm(size) + args[2] = sign_loc + + args[0] = self._call(op, args, force_store, save_all_regs) + return args + + def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls self.vfprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -565,11 +584,11 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(save_all_regs=save_all_regs) + self.before_call_called = True + resloc = None if op.result: resloc = self.after_call(op.result) - args[0] = resloc - self.before_call_called = True - return args + return resloc def prepare_op_call_malloc_gc(self, op, fcond): return self._prepare_call(op) @@ -1153,9 +1172,9 @@ def prepare_guard_call_assembler(self, op, guard_op, fcond): locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) - call_locs = self._prepare_call(op, save_all_regs=True) + resloc = self._call(op, locs + [tmploc], save_all_regs=True) self.possibly_free_vars(guard_op.getfailargs()) - return locs + [call_locs[0], tmploc] + return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -1,9 +1,10 @@ from rpython.rlib.objectmodel import instantiate from rpython.jit.backend.arm.assembler import AssemblerARM -from rpython.jit.backend.arm.locations import imm, ConstFloatLoc,\ - RegisterLocation, StackLocation, \ - VFPRegisterLocation, get_fp_offset -from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip +from rpython.jit.backend.arm.locations import imm, ConstFloatLoc +from rpython.jit.backend.arm.locations import RegisterLocation, StackLocation +from rpython.jit.backend.arm.locations import VFPRegisterLocation, get_fp_offset +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip, sp from rpython.jit.backend.arm.conditions import AL from rpython.jit.backend.arm.arch import WORD from rpython.jit.metainterp.history import FLOAT @@ -54,6 +55,12 @@ addr = int(value) # whatever return ConstFloatLoc(addr) +def raw_stack(i): + return RawSPStackLocation(i) + +def raw_stack_float(i): + return RawSPStackLocation(i, type=FLOAT) + class MockBuilder(object): def __init__(self): @@ -79,13 +86,13 @@ result = self.builder.instrs assert result == expected - -class TestRegallocMov(BaseMovTest): - def mov(self, a, b, expected=None): self.asm.regalloc_mov(a, b) self.validate(expected) + +class TestRegallocMov(BaseMovTest): + def test_mov_imm_to_reg(self): val = imm(123) reg = r(7) @@ -102,45 +109,37 @@ val = imm(100) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 100, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_stacklock(self): val = imm(65536) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 65536, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] - + ] self.mov(val, s, expected) def test_mov_imm_to_big_stacklock(self): val = imm(100) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 100, cond=AL), - mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 100, cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_big_stacklock(self): val = imm(65536) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 65536, cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_reg_to_reg(self): @@ -158,10 +157,10 @@ def test_mov_reg_to_big_stackloc(self): s = stack(8191) r6 = r(6) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r6.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r6, s, expected) def test_mov_stack_to_reg(self): @@ -174,10 +173,8 @@ s = stack(8191) r6 = r(6) expected = [ - mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 32940, cond=AL), - mi('LDR_rr', r6.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), + mi('gen_load_int', ip.value, 32940, cond=AL), + mi('LDR_rr', r6.value, fp.value, ip.value, cond=AL), ] self.mov(s, r6, expected) @@ -185,10 +182,9 @@ f = imm_float(3.5) reg = vfp(5) expected = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, f.value, cond=AL), mi('VLDR', 5, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(f, reg, expected) def test_mov_vfp_reg_to_vfp_reg(self): @@ -206,11 +202,11 @@ def test_mov_vfp_reg_to_large_stackloc(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_mov_stack_to_vfp_reg(self): @@ -222,11 +218,11 @@ def test_mov_big_stackloc_to_vfp_reg(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_unsopported_cases(self): @@ -265,8 +261,6 @@ py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), vfp(2))') py.test.raises(AssertionError, - 'self.asm.regalloc_mov(stack(1), lr)') - py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm(2))') py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm_float(2))') @@ -312,12 +306,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('LDR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=WORD, cond=AL), mi('LDR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(s, r1, r2, e) def test_from_imm_float(self): @@ -325,11 +318,10 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, i.value, cond=AL), mi('LDR_ri', r1.value, ip.value, cond=AL), mi('LDR_ri', r2.value, ip.value, imm=4, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(i, r1, r2, e) def test_unsupported(self): @@ -369,12 +361,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=4, cond=AL), mi('STR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r1, r2, s, e) def unsupported(self): @@ -408,10 +399,9 @@ def test_push_imm_float(self): f = imm_float(7) - e = [mi('PUSH', [ip.value], cond=AL), + e = [ mi('gen_load_int', ip.value, 7, cond=AL), mi('VLDR', vfp_ip.value, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL) ] self.push(f, e) @@ -426,10 +416,8 @@ def test_push_big_stack(self): s = stack(1025) e = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('LDR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), mi('PUSH', [ip.value], cond=AL) ] self.push(s, e) @@ -450,11 +438,9 @@ def test_push_large_stackfloat(self): sf = stack_float(100) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, sf.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VLDR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL), ] self.push(sf, e) @@ -486,10 +472,8 @@ s = stack(1200) e = [ mi('POP', [ip.value], cond=AL), - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('STR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL) ] self.pop(s, e) @@ -505,13 +489,88 @@ s = stack_float(1200) e = [ mi('VPOP', [vfp_ip.value], cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.pop(s, e) def test_unsupported(self): py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm(1))') py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm_float(1))') + +class TestRawStackLocs(BaseMovTest): + def test_unsupported(self): + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm_float(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), r(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), vfp(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(r(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), raw_stack_float(1))') + + def test_from_imm(self): + s = raw_stack(1024) + i = imm(999) + e = [ + mi('gen_load_int', lr.value, i.value, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', lr.value, sp.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_vfp_imm(self): + s = raw_stack_float(1024) + i = imm_float(999) + e = [ + mi('gen_load_int', ip.value, i.value, cond=AL), + mi('VLDR', vfp_ip.value, ip.value, cond=AL, imm=0), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_reg(self): + s = raw_stack(1024) + reg = r(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', reg.value, sp.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_reg(self): + s = raw_stack_float(1024) + reg = vfp(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', reg.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_stack(self): + s = raw_stack(1024) + reg = stack(10) + e = [mi('LDR_ri', ip.value, fp.value, imm=216, cond=AL), + mi('gen_load_int', lr.value, s.value, cond=AL), + mi('STR_rr', ip.value, sp.value, lr.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_stack(self): + s = raw_stack_float(1024) + reg = stack_float(10) + e = [mi('VLDR', vfp_ip.value, fp.value, imm=220, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) 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 @@ -372,6 +372,9 @@ self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + def _is_asmgcc(self): + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + return bool(gcrootmap) and not gcrootmap.is_shadow_stack def debug_bridge(descr_number, rawstart, codeendpos): diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/llsupport/callbuilder.py @@ -0,0 +1,92 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI + +class AbstractCallBuilder(object): + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + + def __init__(self, assembler, fnloc, arglocs, resloc, restype, ressize): + self.fnloc = fnloc + self.arglocs = arglocs + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_stack_pointer() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def call_releasegil_addr_and_move_real_arguments(self): + raise NotImplementedError + + def move_real_result_and_call_reacqgil_addr(self): + raise NotImplementedError + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + + def prepare_arguments(self): + raise NotImplementedError + + def push_gcmap(self): + raise NotImplementedError + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + raise NotImplementedError + + def emit_raw_call(self): + raise NotImplementedError + + def restore_stack_pointer(self): + raise NotImplementedError + + def load_result(self): + raise NotImplementedError diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -999,10 +999,6 @@ self.implement_guard(guard_token, checkfalsecond) return genop_cmp_guard_float - def _is_asmgcc(self): - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: result_type = FLOAT diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -8,6 +8,7 @@ r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) from rpython.jit.backend.x86.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder # darwin requires the stack to be 16 bytes aligned on calls. @@ -18,77 +19,30 @@ return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - -class AbstractCallBuilder(object): +class CallBuilderX86(AbstractCallBuilder): # max number of words we have room in esp; if we need more for # arguments, we need to decrease esp temporarily stack_max = PASS_ON_MY_FRAME - # this can be set to guide more complex calls: gives the detailed - # type of the arguments - argtypes = "" - ressign = False - - # this is the calling convention (can be FFI_STDCALL on Windows) - callconv = FFI_DEFAULT_ABI - - # is it for the main CALL of a call_release_gil? - is_call_release_gil = False - # set by save_result_value() tmpresloc = None - def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT, ressize=WORD): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) # Avoid tons of issues with a non-immediate fnloc by sticking it # as an extra argument if needed self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) - if self.fnloc_is_immediate: - self.fnloc = fnloc - self.arglocs = arglocs - else: + if not self.fnloc_is_immediate: + self.fnloc = None self.arglocs = arglocs + [fnloc] - self.asm = assembler - self.mc = assembler.mc - self.resloc = resloc - self.restype = restype - self.ressize = ressize self.current_esp = 0 # 0 or (usually) negative, counted in bytes - def emit_no_collect(self): - """Emit a call that cannot collect.""" - self.prepare_arguments() - self.emit_raw_call() - self.restore_esp() - self.load_result() - - def emit(self): - """Emit a regular call; not for CALL_RELEASE_GIL.""" - self.prepare_arguments() - self.push_gcmap() - self.emit_raw_call() - self.restore_esp() - self.pop_gcmap() - self.load_result() - - def emit_call_release_gil(self): - """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr - and reacqgil_addr.""" - self.select_call_release_gil_mode() - self.prepare_arguments() - self.push_gcmap_for_call_release_gil() - self.call_releasegil_addr_and_move_real_arguments() - self.emit_raw_call() - self.restore_esp() - self.move_real_result_and_call_reacqgil_addr() - self.pop_gcmap() - self.load_result() - def select_call_release_gil_mode(self): """Overridden in CallBuilder64""" - self.is_call_release_gil = True + AbstractCallBuilder.select_call_release_gil_mode(self) if self.asm._is_asmgcc(): from rpython.memory.gctransform import asmgcroot self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS @@ -105,7 +59,7 @@ self.current_esp -= align * WORD self.mc.SUB_ri(esp.value, align * WORD) - def restore_esp(self, target_esp=0): + def restore_stack_pointer(self, target_esp=0): if self.current_esp != target_esp: self.mc.ADD_ri(esp.value, target_esp - self.current_esp) self.current_esp = target_esp @@ -140,17 +94,6 @@ gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) self.asm.push_gcmap(self.mc, gcmap, store=True) - def push_gcmap_for_call_release_gil(self): - assert self.is_call_release_gil - # we put the gcmap now into the frame before releasing the GIL, - # and pop it after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self.asm._regalloc.get_gcmap(noregs=True) - self.asm.push_gcmap(self.mc, gcmap, store=True) - def pop_gcmap(self): self.asm._reload_frame_if_necessary(self.mc) if self.change_extra_stack_depth: @@ -204,7 +147,7 @@ self.mc.ADD(ebp, imm(1)) # ebp any more # self.restore_register_arguments() - self.restore_esp(initial_esp) + self.restore_stack_pointer(initial_esp) def save_register_arguments(self): """Overridden in CallBuilder64""" @@ -248,7 +191,7 @@ raise NotImplementedError -class CallBuilder32(AbstractCallBuilder): +class CallBuilder32(CallBuilderX86): def prepare_arguments(self): arglocs = self.arglocs @@ -318,7 +261,7 @@ else: self.mc.MOV(resloc, self.tmpresloc) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP+4]. We use "+4" @@ -343,7 +286,7 @@ self.mc.MOV_sr(4, eax.value) -class CallBuilder64(AbstractCallBuilder): +class CallBuilder64(CallBuilderX86): ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] @@ -389,7 +332,7 @@ i += 1 def select_call_release_gil_mode(self): - AbstractCallBuilder.select_call_release_gil_mode(self) + CallBuilderX86.select_call_release_gil_mode(self) # We have to copy the arguments around a bit more in this mode, # but on the other hand we don't need prepare_arguments() moving # them in precisely the final registers. Here we look around for @@ -502,7 +445,7 @@ # from the lower 32 bits of XMM0 self.mc.MOVD(self.resloc, xmm0) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP]. From noreply at buildbot.pypy.org Mon May 27 14:58:45 2013 From: noreply at buildbot.pypy.org (Stian Andreassen) Date: Mon, 27 May 2013 14:58:45 +0200 (CEST) Subject: [pypy-commit] pypy default: No need to mask the carry bit. Message-ID: <20130527125845.D8ED81C0189@cobra.cs.uni-duesseldorf.de> Author: Stian Andreassen Branch: Changeset: r64581:ccb0ca253584 Date: 2013-05-27 14:50 +0200 http://bitbucket.org/pypy/pypy/changeset/ccb0ca253584/ Log: No need to mask the carry bit. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -189,7 +189,7 @@ carry = ival >> SHIFT if carry: return rbigint([_store_digit(ival & MASK), - _store_digit(carry & MASK)], sign, 2) + _store_digit(carry)], sign, 2) else: return rbigint([_store_digit(ival & MASK)], sign, 1) @@ -566,7 +566,7 @@ res = b.widedigit(0) * a.widedigit(0) carry = res >> SHIFT if carry: - return rbigint([_store_digit(res & MASK), _store_digit(carry & MASK)], a.sign * b.sign, 2) + return rbigint([_store_digit(res & MASK), _store_digit(carry)], a.sign * b.sign, 2) else: return rbigint([_store_digit(res & MASK)], a.sign * b.sign, 1) From noreply at buildbot.pypy.org Mon May 27 14:58:47 2013 From: noreply at buildbot.pypy.org (Stian Andreassen) Date: Mon, 27 May 2013 14:58:47 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge Message-ID: <20130527125847.6619E1C0189@cobra.cs.uni-duesseldorf.de> Author: Stian Andreassen Branch: Changeset: r64582:99e5b6182fd5 Date: 2013-05-27 14:52 +0200 http://bitbucket.org/pypy/pypy/changeset/99e5b6182fd5/ Log: Merge diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT, VOID from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -27,6 +27,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.arm import callbuilder class AssemblerARM(ResOpAssembler): @@ -934,23 +935,6 @@ asm_math_operations[oopspecindex](self, op, arglocs, regalloc, fcond) return fcond - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 4: - return - if size == 1: - if not signed: # unsigned char - self.mc.AND_ri(resloc.value, resloc.value, 0xFF) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 24) - self.mc.ASR_ri(resloc.value, resloc.value, 24) - elif size == 2: - if not signed: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.LSR_ri(resloc.value, resloc.value, 16) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.ASR_ri(resloc.value, resloc.value, 16) - def patch_trace(self, faildescr, looptoken, bridge_addr, regalloc): b = InstrBuilder(self.cpu.cpuinfo.arch_version) patch_addr = faildescr._arm_failure_recovery_block @@ -1012,20 +996,32 @@ mc.gen_load_int(helper.value, ofs, cond=cond) mc.STR_rr(source.value, base.value, helper.value, cond=cond) + def get_tmp_reg(self, forbidden_regs=None): + if forbidden_regs is None: + return r.ip, False + for x in [r.ip, r.lr]: + if x not in forbidden_regs: + return x, False + # pick some reg, that we need to save + for x in r.all_regs: + if x not in forbidden_regs: + return x, True + assert 0 + def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL): - if not loc.is_reg() and not (loc.is_stack() and loc.type != FLOAT): + if loc.type == FLOAT: raise AssertionError("invalid target for move from imm value") if loc.is_reg(): new_loc = loc - elif loc.is_stack(): - self.mc.PUSH([r.lr.value], cond=cond) + elif loc.is_stack() or loc.is_raw_sp(): new_loc = r.lr else: raise AssertionError("invalid target for move from imm value") self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond) if loc.is_stack(): self.regalloc_mov(new_loc, loc) - self.mc.POP([r.lr.value], cond=cond) + elif loc.is_raw_sp(): + self.store_reg(self.mc, new_loc, r.sp, loc.value, cond=cond, helper=r.ip) def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_imm(): @@ -1034,60 +1030,77 @@ self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond) elif loc.is_stack() and loc.type != FLOAT: # spill a core register - if prev_loc is r.ip: - temp = r.lr - else: - temp = r.ip + temp, save = self.get_tmp_reg([prev_loc, loc]) offset = loc.value is_imm = check_imm_arg(offset, size=0xFFF) - if not is_imm: + if not is_imm and save: self.mc.PUSH([temp.value], cond=cond) self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) - if not is_imm: + if not is_imm and save: self.mc.POP([temp.value], cond=cond) + elif loc.is_raw_sp() and loc.type != FLOAT: + temp, save = self.get_tmp_reg([prev_loc]) + assert not save + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) else: assert 0, 'unsupported case' def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL): - # disabled for now, has side effects in combination with remap_frame_layout when called from a jump - helper = None # self._regalloc.get_free_reg() + helper = None + offset = prev_loc.value + tmp = None if loc.is_reg(): assert prev_loc.type != FLOAT, 'trying to load from an \ incompatible location into a core register' - assert loc is not r.lr, 'lr is not supported as a target \ - when moving from the stack' # unspill a core register - offset = prev_loc.value is_imm = check_imm_arg(offset, size=0xFFF) - helper = r.lr if helper is None else helper - save_helper = not is_imm and helper is r.lr + helper, save = self.get_tmp_reg([loc]) + save_helper = not is_imm and save elif loc.is_vfp_reg(): assert prev_loc.type == FLOAT, 'trying to load from an \ incompatible location into a float register' # load spilled value into vfp reg - offset = prev_loc.value is_imm = check_imm_arg(offset) - helper = r.ip if helper is None else helper - save_helper = not is_imm and helper is r.ip + helper, save = self.get_tmp_reg() + save_helper = not is_imm and save + elif loc.is_raw_sp(): + assert (loc.type == prev_loc.type == FLOAT + or (loc.type != FLOAT and prev_loc.type != FLOAT)) + tmp = loc + if loc.is_float(): + loc = r.vfp_ip + else: + loc, save_helper = self.get_tmp_reg() + assert not save_helper + helper, save_helper = self.get_tmp_reg([loc]) + assert not save_helper else: assert 0, 'unsupported case' + if save_helper: self.mc.PUSH([helper.value], cond=cond) self.load_reg(self.mc, loc, r.fp, offset, cond=cond, helper=helper) if save_helper: self.mc.POP([helper.value], cond=cond) + if tmp and tmp.is_raw_sp(): + self.store_reg(self.mc, loc, r.sp, tmp.value, cond=cond, helper=helper) + def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_vfp_reg(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond) - self.load_reg(self.mc, loc, r.ip, 0, cond=cond) - self.mc.POP([r.ip.value], cond=cond) - elif loc.is_stack(): - self.regalloc_push(r.vfp_ip) + helper, save_helper = self.get_tmp_reg([loc]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, prev_loc.getint(), cond=cond) + self.load_reg(self.mc, loc, helper, 0, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) + elif loc.is_stack() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - self.regalloc_pop(r.vfp_ip) + elif loc.is_raw_sp() and loc.type == FLOAT: + self.regalloc_mov(prev_loc, r.vfp_ip, cond) + self.regalloc_mov(r.vfp_ip, loc, cond) else: assert 0, 'unsupported case' @@ -1100,11 +1113,11 @@ # spill vfp register offset = loc.value is_imm = check_imm_arg(offset) - if not is_imm: - self.mc.PUSH([r.ip.value], cond=cond) - self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond) - if not is_imm: - self.mc.POP([r.ip.value], cond=cond) + self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) + elif loc.is_raw_sp(): + assert loc.type == FLOAT, 'trying to store to an \ + incompatible location from a float register' + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' @@ -1120,6 +1133,8 @@ self._mov_imm_float_to_loc(prev_loc, loc, cond) elif prev_loc.is_vfp_reg(): self._mov_vfp_reg_to_loc(prev_loc, loc, cond) + elif prev_loc.is_raw_sp(): + assert 0, 'raw sp locs are not supported as source loc' else: assert 0, 'unsupported case' mov_loc_loc = regalloc_mov @@ -1131,23 +1146,29 @@ if vfp_loc.is_vfp_reg(): self.mc.VMOV_rc(reg1.value, reg2.value, vfp_loc.value, cond=cond) elif vfp_loc.is_imm_float(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, vfp_loc.getint(), cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, vfp_loc.getint(), cond=cond) # we need to load one word to loc and one to loc+1 which are # two 32-bit core registers - self.mc.LDR_ri(reg1.value, r.ip.value, cond=cond) - self.mc.LDR_ri(reg2.value, r.ip.value, imm=WORD, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + self.mc.LDR_ri(reg1.value, helper.value, cond=cond) + self.mc.LDR_ri(reg2.value, helper.value, imm=WORD, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif vfp_loc.is_stack() and vfp_loc.type == FLOAT: # load spilled vfp value into two core registers offset = vfp_loc.value if not check_imm_arg(offset, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.LDR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.LDR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.LDR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.LDR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.LDR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.LDR_ri(reg2.value, r.fp.value, @@ -1165,12 +1186,15 @@ # move from two core registers to a float stack location offset = vfp_loc.value if not check_imm_arg(offset + WORD, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.STR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.STR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.STR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.STR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.STR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.STR_ri(reg2.value, r.fp.value, @@ -1417,6 +1441,26 @@ # return shiftsize + def simple_call(self, fnloc, arglocs, result_loc=r.r0): + if result_loc is None: + result_type = VOID + result_size = 0 + elif result_loc.is_vfp_reg(): + result_type = FLOAT + result_size = DOUBLE_WORD + else: + result_type = INT + result_size = WORD + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() + + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs) + cb.emit_no_collect() + + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/callbuilder.py @@ -0,0 +1,304 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT, REF +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.assembler import saved_registers +from rpython.jit.backend.arm.helper.regalloc import check_imm_arg + + +class ARMCallbuilder(AbstractCallBuilder): + def __init__(self, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) + self.current_sp = 0 + + def push_gcmap(self): + assert not self.is_call_release_gil + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r0], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + self.asm.pop_gcmap(self.mc) + + def emit_raw_call(self): + #the actual call + if self.fnloc.is_imm(): + self.mc.BL(self.fnloc.value) + return + if self.fnloc.is_stack(): + self.asm.mov_loc_loc(self.fnloc, r.ip) + self.fnloc = r.ip + assert self.fnloc.is_reg() + self.mc.BLX(self.fnloc.value) + + def restore_stack_pointer(self): + # readjust the sp in case we passed some args on the stack + assert self.current_sp % 8 == 0 # sanity check + if self.current_sp != 0: + self._adjust_sp(self.current_sp) + self.current_sp = 0 + + def _push_stack_args(self, stack_args, on_stack): + assert on_stack % 8 == 0 + self._adjust_sp(-on_stack) + self.current_sp = on_stack + ofs = 0 + for i, arg in enumerate(stack_args): + if arg is not None: + sp_loc = RawSPStackLocation(ofs, arg.type) + self.asm.regalloc_mov(arg, sp_loc) + ofs += sp_loc.width + else: # alignment word + ofs += WORD + + def _adjust_sp(self, n): + # adjust the current stack pointer by n bytes + if n > 0: + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value) + else: + n = abs(n) + if check_imm_arg(n): + self.mc.SUB_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value) + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + + def call_releasegil_addr_and_move_real_arguments(self): + assert not self.asm._is_asmgcc() + from rpython.jit.backend.arm.regalloc import CoreRegisterManager + with saved_registers(self.mc, + CoreRegisterManager.save_around_call_regs): + self.mc.BL(self.asm.releasegil_addr) + + if not we_are_translated(): # for testing: we should not access + self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got + assert not self.asm._is_asmgcc() + gpr_to_save, vfp_to_save = self.get_result_locs() + with saved_registers(self.mc, gpr_to_save, vfp_to_save): + self.mc.BL(self.asm.reacqgil_addr) + + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again + + # for shadowstack, done for us by _reload_frame_if_necessary() + + def get_result_locs(self): + raise NotImplementedError + + def _ensure_result_bit_extension(self, resloc, size, signed): + if size == 4: + return + if size == 1: + if not signed: # unsigned char + self.mc.AND_ri(resloc.value, resloc.value, 0xFF) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 24) + self.mc.ASR_ri(resloc.value, resloc.value, 24) + elif size == 2: + if not signed: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.LSR_ri(resloc.value, resloc.value, 16) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.ASR_ri(resloc.value, resloc.value, 16) + + + +class SoftFloatCallBuilder(ARMCallbuilder): + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [r.r0, r.r1], [] + assert self.resloc.is_reg() + return [r.r0], [] + + def load_result(self): + # ensure the result is wellformed and stored in the correct location + resloc = self.resloc + if resloc is None: + return + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + # move result to the allocated register + if resloc is not r.r0: + self.asm.mov_loc_loc(r.r0, resloc) + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + + def _collect_and_push_stack_args(self, arglocs): + n_args = len(arglocs) + reg_args = count_reg_args(arglocs) + # all arguments past the 4th go on the stack + # first we need to prepare the list so it stays aligned + stack_args = [] + count = 0 + on_stack = 0 + if n_args > reg_args: + for i in range(reg_args, n_args): + arg = arglocs[i] + if arg.type != FLOAT: + count += 1 + on_stack += 1 + else: + on_stack += 2 + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + if count % 2 != 0: + on_stack += 1 + stack_args.append(None) + if on_stack > 0: + self._push_stack_args(stack_args, on_stack*WORD) + + def prepare_arguments(self): + arglocs = self.arglocs + reg_args = count_reg_args(arglocs) + self._collect_and_push_stack_args(arglocs) + # collect variables that need to go in registers and the registers they + # will be stored in + num = 0 + count = 0 + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(reg_args): + arg = arglocs[i] + if arg.type == FLOAT and count % 2 != 0: + num += 1 + count = 0 + reg = r.caller_resp[num] + + if arg.type == FLOAT: + float_locs.append((arg, reg)) + else: + non_float_locs.append(arg) + non_float_regs.append(reg) + + if arg.type == FLOAT: + num += 2 + else: + num += 1 + count += 1 + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in r.argument_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + + for loc, reg in float_locs: + self.asm.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) + +class HardFloatCallBuilder(ARMCallbuilder): + + def prepare_arguments(self): + non_float_locs = [] + non_float_regs = [] + float_locs = [] + float_regs = [] + stack_args = [] + + arglocs = self.arglocs + argtypes = self.argtypes + + count = 0 # stack alignment counter + on_stack = 0 + for arg in arglocs: + if arg.type != FLOAT: + if len(non_float_regs) < len(r.argument_regs): + reg = r.argument_regs[len(non_float_regs)] + non_float_locs.append(arg) + non_float_regs.append(reg) + else: # non-float argument that needs to go on the stack + count += 1 + on_stack += 1 + stack_args.append(arg) + else: + if len(float_regs) < len(r.vfp_argument_regs): + reg = r.vfp_argument_regs[len(float_regs)] + float_locs.append(arg) + float_regs.append(reg) + else: # float argument that needs to go on the stack + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + on_stack += 2 + # align the stack + if count % 2 != 0: + stack_args.append(None) + on_stack += 1 + self._push_stack_args(stack_args, on_stack*WORD) + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + # remap values stored in vfp registers + remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip) + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None and resloc.is_reg(): + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [], [r.d0] + assert self.resloc.is_reg() + return [r.r0], [] + + +def get_callbuilder(cpu, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + if cpu.cpuinfo.hf_abi: + return HardFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) + else: + return SoftFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) diff --git a/rpython/jit/backend/arm/locations.py b/rpython/jit/backend/arm/locations.py --- a/rpython/jit/backend/arm/locations.py +++ b/rpython/jit/backend/arm/locations.py @@ -12,6 +12,9 @@ def is_stack(self): return False + def is_raw_sp(self): + return False + def is_reg(self): return False @@ -145,7 +148,27 @@ return self.position + 10000 def is_float(self): - return type == FLOAT + return self.type == FLOAT + +class RawSPStackLocation(AssemblerLocation): + _immutable_ = True + + def __init__(self, sp_offset, type=INT): + if type == FLOAT: + self.width = DOUBLE_WORD + else: + self.width = WORD + self.value = sp_offset + self.type = type + + def __repr__(self): + return 'SP(%s)+%d' % (self.type, self.value,) + + def is_raw_sp(self): + return True + + def is_float(self): + return self.type == FLOAT def imm(i): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -13,8 +13,7 @@ gen_emit_float_cmp_op, gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, - saved_registers, - count_reg_args) + saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout @@ -31,8 +30,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.arm import callbuilder class ArmGuardToken(GuardToken): @@ -339,217 +337,36 @@ return fcond def emit_op_call(self, op, arglocs, regalloc, fcond): - resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + return self._emit_call(op, arglocs, fcond=fcond) + + def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): + # args = [resloc, size, sign, args...] + from rpython.jit.backend.llsupport.descr import CallDescr + + cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3], arglocs[4:], arglocs[0]) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - cond = self._emit_call(adr, arglist, - fcond, resloc, (size, signed)) - return cond + assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[1] + assert sizeloc.is_imm() + cb.ressize = sizeloc.value + signloc = arglocs[2] + assert signloc.is_imm() + cb.ressign = signloc.value - def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None, - result_info=(-1, -1), - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True): - if self.cpu.cpuinfo.hf_abi: - stack_args, adr = self._setup_call_hf(adr, arglocs, fcond, - resloc, result_info) + if is_call_release_gil: + cb.emit_call_release_gil() else: - stack_args, adr = self._setup_call_sf(adr, arglocs, fcond, - resloc, result_info) - - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - #the actual call - if adr.is_imm(): - self.mc.BL(adr.value) - elif adr.is_stack(): - self.mov_loc_loc(adr, r.ip) - adr = r.ip - else: - assert adr.is_reg() - if adr.is_reg(): - self.mc.BLX(adr.value) - self._restore_sp(stack_args, fcond) - - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg() and not self.cpu.cpuinfo.hf_abi: - # move result to the allocated register - self.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg() and result_info != (-1, -1): - self._ensure_result_bit_extension(resloc, result_info[0], - result_info[1]) - if can_collect: - self._reload_frame_if_necessary(self.mc) - self.pop_gcmap(self.mc) + cb.emit() return fcond - def _restore_sp(self, stack_args, fcond): - # readjust the sp in case we passed some args on the stack - if len(stack_args) > 0: - n = 0 - for arg in stack_args: - if arg is None or arg.type != FLOAT: - n += WORD - else: - n += DOUBLE_WORD - self._adjust_sp(-n, fcond=fcond) - assert n % 8 == 0 # sanity check - - def _adjust_sp(self, n, cb=None, fcond=c.AL, base_reg=r.sp): - if cb is None: - cb = self.mc - if n < 0: - n = -n - rev = True - else: - rev = False - if n <= 0xFF and fcond == c.AL: - if rev: - cb.ADD_ri(r.sp.value, base_reg.value, n) - else: - cb.SUB_ri(r.sp.value, base_reg.value, n) - else: - cb.gen_load_int(r.ip.value, n, cond=fcond) - if rev: - cb.ADD_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - else: - cb.SUB_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - - - def _collect_stack_args_sf(self, arglocs): - n_args = len(arglocs) - reg_args = count_reg_args(arglocs) - # all arguments past the 4th go on the stack - # first we need to prepare the list so it stays aligned - stack_args = [] - count = 0 - if n_args > reg_args: - for i in range(reg_args, n_args): - arg = arglocs[i] - if arg.type != FLOAT: - count += 1 - else: - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - if count % 2 != 0: - stack_args.append(None) - return stack_args - - def _push_stack_args(self, stack_args): - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.regalloc_push(arg) - - def _setup_call_sf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - reg_args = count_reg_args(arglocs) - stack_args = self._collect_stack_args_sf(arglocs) - self._push_stack_args(stack_args) - # collect variables that need to go in registers and the registers they - # will be stored in - num = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - for i in range(reg_args): - arg = arglocs[i] - if arg.type == FLOAT and count % 2 != 0: - num += 1 - count = 0 - reg = r.caller_resp[num] - - if arg.type == FLOAT: - float_locs.append((arg, reg)) - else: - non_float_locs.append(arg) - non_float_regs.append(reg) - - if arg.type == FLOAT: - num += 2 - else: - num += 1 - count += 1 - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - - for loc, reg in float_locs: - self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) - return stack_args, adr - - def _setup_call_hf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - count = 0 # stack alignment counter - for arg in arglocs: - if arg.type != FLOAT: - if len(non_float_regs) < len(r.argument_regs): - reg = r.argument_regs[len(non_float_regs)] - non_float_locs.append(arg) - non_float_regs.append(reg) - else: # non-float argument that needs to go on the stack - count += 1 - stack_args.append(arg) - else: - if len(float_regs) < len(r.vfp_argument_regs): - reg = r.vfp_argument_regs[len(float_regs)] - float_locs.append(arg) - float_regs.append(reg) - else: # float argument that needs to go on the stack - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - # align the stack - if count % 2 != 0: - stack_args.append(None) - self._push_stack_args(stack_args) - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - # remap values stored in vfp registers - remap_frame_layout(self, float_locs, float_regs, r.vfp_ip) - - return stack_args, adr - def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs - self.mov_loc_loc(argloc, resloc) + if argloc is not resloc: + self.mov_loc_loc(argloc, resloc) return fcond emit_op_cast_ptr_to_int = emit_op_same_as @@ -1037,9 +854,8 @@ length_loc = bytes_loc # call memcpy() regalloc.before_call() - self._emit_call(imm(self.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.simple_call_no_collect(imm(self.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.rm.possibly_free_var(length_box) regalloc.rm.possibly_free_var(dstaddr_box) regalloc.rm.possibly_free_var(srcaddr_box) @@ -1127,14 +943,14 @@ vloc = imm(0) self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op), guard_op.numargs()) + regalloc._prepare_guard(guard_op)) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self._emit_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], result_loc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self._emit_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, result_loc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') @@ -1213,20 +1029,14 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed)) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) + self._emit_call(op, callargs, fcond=fcond) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def _emit_guard_may_force(self, guard_op, arglocs, numargs): + def _emit_guard_may_force(self, guard_op, arglocs): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) @@ -1235,68 +1045,14 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): - + numargs = op.numargs() + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - # do the call - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed), - can_collect=False) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - self.pop_gcmap(self.mc) # remove the gcmap saved above - - self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) + self._emit_call(op, callargs, is_call_release_gil=True) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): - # Save caller saved registers and do the call - # NOTE: We assume that the floating point registers won't be modified. - assert gcrootmap.is_shadow_stack - with saved_registers(self.mc, regalloc.rm.save_around_call_regs): - self._emit_call(imm(self.releasegil_addr), [], - fcond, can_collect=False) - - def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): - # save the previous result into the stack temporarily, in case it is in - # a caller saved register. - # NOTE: like with call_release_gil(), we assume that we don't need to - # save vfp regs in this case. Besides the result location - regs_to_save = [] - vfp_regs_to_save = [] - if save_loc and save_loc in regalloc.rm.save_around_call_regs: - regs_to_save.append(save_loc) - regs_to_save.append(r.ip) # for alingment - elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs: - vfp_regs_to_save.append(save_loc) - assert gcrootmap.is_shadow_stack - # call the reopenstack() function (also reacquiring the GIL) - with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): - self._emit_call(imm(self.reacqgil_addr), [], fcond, - can_collect=False) - self._reload_frame_if_necessary(self.mc) - def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -34,6 +34,7 @@ from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr from rpython.rlib.rarithmetic import r_uint +from rpython.jit.backend.llsupport.descr import CallDescr # xxx hack: set a default value for TargetToken._ll_loop_code. If 0, we know @@ -555,9 +556,27 @@ return self._prepare_call(op) def _prepare_call(self, op, force_store=[], save_all_regs=False): - args = [None] * (op.numargs() + 1) + args = [None] * (op.numargs() + 3) + calldescr = op.getdescr() + assert isinstance(calldescr, CallDescr) + assert len(calldescr.arg_classes) == op.numargs() - 1 + for i in range(op.numargs()): - args[i + 1] = self.loc(op.getarg(i)) + args[i + 3] = self.loc(op.getarg(i)) + + size = calldescr.get_result_size() + sign = calldescr.is_result_signed() + if sign: + sign_loc = imm(1) + else: + sign_loc = imm(0) + args[1] = imm(size) + args[2] = sign_loc + + args[0] = self._call(op, args, force_store, save_all_regs) + return args + + def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls self.vfprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -565,11 +584,11 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(save_all_regs=save_all_regs) + self.before_call_called = True + resloc = None if op.result: resloc = self.after_call(op.result) - args[0] = resloc - self.before_call_called = True - return args + return resloc def prepare_op_call_malloc_gc(self, op, fcond): return self._prepare_call(op) @@ -1153,9 +1172,9 @@ def prepare_guard_call_assembler(self, op, guard_op, fcond): locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) - call_locs = self._prepare_call(op, save_all_regs=True) + resloc = self._call(op, locs + [tmploc], save_all_regs=True) self.possibly_free_vars(guard_op.getfailargs()) - return locs + [call_locs[0], tmploc] + return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -1,9 +1,10 @@ from rpython.rlib.objectmodel import instantiate from rpython.jit.backend.arm.assembler import AssemblerARM -from rpython.jit.backend.arm.locations import imm, ConstFloatLoc,\ - RegisterLocation, StackLocation, \ - VFPRegisterLocation, get_fp_offset -from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip +from rpython.jit.backend.arm.locations import imm, ConstFloatLoc +from rpython.jit.backend.arm.locations import RegisterLocation, StackLocation +from rpython.jit.backend.arm.locations import VFPRegisterLocation, get_fp_offset +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip, sp from rpython.jit.backend.arm.conditions import AL from rpython.jit.backend.arm.arch import WORD from rpython.jit.metainterp.history import FLOAT @@ -54,6 +55,12 @@ addr = int(value) # whatever return ConstFloatLoc(addr) +def raw_stack(i): + return RawSPStackLocation(i) + +def raw_stack_float(i): + return RawSPStackLocation(i, type=FLOAT) + class MockBuilder(object): def __init__(self): @@ -79,13 +86,13 @@ result = self.builder.instrs assert result == expected - -class TestRegallocMov(BaseMovTest): - def mov(self, a, b, expected=None): self.asm.regalloc_mov(a, b) self.validate(expected) + +class TestRegallocMov(BaseMovTest): + def test_mov_imm_to_reg(self): val = imm(123) reg = r(7) @@ -102,45 +109,37 @@ val = imm(100) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 100, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_stacklock(self): val = imm(65536) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 65536, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] - + ] self.mov(val, s, expected) def test_mov_imm_to_big_stacklock(self): val = imm(100) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 100, cond=AL), - mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 100, cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_big_stacklock(self): val = imm(65536) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 65536, cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_reg_to_reg(self): @@ -158,10 +157,10 @@ def test_mov_reg_to_big_stackloc(self): s = stack(8191) r6 = r(6) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r6.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r6, s, expected) def test_mov_stack_to_reg(self): @@ -174,10 +173,8 @@ s = stack(8191) r6 = r(6) expected = [ - mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 32940, cond=AL), - mi('LDR_rr', r6.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), + mi('gen_load_int', ip.value, 32940, cond=AL), + mi('LDR_rr', r6.value, fp.value, ip.value, cond=AL), ] self.mov(s, r6, expected) @@ -185,10 +182,9 @@ f = imm_float(3.5) reg = vfp(5) expected = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, f.value, cond=AL), mi('VLDR', 5, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(f, reg, expected) def test_mov_vfp_reg_to_vfp_reg(self): @@ -206,11 +202,11 @@ def test_mov_vfp_reg_to_large_stackloc(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_mov_stack_to_vfp_reg(self): @@ -222,11 +218,11 @@ def test_mov_big_stackloc_to_vfp_reg(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_unsopported_cases(self): @@ -265,8 +261,6 @@ py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), vfp(2))') py.test.raises(AssertionError, - 'self.asm.regalloc_mov(stack(1), lr)') - py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm(2))') py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm_float(2))') @@ -312,12 +306,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('LDR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=WORD, cond=AL), mi('LDR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(s, r1, r2, e) def test_from_imm_float(self): @@ -325,11 +318,10 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, i.value, cond=AL), mi('LDR_ri', r1.value, ip.value, cond=AL), mi('LDR_ri', r2.value, ip.value, imm=4, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(i, r1, r2, e) def test_unsupported(self): @@ -369,12 +361,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=4, cond=AL), mi('STR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r1, r2, s, e) def unsupported(self): @@ -408,10 +399,9 @@ def test_push_imm_float(self): f = imm_float(7) - e = [mi('PUSH', [ip.value], cond=AL), + e = [ mi('gen_load_int', ip.value, 7, cond=AL), mi('VLDR', vfp_ip.value, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL) ] self.push(f, e) @@ -426,10 +416,8 @@ def test_push_big_stack(self): s = stack(1025) e = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('LDR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), mi('PUSH', [ip.value], cond=AL) ] self.push(s, e) @@ -450,11 +438,9 @@ def test_push_large_stackfloat(self): sf = stack_float(100) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, sf.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VLDR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL), ] self.push(sf, e) @@ -486,10 +472,8 @@ s = stack(1200) e = [ mi('POP', [ip.value], cond=AL), - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('STR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL) ] self.pop(s, e) @@ -505,13 +489,88 @@ s = stack_float(1200) e = [ mi('VPOP', [vfp_ip.value], cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.pop(s, e) def test_unsupported(self): py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm(1))') py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm_float(1))') + +class TestRawStackLocs(BaseMovTest): + def test_unsupported(self): + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm_float(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), r(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), vfp(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(r(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), raw_stack_float(1))') + + def test_from_imm(self): + s = raw_stack(1024) + i = imm(999) + e = [ + mi('gen_load_int', lr.value, i.value, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', lr.value, sp.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_vfp_imm(self): + s = raw_stack_float(1024) + i = imm_float(999) + e = [ + mi('gen_load_int', ip.value, i.value, cond=AL), + mi('VLDR', vfp_ip.value, ip.value, cond=AL, imm=0), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_reg(self): + s = raw_stack(1024) + reg = r(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', reg.value, sp.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_reg(self): + s = raw_stack_float(1024) + reg = vfp(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', reg.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_stack(self): + s = raw_stack(1024) + reg = stack(10) + e = [mi('LDR_ri', ip.value, fp.value, imm=216, cond=AL), + mi('gen_load_int', lr.value, s.value, cond=AL), + mi('STR_rr', ip.value, sp.value, lr.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_stack(self): + s = raw_stack_float(1024) + reg = stack_float(10) + e = [mi('VLDR', vfp_ip.value, fp.value, imm=220, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) 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 @@ -372,6 +372,9 @@ self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + def _is_asmgcc(self): + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + return bool(gcrootmap) and not gcrootmap.is_shadow_stack def debug_bridge(descr_number, rawstart, codeendpos): diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/llsupport/callbuilder.py @@ -0,0 +1,92 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI + +class AbstractCallBuilder(object): + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + + def __init__(self, assembler, fnloc, arglocs, resloc, restype, ressize): + self.fnloc = fnloc + self.arglocs = arglocs + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_stack_pointer() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def call_releasegil_addr_and_move_real_arguments(self): + raise NotImplementedError + + def move_real_result_and_call_reacqgil_addr(self): + raise NotImplementedError + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + + def prepare_arguments(self): + raise NotImplementedError + + def push_gcmap(self): + raise NotImplementedError + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + raise NotImplementedError + + def emit_raw_call(self): + raise NotImplementedError + + def restore_stack_pointer(self): + raise NotImplementedError + + def load_result(self): + raise NotImplementedError diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -999,10 +999,6 @@ self.implement_guard(guard_token, checkfalsecond) return genop_cmp_guard_float - def _is_asmgcc(self): - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: result_type = FLOAT diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -8,6 +8,7 @@ r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) from rpython.jit.backend.x86.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder # darwin requires the stack to be 16 bytes aligned on calls. @@ -18,77 +19,30 @@ return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - -class AbstractCallBuilder(object): +class CallBuilderX86(AbstractCallBuilder): # max number of words we have room in esp; if we need more for # arguments, we need to decrease esp temporarily stack_max = PASS_ON_MY_FRAME - # this can be set to guide more complex calls: gives the detailed - # type of the arguments - argtypes = "" - ressign = False - - # this is the calling convention (can be FFI_STDCALL on Windows) - callconv = FFI_DEFAULT_ABI - - # is it for the main CALL of a call_release_gil? - is_call_release_gil = False - # set by save_result_value() tmpresloc = None - def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT, ressize=WORD): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) # Avoid tons of issues with a non-immediate fnloc by sticking it # as an extra argument if needed self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) - if self.fnloc_is_immediate: - self.fnloc = fnloc - self.arglocs = arglocs - else: + if not self.fnloc_is_immediate: + self.fnloc = None self.arglocs = arglocs + [fnloc] - self.asm = assembler - self.mc = assembler.mc - self.resloc = resloc - self.restype = restype - self.ressize = ressize self.current_esp = 0 # 0 or (usually) negative, counted in bytes - def emit_no_collect(self): - """Emit a call that cannot collect.""" - self.prepare_arguments() - self.emit_raw_call() - self.restore_esp() - self.load_result() - - def emit(self): - """Emit a regular call; not for CALL_RELEASE_GIL.""" - self.prepare_arguments() - self.push_gcmap() - self.emit_raw_call() - self.restore_esp() - self.pop_gcmap() - self.load_result() - - def emit_call_release_gil(self): - """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr - and reacqgil_addr.""" - self.select_call_release_gil_mode() - self.prepare_arguments() - self.push_gcmap_for_call_release_gil() - self.call_releasegil_addr_and_move_real_arguments() - self.emit_raw_call() - self.restore_esp() - self.move_real_result_and_call_reacqgil_addr() - self.pop_gcmap() - self.load_result() - def select_call_release_gil_mode(self): """Overridden in CallBuilder64""" - self.is_call_release_gil = True + AbstractCallBuilder.select_call_release_gil_mode(self) if self.asm._is_asmgcc(): from rpython.memory.gctransform import asmgcroot self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS @@ -105,7 +59,7 @@ self.current_esp -= align * WORD self.mc.SUB_ri(esp.value, align * WORD) - def restore_esp(self, target_esp=0): + def restore_stack_pointer(self, target_esp=0): if self.current_esp != target_esp: self.mc.ADD_ri(esp.value, target_esp - self.current_esp) self.current_esp = target_esp @@ -140,17 +94,6 @@ gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) self.asm.push_gcmap(self.mc, gcmap, store=True) - def push_gcmap_for_call_release_gil(self): - assert self.is_call_release_gil - # we put the gcmap now into the frame before releasing the GIL, - # and pop it after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self.asm._regalloc.get_gcmap(noregs=True) - self.asm.push_gcmap(self.mc, gcmap, store=True) - def pop_gcmap(self): self.asm._reload_frame_if_necessary(self.mc) if self.change_extra_stack_depth: @@ -204,7 +147,7 @@ self.mc.ADD(ebp, imm(1)) # ebp any more # self.restore_register_arguments() - self.restore_esp(initial_esp) + self.restore_stack_pointer(initial_esp) def save_register_arguments(self): """Overridden in CallBuilder64""" @@ -248,7 +191,7 @@ raise NotImplementedError -class CallBuilder32(AbstractCallBuilder): +class CallBuilder32(CallBuilderX86): def prepare_arguments(self): arglocs = self.arglocs @@ -318,7 +261,7 @@ else: self.mc.MOV(resloc, self.tmpresloc) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP+4]. We use "+4" @@ -343,7 +286,7 @@ self.mc.MOV_sr(4, eax.value) -class CallBuilder64(AbstractCallBuilder): +class CallBuilder64(CallBuilderX86): ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] @@ -389,7 +332,7 @@ i += 1 def select_call_release_gil_mode(self): - AbstractCallBuilder.select_call_release_gil_mode(self) + CallBuilderX86.select_call_release_gil_mode(self) # We have to copy the arguments around a bit more in this mode, # but on the other hand we don't need prepare_arguments() moving # them in precisely the final registers. Here we look around for @@ -502,7 +445,7 @@ # from the lower 32 bits of XMM0 self.mc.MOVD(self.resloc, xmm0) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP]. From noreply at buildbot.pypy.org Mon May 27 15:31:13 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 15:31:13 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix a warning Message-ID: <20130527133113.2162E1C13B4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r38:8ad26fdbea4a Date: 2013-05-27 14:34 +0200 http://bitbucket.org/pypy/stmgc/changeset/8ad26fdbea4a/ Log: Fix a warning diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -774,7 +774,7 @@ revision_t newrev = -(cur_time + 1); assert(newrev & 1); ACCESS_ONCE(stm_local_revision) = newrev; - fprintf(stderr, "%p: stm_local_revision = %ld\n", d, newrev); + fprintf(stderr, "%p: stm_local_revision = %ld\n", d, (long)newrev); assert(d->local_revision_ref = &stm_local_revision); UpdateChainHeads(d, cur_time, localrev); From noreply at buildbot.pypy.org Mon May 27 15:31:14 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 15:31:14 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix a subtle issue Message-ID: <20130527133114.4758B1C13B4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r39:c928b67403e8 Date: 2013-05-27 14:51 +0200 http://bitbucket.org/pypy/stmgc/changeset/c928b67403e8/ Log: Fix a subtle issue diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -113,7 +113,7 @@ stmgcpage_release_global_lock(); } -struct tx_descriptor *stm_find_thread_containing_pointer(gcptr L) +struct tx_descriptor *stm_find_thread_containing_pointer_and_lock(gcptr L) { stmgcpage_acquire_global_lock(); @@ -126,6 +126,10 @@ abort(); found: + /* must acquire the collection_lock before releasing the global lock, + otherwise 'd' might be freed under our feet */ + spinlock_acquire(d->collection_lock, 'S'); /* stealing */ + stmgcpage_release_global_lock(); return d; } diff --git a/c3/gcpage.h b/c3/gcpage.h --- a/c3/gcpage.h +++ b/c3/gcpage.h @@ -76,7 +76,7 @@ void stmgcpage_free(gcptr obj); void stmgcpage_add_prebuilt_root(gcptr obj); void stmgcpage_possibly_major_collect(int force); -struct tx_descriptor *stm_find_thread_containing_pointer(gcptr); +struct tx_descriptor *stm_find_thread_containing_pointer_and_lock(gcptr); extern struct GcPtrList stm_prebuilt_gcroots; diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -1030,11 +1030,13 @@ thread's minor collection lock. This also prevents several threads from getting on each other's toes trying to extract objects from the same nursery */ - struct tx_descriptor *source_d = stm_find_thread_containing_pointer(R); + struct tx_descriptor *source_d; + + /* source_d->collection_lock will be acquired with 'S' (stealing) + by the following call: */ + source_d = stm_find_thread_containing_pointer_and_lock(R); assert(source_d != thread_descriptor); - spinlock_acquire(source_d->collection_lock, 'S'); /* stealing */ - /* now that we have the lock, check again that P->h_revision was not modified in the meantime. If it did change, we do nothing and will retry. From noreply at buildbot.pypy.org Mon May 27 15:31:15 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 15:31:15 +0200 (CEST) Subject: [pypy-commit] stmgc default: Another similar bug Message-ID: <20130527133115.7CD8F1C13B4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r40:134108fde888 Date: 2013-05-27 15:28 +0200 http://bitbucket.org/pypy/stmgc/changeset/134108fde888/ Log: Another similar bug diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -122,8 +122,8 @@ if (stmgc_is_young_in(d, L)) goto found; } - assert(0); /* L is not a young pointer anywhere! */ - abort(); + stmgcpage_release_global_lock(); + return NULL; /* L is not a young pointer anywhere! */ found: /* must acquire the collection_lock before releasing the global lock, diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -1042,6 +1042,8 @@ retry. */ if (P->h_revision == v) { + assert(source_d != NULL); + /* careful here: all 'thread_descriptor' accesses will continue to get the current thread (needed e.g. for stmgcpage_malloc()) which is different from 'source_d', the source thread out of @@ -1067,7 +1069,9 @@ /* debugging support: "deactivate" the foreign nursery again */ assert(stmgc_nursery_hiding(source_d, 1)); } - spinlock_release(source_d->collection_lock); + + if (source_d != NULL) + spinlock_release(source_d->collection_lock); } static void normalize_stolen_objects(struct tx_descriptor *d) From noreply at buildbot.pypy.org Mon May 27 15:31:16 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 15:31:16 +0200 (CEST) Subject: [pypy-commit] stmgc default: Refactor the code (but not what it does) to include checking all the Message-ID: <20130527133116.92DCB1C13B4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r41:e95c7bc26589 Date: 2013-05-27 15:31 +0200 http://bitbucket.org/pypy/stmgc/changeset/e95c7bc26589/ Log: Refactor the code (but not what it does) to include checking all the time that the numbers make sense. Found that it contains a rare crash, but has been crashing the same way forever. diff --git a/c3/Makefile b/c3/Makefile --- a/c3/Makefile +++ b/c3/Makefile @@ -28,7 +28,7 @@ H_FILES = et.h lists.h nursery.h gcpage.h stmsync.h dbgmem.h stmgc.h atomic_ops.h stmimpl.h C_FILES = et.c lists.c nursery.c gcpage.c stmsync.c dbgmem.c -DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 +DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=2 build-%: %.c ${H_FILES} ${C_FILES} diff --git a/c3/demo1.c b/c3/demo1.c --- a/c3/demo1.c +++ b/c3/demo1.c @@ -10,7 +10,7 @@ #include "stmgc.h" -#define UPPER_BOUND 250 +#define UPPER_BOUND 10 #define NUMTHREADS 4 @@ -42,28 +42,50 @@ NULL, }; +struct node *do_a_check(int seen[], int stress_gc) +{ + int i; + for (i=0; ivalue == -1); + while (r_n->next) + { + prev_n = r_n; /* for gdb only */ + + if (stress_gc) + { + /* allocate a young object that is forgotten, to stress the GC */ + stm_push_root((gcptr)r_n); + stm_allocate(sizeof(struct node), GCTID_STRUCT_NODE); + r_n = (struct node *)stm_pop_root(); + } + + r_n = (struct node *)stm_read_barrier((gcptr)r_n->next); + long v = r_n->value; + assert(0 <= v && v < UPPER_BOUND); + if (v == 0) + assert(seen[v] < NUMTHREADS); + else + assert(seen[v] < seen[v-1]); + seen[v]++; + } + return r_n; +} + int insert1(gcptr arg1, int retry_counter) { + int seen[UPPER_BOUND]; long nvalue; - struct node *n = &global_chained_list; - struct node *last = NULL; struct node *r_arg; r_arg = (struct node *)stm_read_barrier(arg1); nvalue = r_arg->value; - while (n) - { - n = (struct node *)stm_read_barrier((gcptr)n); + struct node *last = do_a_check(seen, 1); - /* allocate a young object that is forgotten, to stress the GC */ - stm_push_root((gcptr)n); - stm_allocate(sizeof(struct node), GCTID_STRUCT_NODE); - n = (struct node *)stm_pop_root(); - - last = n; - n = n->next; - } stm_push_root((gcptr)last); struct node *w_newnode = (struct node *)stm_allocate(sizeof(struct node), @@ -83,7 +105,7 @@ extern void stmgcpage_possibly_major_collect(int force); /* temp */ -void* demo1(void *arg) +void *demo1(void *arg) { int i, status; struct node *w_node; @@ -107,29 +129,13 @@ return NULL; } -void check(int numthreads) +void final_check(void) { - struct node *r_n; int seen[UPPER_BOUND]; - int i; - for (i=0; ivalue == -1); - while (r_n->next) - { - r_n = (struct node *)stm_read_barrier((gcptr)r_n->next); - long v = r_n->value; - assert(0 <= v && v < UPPER_BOUND); - if (v == 0) - assert(seen[v] < numthreads); - else - assert(seen[v] < seen[v-1]); - seen[v]++; - } - assert(seen[UPPER_BOUND-1] == numthreads); + do_a_check(seen, 0); + assert(seen[UPPER_BOUND-1] == NUMTHREADS); stm_finalize(); printf("check ok\n"); } @@ -146,22 +152,21 @@ int main(void) { - int numthreads = NUMTHREADS; int i, status; status = sem_init(&done, 0, 0); assert(status == 0); - for (i=0; i Author: Armin Rigo Branch: Changeset: r42:0fc12d746859 Date: 2013-05-27 16:13 +0200 http://bitbucket.org/pypy/stmgc/changeset/0fc12d746859/ Log: Fix diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -621,6 +621,7 @@ static void CancelLocks(struct tx_descriptor *d) { + revision_t my_lock = d->my_lock; wlog_t *item; if (!g2l_any_entry(&d->public_to_private)) @@ -628,16 +629,20 @@ G2L_LOOP_FORWARD(d->public_to_private, item) { + gcptr R = item->addr; gcptr L = item->val; revision_t v = L->h_revision; if (v == stm_local_revision) - break; /* done */ + { + assert(R->h_revision != my_lock); + break; /* done */ + } L->h_revision = stm_local_revision; - gcptr R = item->addr; #ifdef DUMP_EXTRA fprintf(stderr, "%p->h_revision = %p (CancelLocks)\n", R, (gcptr)v); #endif + assert(R->h_revision == my_lock); ACCESS_ONCE(R->h_revision) = v; } G2L_LOOP_END; diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -108,7 +108,12 @@ void stmgc_done_tls(void) { struct tx_descriptor *d = thread_descriptor; + + spinlock_acquire(d->collection_lock, 'F'); /* freeing */ + assert(d->nursery_current == d->nursery); /* else, not empty! */ + assert(!g2l_any_entry(&d->young_objects_outside_nursery)); + stm_free(d->nursery, GC_NURSERY); gcptrlist_delete(&d->protected_with_private_copy); g2l_delete(&d->public_to_private); From noreply at buildbot.pypy.org Mon May 27 16:17:01 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 16:17:01 +0200 (CEST) Subject: [pypy-commit] stmgc default: Add a hack to display the stderr messages in colors depending on which Message-ID: <20130527141701.A1C411C1464@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r43:c27946a8f461 Date: 2013-05-27 16:14 +0200 http://bitbucket.org/pypy/stmgc/changeset/c27946a8f461/ Log: Add a hack to display the stderr messages in colors depending on which thread emits them. diff --git a/c3/fprintcolor.h b/c3/fprintcolor.h new file mode 100644 --- /dev/null +++ b/c3/fprintcolor.h @@ -0,0 +1,37 @@ +#include + + +#define fprintf threadcolor_fprintf + + +int threadcolor_fprintf(FILE *stream, const char *format, ...) + __attribute__((unused, format (printf, 2, 3), weak)); + +int threadcolor_fprintf(FILE *stream, const char *format, ...) +{ + char buffer[2048]; + va_list ap; + int result; + static __thread revision_t color = 0; + if (color == 0) { + static revision_t nextid = 0; + while (1) { + color = nextid; + if (bool_cas(&nextid, color, color + 1)) + break; + } + color = 31 + color % 7; + } + int size = (int)sprintf(buffer, "\033[%dm", (int)color); + assert(size >= 0); + + va_start(ap, format); + result = vsnprintf(buffer + size, 2000, format, ap); + assert(result >= 0); + va_end(ap); + + strcpy(buffer + size + result, "\033[0m"); + fputs(buffer, stream); + + return result; +} diff --git a/c3/stmimpl.h b/c3/stmimpl.h --- a/c3/stmimpl.h +++ b/c3/stmimpl.h @@ -27,6 +27,7 @@ #include "stmgc.h" #include "atomic_ops.h" +#include "fprintcolor.h" #include "lists.h" #include "dbgmem.h" #include "nursery.h" From noreply at buildbot.pypy.org Mon May 27 16:22:13 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 16:22:13 +0200 (CEST) Subject: [pypy-commit] stmgc default: Fix the coloring Message-ID: <20130527142213.B453A1C1464@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r44:53f2a3179081 Date: 2013-05-27 16:21 +0200 http://bitbucket.org/pypy/stmgc/changeset/53f2a3179081/ Log: Fix the coloring diff --git a/c3/Makefile b/c3/Makefile --- a/c3/Makefile +++ b/c3/Makefile @@ -25,8 +25,8 @@ +make test-demo4 test-demo5 test-demo1 test-demo2 test-demo3 -H_FILES = et.h lists.h nursery.h gcpage.h stmsync.h dbgmem.h stmgc.h atomic_ops.h stmimpl.h -C_FILES = et.c lists.c nursery.c gcpage.c stmsync.c dbgmem.c +H_FILES = et.h lists.h nursery.h gcpage.h stmsync.h dbgmem.h fprintcolor.h stmgc.h atomic_ops.h stmimpl.h +C_FILES = et.c lists.c nursery.c gcpage.c stmsync.c dbgmem.c fprintcolor.c DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=2 diff --git a/c3/fprintcolor.c b/c3/fprintcolor.c new file mode 100644 --- /dev/null +++ b/c3/fprintcolor.c @@ -0,0 +1,32 @@ +#include "stmimpl.h" + +static __thread revision_t tcolor = 0; +static revision_t tnextid = 0; + + +int threadcolor_fprintf(FILE *stream, const char *format, ...) +{ + char buffer[2048]; + va_list ap; + int result; + if (tcolor == 0) { + while (1) { + tcolor = tnextid; + if (bool_cas(&tnextid, tcolor, tcolor + 1)) + break; + } + tcolor = 31 + tcolor % 7; + } + int size = (int)sprintf(buffer, "\033[%dm", (int)tcolor); + assert(size >= 0); + + va_start(ap, format); + result = vsnprintf(buffer + size, 2000, format, ap); + assert(result >= 0); + va_end(ap); + + strcpy(buffer + size + result, "\033[0m"); + fputs(buffer, stream); + + return result; +} diff --git a/c3/fprintcolor.h b/c3/fprintcolor.h --- a/c3/fprintcolor.h +++ b/c3/fprintcolor.h @@ -5,33 +5,4 @@ int threadcolor_fprintf(FILE *stream, const char *format, ...) - __attribute__((unused, format (printf, 2, 3), weak)); - -int threadcolor_fprintf(FILE *stream, const char *format, ...) -{ - char buffer[2048]; - va_list ap; - int result; - static __thread revision_t color = 0; - if (color == 0) { - static revision_t nextid = 0; - while (1) { - color = nextid; - if (bool_cas(&nextid, color, color + 1)) - break; - } - color = 31 + color % 7; - } - int size = (int)sprintf(buffer, "\033[%dm", (int)color); - assert(size >= 0); - - va_start(ap, format); - result = vsnprintf(buffer + size, 2000, format, ap); - assert(result >= 0); - va_end(ap); - - strcpy(buffer + size + result, "\033[0m"); - fputs(buffer, stream); - - return result; -} + __attribute__((format (printf, 2, 3))); diff --git a/c3/test/support.py b/c3/test/support.py --- a/c3/test/support.py +++ b/c3/test/support.py @@ -6,11 +6,11 @@ header_files = [os.path.join(parent_dir, _n) for _n in "et.h lists.h nursery.h gcpage.h " - "stmsync.h dbgmem.h " + "stmsync.h dbgmem.h fprintcolor.h " "stmgc.h stmimpl.h atomic_ops.h".split()] source_files = [os.path.join(parent_dir, _n) for _n in "et.c lists.c nursery.c gcpage.c " - "stmsync.c dbgmem.c".split()] + "stmsync.c dbgmem.c fprintcolor.c".split()] _pycache_ = os.path.join(parent_dir, 'test', '__pycache__') if os.path.exists(_pycache_): From noreply at buildbot.pypy.org Mon May 27 18:12:51 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 27 May 2013 18:12:51 +0200 (CEST) Subject: [pypy-commit] pypy default: Backported 5629bf4c6bba from CPython. Message-ID: <20130527161251.692271C1442@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64584:5911ba2ee308 Date: 2013-05-25 13:59 -0400 http://bitbucket.org/pypy/pypy/changeset/5911ba2ee308/ Log: Backported 5629bf4c6bba from CPython. diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py --- a/lib-python/2.7/logging/__init__.py +++ b/lib-python/2.7/logging/__init__.py @@ -134,20 +134,22 @@ DEBUG = 10 NOTSET = 0 -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO : 'INFO', - DEBUG : 'DEBUG', - NOTSET : 'NOTSET', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARNING, - 'WARNING' : WARNING, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'NOTSET' : NOTSET, +_levelToName = { + CRITICAL: 'CRITICAL', + ERROR: 'ERROR', + WARNING: 'WARNING', + INFO: 'INFO', + DEBUG: 'DEBUG', + NOTSET: 'NOTSET', +} +_nameToLevel = { + 'CRITICAL': CRITICAL, + 'ERROR': ERROR, + 'WARN': WARNING, + 'WARNING': WARNING, + 'INFO': INFO, + 'DEBUG': DEBUG, + 'NOTSET': NOTSET, } def getLevelName(level): @@ -164,7 +166,7 @@ Otherwise, the string "Level %s" % level is returned. """ - return _levelNames.get(level, ("Level %s" % level)) + return _levelToName.get(level, ("Level %s" % level)) def addLevelName(level, levelName): """ @@ -174,8 +176,8 @@ """ _acquireLock() try: #unlikely to cause an exception, but you never know... - _levelNames[level] = levelName - _levelNames[levelName] = level + _levelToName[level] = levelName + _nameToLevel[levelName] = level finally: _releaseLock() @@ -183,9 +185,9 @@ if isinstance(level, int): rv = level elif str(level) == level: - if level not in _levelNames: + if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) - rv = _levelNames[level] + rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv diff --git a/lib-python/2.7/logging/config.py b/lib-python/2.7/logging/config.py --- a/lib-python/2.7/logging/config.py +++ b/lib-python/2.7/logging/config.py @@ -156,7 +156,7 @@ h = klass(*args) if "level" in opts: level = cp.get(sectname, "level") - h.setLevel(logging._levelNames[level]) + h.setLevel(level) if len(fmt): h.setFormatter(formatters[fmt]) if issubclass(klass, logging.handlers.MemoryHandler): @@ -187,7 +187,7 @@ opts = cp.options(sectname) if "level" in opts: level = cp.get(sectname, "level") - log.setLevel(logging._levelNames[level]) + log.setLevel(level) for h in root.handlers[:]: root.removeHandler(h) hlist = cp.get(sectname, "handlers") @@ -237,7 +237,7 @@ existing.remove(qn) if "level" in opts: level = cp.get(sectname, "level") - logger.setLevel(logging._levelNames[level]) + logger.setLevel(level) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate diff --git a/lib-python/2.7/test/test_logging.py b/lib-python/2.7/test/test_logging.py --- a/lib-python/2.7/test/test_logging.py +++ b/lib-python/2.7/test/test_logging.py @@ -65,7 +65,8 @@ self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] self.saved_loggers = logger_dict.copy() - self.saved_level_names = logging._levelNames.copy() + self.saved_name_to_level = logging._nameToLevel.copy() + self.saved_level_to_name = logging._levelToName.copy() finally: logging._releaseLock() @@ -97,8 +98,10 @@ self.root_logger.setLevel(self.original_logging_level) logging._acquireLock() try: - logging._levelNames.clear() - logging._levelNames.update(self.saved_level_names) + logging._levelToName.clear() + logging._levelToName.update(self.saved_level_to_name) + logging._nameToLevel.clear() + logging._nameToLevel.update(self.saved_name_to_level) logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list From noreply at buildbot.pypy.org Mon May 27 18:12:49 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 27 May 2013 18:12:49 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged deafult in Message-ID: <20130527161250.003321C0189@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64583:8fe4e98979ce Date: 2013-05-27 12:10 -0400 http://bitbucket.org/pypy/pypy/changeset/8fe4e98979ce/ Log: merged deafult in diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -166,8 +166,7 @@ if self is StructOrUnion: return if '_fields_' not in self.__dict__: - self._fields_ = [] - _set_shape(self, [], self._is_union) + self._fields_ = [] # As a side-effet, this also sets the ffishape. __setattr__ = struct_setattr diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -16,6 +16,11 @@ else: return space.int_w(w_size) +def unsupported(space, message): + w_exc = space.getattr(space.getbuiltinmodule('_io'), + space.wrap('UnsupportedOperation')) + return OperationError(w_exc, space.wrap(message)) + # May be called with any object def check_readable_w(space, w_obj): if not space.is_true(space.call_method(w_obj, 'readable')): @@ -86,6 +91,9 @@ # attribute as returned by whatever subclass. return self.__IOBase_closed + def _unsupportedoperation(self, space, message): + raise unsupported(space, message) + def _check_closed(self, space, message=None): if message is None: message = "I/O operation on closed file" @@ -111,9 +119,18 @@ space.w_ValueError, space.wrap("I/O operation on closed file")) + def seek_w(self, space, w_offset, w_whence=None): + self._unsupportedoperation(space, "seek") + def tell_w(self, space): return space.call_method(self, "seek", space.wrap(0), space.wrap(1)) + def truncate_w(self, space, w_size=None): + self._unsupportedoperation(space, "truncate") + + def fileno_w(self, space): + self._unsupportedoperation(space, "fileno") + def enter_w(self, space): self._check_closed(space) return space.wrap(self) @@ -248,11 +265,15 @@ next = interp2app(W_IOBase.next_w), close = interp2app(W_IOBase.close_w), flush = interp2app(W_IOBase.flush_w), + seek = interp2app(W_IOBase.seek_w), tell = interp2app(W_IOBase.tell_w), + truncate = interp2app(W_IOBase.truncate_w), + fileno = interp2app(W_IOBase.fileno_w), isatty = interp2app(W_IOBase.isatty_w), readable = interp2app(W_IOBase.readable_w), writable = interp2app(W_IOBase.writable_w), seekable = interp2app(W_IOBase.seekable_w), + _checkReadable = interp2app(check_readable_w), _checkWritable = interp2app(check_writable_w), _checkSeekable = interp2app(check_seekable_w), diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -196,11 +196,6 @@ def __init__(self, space): W_IOBase.__init__(self, space) - def _unsupportedoperation(self, space, message): - w_exc = space.getattr(space.getbuiltinmodule('_io'), - space.wrap('UnsupportedOperation')) - raise OperationError(w_exc, space.wrap(message)) - def read_w(self, space, w_size=None): self._unsupportedoperation(space, "read") diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -43,6 +43,13 @@ import _io e = _io.UnsupportedOperation("seek") + def test_default_implementations(self): + import _io + file = _io._IOBase() + raises(_io.UnsupportedOperation, file.seek, 0, 1) + raises(_io.UnsupportedOperation, file.fileno) + raises(_io.UnsupportedOperation, file.truncate) + def test_blockingerror(self): import _io try: diff --git a/pypy/module/_io/test/test_textio.py b/pypy/module/_io/test/test_textio.py --- a/pypy/module/_io/test/test_textio.py +++ b/pypy/module/_io/test/test_textio.py @@ -26,6 +26,14 @@ assert t.readable() assert t.seekable() + def test_default_implementations(self): + import _io + file = _io._TextIOBase() + raises(_io.UnsupportedOperation, file.read) + raises(_io.UnsupportedOperation, file.seek, 0) + raises(_io.UnsupportedOperation, file.readline) + raises(_io.UnsupportedOperation, file.detach) + def test_unreadable(self): import _io class UnReadable(_io.BytesIO): diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -46,11 +46,11 @@ self.name = name class FakeSpace(object): - w_ValueError = "ValueError" - w_TypeError = "TypeError" - w_IndexError = "IndexError" - w_OverflowError = "OverflowError" - w_NotImplementedError = "NotImplementedError" + w_ValueError = W_TypeObject("ValueError") + w_TypeError = W_TypeObject("TypeError") + w_IndexError = W_TypeObject("IndexError") + w_OverflowError = W_TypeObject("OverflowError") + w_NotImplementedError = W_TypeObject("NotImplementedError") w_None = None w_bool = W_TypeObject("bool") diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -254,6 +254,8 @@ descr__new__, _get_dtype = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): + _attrs_ = ['ofs', 'dtype', 'arr'] + _immutable_fields_ = ['ofs'] def __init__(self, arr, ofs, dtype): self.arr = arr # we have to keep array alive self.ofs = ofs diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -786,7 +786,7 @@ def test_create_subarrays(self): from numpypy import dtype - d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + d = dtype([("x", "float", (2,)), ("y", "int64", (2,))]) assert d.itemsize == 32 assert d.name == "void256" keys = d.fields.keys() diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2715,7 +2715,7 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") @@ -2735,7 +2735,7 @@ def test_multidim_subarray(self): from numpypy import dtype, array - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1705,8 +1705,10 @@ def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match + from interp_dtype import W_Dtype items_w = space.fixedview(w_items) subdtype = dtype.subdtype + assert isinstance(subdtype, W_Dtype) itemtype = subdtype.itemtype if len(shape) <= 1: for i in range(len(items_w)): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -239,6 +239,9 @@ pass pos = POSITION(1, 2) assert (pos.x, pos.y) == (1, 2) + # Try a second time, result may be different (cf. issue1498) + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) def test_invalid_field_types(self): diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT, VOID from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -27,6 +27,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.arm import callbuilder class AssemblerARM(ResOpAssembler): @@ -934,23 +935,6 @@ asm_math_operations[oopspecindex](self, op, arglocs, regalloc, fcond) return fcond - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 4: - return - if size == 1: - if not signed: # unsigned char - self.mc.AND_ri(resloc.value, resloc.value, 0xFF) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 24) - self.mc.ASR_ri(resloc.value, resloc.value, 24) - elif size == 2: - if not signed: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.LSR_ri(resloc.value, resloc.value, 16) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.ASR_ri(resloc.value, resloc.value, 16) - def patch_trace(self, faildescr, looptoken, bridge_addr, regalloc): b = InstrBuilder(self.cpu.cpuinfo.arch_version) patch_addr = faildescr._arm_failure_recovery_block @@ -1012,20 +996,32 @@ mc.gen_load_int(helper.value, ofs, cond=cond) mc.STR_rr(source.value, base.value, helper.value, cond=cond) + def get_tmp_reg(self, forbidden_regs=None): + if forbidden_regs is None: + return r.ip, False + for x in [r.ip, r.lr]: + if x not in forbidden_regs: + return x, False + # pick some reg, that we need to save + for x in r.all_regs: + if x not in forbidden_regs: + return x, True + assert 0 + def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL): - if not loc.is_reg() and not (loc.is_stack() and loc.type != FLOAT): + if loc.type == FLOAT: raise AssertionError("invalid target for move from imm value") if loc.is_reg(): new_loc = loc - elif loc.is_stack(): - self.mc.PUSH([r.lr.value], cond=cond) + elif loc.is_stack() or loc.is_raw_sp(): new_loc = r.lr else: raise AssertionError("invalid target for move from imm value") self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond) if loc.is_stack(): self.regalloc_mov(new_loc, loc) - self.mc.POP([r.lr.value], cond=cond) + elif loc.is_raw_sp(): + self.store_reg(self.mc, new_loc, r.sp, loc.value, cond=cond, helper=r.ip) def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_imm(): @@ -1034,60 +1030,77 @@ self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond) elif loc.is_stack() and loc.type != FLOAT: # spill a core register - if prev_loc is r.ip: - temp = r.lr - else: - temp = r.ip + temp, save = self.get_tmp_reg([prev_loc, loc]) offset = loc.value is_imm = check_imm_arg(offset, size=0xFFF) - if not is_imm: + if not is_imm and save: self.mc.PUSH([temp.value], cond=cond) self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) - if not is_imm: + if not is_imm and save: self.mc.POP([temp.value], cond=cond) + elif loc.is_raw_sp() and loc.type != FLOAT: + temp, save = self.get_tmp_reg([prev_loc]) + assert not save + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) else: assert 0, 'unsupported case' def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL): - # disabled for now, has side effects in combination with remap_frame_layout when called from a jump - helper = None # self._regalloc.get_free_reg() + helper = None + offset = prev_loc.value + tmp = None if loc.is_reg(): assert prev_loc.type != FLOAT, 'trying to load from an \ incompatible location into a core register' - assert loc is not r.lr, 'lr is not supported as a target \ - when moving from the stack' # unspill a core register - offset = prev_loc.value is_imm = check_imm_arg(offset, size=0xFFF) - helper = r.lr if helper is None else helper - save_helper = not is_imm and helper is r.lr + helper, save = self.get_tmp_reg([loc]) + save_helper = not is_imm and save elif loc.is_vfp_reg(): assert prev_loc.type == FLOAT, 'trying to load from an \ incompatible location into a float register' # load spilled value into vfp reg - offset = prev_loc.value is_imm = check_imm_arg(offset) - helper = r.ip if helper is None else helper - save_helper = not is_imm and helper is r.ip + helper, save = self.get_tmp_reg() + save_helper = not is_imm and save + elif loc.is_raw_sp(): + assert (loc.type == prev_loc.type == FLOAT + or (loc.type != FLOAT and prev_loc.type != FLOAT)) + tmp = loc + if loc.is_float(): + loc = r.vfp_ip + else: + loc, save_helper = self.get_tmp_reg() + assert not save_helper + helper, save_helper = self.get_tmp_reg([loc]) + assert not save_helper else: assert 0, 'unsupported case' + if save_helper: self.mc.PUSH([helper.value], cond=cond) self.load_reg(self.mc, loc, r.fp, offset, cond=cond, helper=helper) if save_helper: self.mc.POP([helper.value], cond=cond) + if tmp and tmp.is_raw_sp(): + self.store_reg(self.mc, loc, r.sp, tmp.value, cond=cond, helper=helper) + def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_vfp_reg(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond) - self.load_reg(self.mc, loc, r.ip, 0, cond=cond) - self.mc.POP([r.ip.value], cond=cond) - elif loc.is_stack(): - self.regalloc_push(r.vfp_ip) + helper, save_helper = self.get_tmp_reg([loc]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, prev_loc.getint(), cond=cond) + self.load_reg(self.mc, loc, helper, 0, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) + elif loc.is_stack() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - self.regalloc_pop(r.vfp_ip) + elif loc.is_raw_sp() and loc.type == FLOAT: + self.regalloc_mov(prev_loc, r.vfp_ip, cond) + self.regalloc_mov(r.vfp_ip, loc, cond) else: assert 0, 'unsupported case' @@ -1100,11 +1113,11 @@ # spill vfp register offset = loc.value is_imm = check_imm_arg(offset) - if not is_imm: - self.mc.PUSH([r.ip.value], cond=cond) - self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond) - if not is_imm: - self.mc.POP([r.ip.value], cond=cond) + self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) + elif loc.is_raw_sp(): + assert loc.type == FLOAT, 'trying to store to an \ + incompatible location from a float register' + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' @@ -1120,6 +1133,8 @@ self._mov_imm_float_to_loc(prev_loc, loc, cond) elif prev_loc.is_vfp_reg(): self._mov_vfp_reg_to_loc(prev_loc, loc, cond) + elif prev_loc.is_raw_sp(): + assert 0, 'raw sp locs are not supported as source loc' else: assert 0, 'unsupported case' mov_loc_loc = regalloc_mov @@ -1131,23 +1146,29 @@ if vfp_loc.is_vfp_reg(): self.mc.VMOV_rc(reg1.value, reg2.value, vfp_loc.value, cond=cond) elif vfp_loc.is_imm_float(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, vfp_loc.getint(), cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, vfp_loc.getint(), cond=cond) # we need to load one word to loc and one to loc+1 which are # two 32-bit core registers - self.mc.LDR_ri(reg1.value, r.ip.value, cond=cond) - self.mc.LDR_ri(reg2.value, r.ip.value, imm=WORD, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + self.mc.LDR_ri(reg1.value, helper.value, cond=cond) + self.mc.LDR_ri(reg2.value, helper.value, imm=WORD, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif vfp_loc.is_stack() and vfp_loc.type == FLOAT: # load spilled vfp value into two core registers offset = vfp_loc.value if not check_imm_arg(offset, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.LDR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.LDR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.LDR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.LDR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.LDR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.LDR_ri(reg2.value, r.fp.value, @@ -1165,12 +1186,15 @@ # move from two core registers to a float stack location offset = vfp_loc.value if not check_imm_arg(offset + WORD, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.STR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.STR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.STR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.STR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.STR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.STR_ri(reg2.value, r.fp.value, @@ -1417,6 +1441,26 @@ # return shiftsize + def simple_call(self, fnloc, arglocs, result_loc=r.r0): + if result_loc is None: + result_type = VOID + result_size = 0 + elif result_loc.is_vfp_reg(): + result_type = FLOAT + result_size = DOUBLE_WORD + else: + result_type = INT + result_size = WORD + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() + + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs) + cb.emit_no_collect() + + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/callbuilder.py @@ -0,0 +1,304 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT, REF +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.assembler import saved_registers +from rpython.jit.backend.arm.helper.regalloc import check_imm_arg + + +class ARMCallbuilder(AbstractCallBuilder): + def __init__(self, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) + self.current_sp = 0 + + def push_gcmap(self): + assert not self.is_call_release_gil + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r0], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + self.asm.pop_gcmap(self.mc) + + def emit_raw_call(self): + #the actual call + if self.fnloc.is_imm(): + self.mc.BL(self.fnloc.value) + return + if self.fnloc.is_stack(): + self.asm.mov_loc_loc(self.fnloc, r.ip) + self.fnloc = r.ip + assert self.fnloc.is_reg() + self.mc.BLX(self.fnloc.value) + + def restore_stack_pointer(self): + # readjust the sp in case we passed some args on the stack + assert self.current_sp % 8 == 0 # sanity check + if self.current_sp != 0: + self._adjust_sp(self.current_sp) + self.current_sp = 0 + + def _push_stack_args(self, stack_args, on_stack): + assert on_stack % 8 == 0 + self._adjust_sp(-on_stack) + self.current_sp = on_stack + ofs = 0 + for i, arg in enumerate(stack_args): + if arg is not None: + sp_loc = RawSPStackLocation(ofs, arg.type) + self.asm.regalloc_mov(arg, sp_loc) + ofs += sp_loc.width + else: # alignment word + ofs += WORD + + def _adjust_sp(self, n): + # adjust the current stack pointer by n bytes + if n > 0: + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value) + else: + n = abs(n) + if check_imm_arg(n): + self.mc.SUB_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value) + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + + def call_releasegil_addr_and_move_real_arguments(self): + assert not self.asm._is_asmgcc() + from rpython.jit.backend.arm.regalloc import CoreRegisterManager + with saved_registers(self.mc, + CoreRegisterManager.save_around_call_regs): + self.mc.BL(self.asm.releasegil_addr) + + if not we_are_translated(): # for testing: we should not access + self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got + assert not self.asm._is_asmgcc() + gpr_to_save, vfp_to_save = self.get_result_locs() + with saved_registers(self.mc, gpr_to_save, vfp_to_save): + self.mc.BL(self.asm.reacqgil_addr) + + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again + + # for shadowstack, done for us by _reload_frame_if_necessary() + + def get_result_locs(self): + raise NotImplementedError + + def _ensure_result_bit_extension(self, resloc, size, signed): + if size == 4: + return + if size == 1: + if not signed: # unsigned char + self.mc.AND_ri(resloc.value, resloc.value, 0xFF) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 24) + self.mc.ASR_ri(resloc.value, resloc.value, 24) + elif size == 2: + if not signed: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.LSR_ri(resloc.value, resloc.value, 16) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.ASR_ri(resloc.value, resloc.value, 16) + + + +class SoftFloatCallBuilder(ARMCallbuilder): + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [r.r0, r.r1], [] + assert self.resloc.is_reg() + return [r.r0], [] + + def load_result(self): + # ensure the result is wellformed and stored in the correct location + resloc = self.resloc + if resloc is None: + return + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + # move result to the allocated register + if resloc is not r.r0: + self.asm.mov_loc_loc(r.r0, resloc) + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + + def _collect_and_push_stack_args(self, arglocs): + n_args = len(arglocs) + reg_args = count_reg_args(arglocs) + # all arguments past the 4th go on the stack + # first we need to prepare the list so it stays aligned + stack_args = [] + count = 0 + on_stack = 0 + if n_args > reg_args: + for i in range(reg_args, n_args): + arg = arglocs[i] + if arg.type != FLOAT: + count += 1 + on_stack += 1 + else: + on_stack += 2 + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + if count % 2 != 0: + on_stack += 1 + stack_args.append(None) + if on_stack > 0: + self._push_stack_args(stack_args, on_stack*WORD) + + def prepare_arguments(self): + arglocs = self.arglocs + reg_args = count_reg_args(arglocs) + self._collect_and_push_stack_args(arglocs) + # collect variables that need to go in registers and the registers they + # will be stored in + num = 0 + count = 0 + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(reg_args): + arg = arglocs[i] + if arg.type == FLOAT and count % 2 != 0: + num += 1 + count = 0 + reg = r.caller_resp[num] + + if arg.type == FLOAT: + float_locs.append((arg, reg)) + else: + non_float_locs.append(arg) + non_float_regs.append(reg) + + if arg.type == FLOAT: + num += 2 + else: + num += 1 + count += 1 + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in r.argument_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + + for loc, reg in float_locs: + self.asm.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) + +class HardFloatCallBuilder(ARMCallbuilder): + + def prepare_arguments(self): + non_float_locs = [] + non_float_regs = [] + float_locs = [] + float_regs = [] + stack_args = [] + + arglocs = self.arglocs + argtypes = self.argtypes + + count = 0 # stack alignment counter + on_stack = 0 + for arg in arglocs: + if arg.type != FLOAT: + if len(non_float_regs) < len(r.argument_regs): + reg = r.argument_regs[len(non_float_regs)] + non_float_locs.append(arg) + non_float_regs.append(reg) + else: # non-float argument that needs to go on the stack + count += 1 + on_stack += 1 + stack_args.append(arg) + else: + if len(float_regs) < len(r.vfp_argument_regs): + reg = r.vfp_argument_regs[len(float_regs)] + float_locs.append(arg) + float_regs.append(reg) + else: # float argument that needs to go on the stack + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + on_stack += 2 + # align the stack + if count % 2 != 0: + stack_args.append(None) + on_stack += 1 + self._push_stack_args(stack_args, on_stack*WORD) + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + # remap values stored in vfp registers + remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip) + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None and resloc.is_reg(): + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [], [r.d0] + assert self.resloc.is_reg() + return [r.r0], [] + + +def get_callbuilder(cpu, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + if cpu.cpuinfo.hf_abi: + return HardFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) + else: + return SoftFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) diff --git a/rpython/jit/backend/arm/locations.py b/rpython/jit/backend/arm/locations.py --- a/rpython/jit/backend/arm/locations.py +++ b/rpython/jit/backend/arm/locations.py @@ -12,6 +12,9 @@ def is_stack(self): return False + def is_raw_sp(self): + return False + def is_reg(self): return False @@ -145,7 +148,27 @@ return self.position + 10000 def is_float(self): - return type == FLOAT + return self.type == FLOAT + +class RawSPStackLocation(AssemblerLocation): + _immutable_ = True + + def __init__(self, sp_offset, type=INT): + if type == FLOAT: + self.width = DOUBLE_WORD + else: + self.width = WORD + self.value = sp_offset + self.type = type + + def __repr__(self): + return 'SP(%s)+%d' % (self.type, self.value,) + + def is_raw_sp(self): + return True + + def is_float(self): + return self.type == FLOAT def imm(i): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -13,8 +13,7 @@ gen_emit_float_cmp_op, gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, - saved_registers, - count_reg_args) + saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout @@ -31,8 +30,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.arm import callbuilder class ArmGuardToken(GuardToken): @@ -339,217 +337,36 @@ return fcond def emit_op_call(self, op, arglocs, regalloc, fcond): - resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + return self._emit_call(op, arglocs, fcond=fcond) + + def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): + # args = [resloc, size, sign, args...] + from rpython.jit.backend.llsupport.descr import CallDescr + + cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3], arglocs[4:], arglocs[0]) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - cond = self._emit_call(adr, arglist, - fcond, resloc, (size, signed)) - return cond + assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[1] + assert sizeloc.is_imm() + cb.ressize = sizeloc.value + signloc = arglocs[2] + assert signloc.is_imm() + cb.ressign = signloc.value - def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None, - result_info=(-1, -1), - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True): - if self.cpu.cpuinfo.hf_abi: - stack_args, adr = self._setup_call_hf(adr, arglocs, fcond, - resloc, result_info) + if is_call_release_gil: + cb.emit_call_release_gil() else: - stack_args, adr = self._setup_call_sf(adr, arglocs, fcond, - resloc, result_info) - - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - #the actual call - if adr.is_imm(): - self.mc.BL(adr.value) - elif adr.is_stack(): - self.mov_loc_loc(adr, r.ip) - adr = r.ip - else: - assert adr.is_reg() - if adr.is_reg(): - self.mc.BLX(adr.value) - self._restore_sp(stack_args, fcond) - - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg() and not self.cpu.cpuinfo.hf_abi: - # move result to the allocated register - self.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg() and result_info != (-1, -1): - self._ensure_result_bit_extension(resloc, result_info[0], - result_info[1]) - if can_collect: - self._reload_frame_if_necessary(self.mc) - self.pop_gcmap(self.mc) + cb.emit() return fcond - def _restore_sp(self, stack_args, fcond): - # readjust the sp in case we passed some args on the stack - if len(stack_args) > 0: - n = 0 - for arg in stack_args: - if arg is None or arg.type != FLOAT: - n += WORD - else: - n += DOUBLE_WORD - self._adjust_sp(-n, fcond=fcond) - assert n % 8 == 0 # sanity check - - def _adjust_sp(self, n, cb=None, fcond=c.AL, base_reg=r.sp): - if cb is None: - cb = self.mc - if n < 0: - n = -n - rev = True - else: - rev = False - if n <= 0xFF and fcond == c.AL: - if rev: - cb.ADD_ri(r.sp.value, base_reg.value, n) - else: - cb.SUB_ri(r.sp.value, base_reg.value, n) - else: - cb.gen_load_int(r.ip.value, n, cond=fcond) - if rev: - cb.ADD_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - else: - cb.SUB_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - - - def _collect_stack_args_sf(self, arglocs): - n_args = len(arglocs) - reg_args = count_reg_args(arglocs) - # all arguments past the 4th go on the stack - # first we need to prepare the list so it stays aligned - stack_args = [] - count = 0 - if n_args > reg_args: - for i in range(reg_args, n_args): - arg = arglocs[i] - if arg.type != FLOAT: - count += 1 - else: - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - if count % 2 != 0: - stack_args.append(None) - return stack_args - - def _push_stack_args(self, stack_args): - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.regalloc_push(arg) - - def _setup_call_sf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - reg_args = count_reg_args(arglocs) - stack_args = self._collect_stack_args_sf(arglocs) - self._push_stack_args(stack_args) - # collect variables that need to go in registers and the registers they - # will be stored in - num = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - for i in range(reg_args): - arg = arglocs[i] - if arg.type == FLOAT and count % 2 != 0: - num += 1 - count = 0 - reg = r.caller_resp[num] - - if arg.type == FLOAT: - float_locs.append((arg, reg)) - else: - non_float_locs.append(arg) - non_float_regs.append(reg) - - if arg.type == FLOAT: - num += 2 - else: - num += 1 - count += 1 - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - - for loc, reg in float_locs: - self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) - return stack_args, adr - - def _setup_call_hf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - count = 0 # stack alignment counter - for arg in arglocs: - if arg.type != FLOAT: - if len(non_float_regs) < len(r.argument_regs): - reg = r.argument_regs[len(non_float_regs)] - non_float_locs.append(arg) - non_float_regs.append(reg) - else: # non-float argument that needs to go on the stack - count += 1 - stack_args.append(arg) - else: - if len(float_regs) < len(r.vfp_argument_regs): - reg = r.vfp_argument_regs[len(float_regs)] - float_locs.append(arg) - float_regs.append(reg) - else: # float argument that needs to go on the stack - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - # align the stack - if count % 2 != 0: - stack_args.append(None) - self._push_stack_args(stack_args) - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - # remap values stored in vfp registers - remap_frame_layout(self, float_locs, float_regs, r.vfp_ip) - - return stack_args, adr - def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs - self.mov_loc_loc(argloc, resloc) + if argloc is not resloc: + self.mov_loc_loc(argloc, resloc) return fcond emit_op_cast_ptr_to_int = emit_op_same_as @@ -1037,9 +854,8 @@ length_loc = bytes_loc # call memcpy() regalloc.before_call() - self._emit_call(imm(self.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.simple_call_no_collect(imm(self.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.rm.possibly_free_var(length_box) regalloc.rm.possibly_free_var(dstaddr_box) regalloc.rm.possibly_free_var(srcaddr_box) @@ -1127,14 +943,14 @@ vloc = imm(0) self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op), guard_op.numargs()) + regalloc._prepare_guard(guard_op)) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self._emit_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], result_loc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self._emit_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, result_loc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') @@ -1213,20 +1029,14 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed)) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) + self._emit_call(op, callargs, fcond=fcond) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def _emit_guard_may_force(self, guard_op, arglocs, numargs): + def _emit_guard_may_force(self, guard_op, arglocs): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) @@ -1235,68 +1045,14 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): - + numargs = op.numargs() + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - # do the call - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed), - can_collect=False) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - self.pop_gcmap(self.mc) # remove the gcmap saved above - - self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) + self._emit_call(op, callargs, is_call_release_gil=True) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): - # Save caller saved registers and do the call - # NOTE: We assume that the floating point registers won't be modified. - assert gcrootmap.is_shadow_stack - with saved_registers(self.mc, regalloc.rm.save_around_call_regs): - self._emit_call(imm(self.releasegil_addr), [], - fcond, can_collect=False) - - def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): - # save the previous result into the stack temporarily, in case it is in - # a caller saved register. - # NOTE: like with call_release_gil(), we assume that we don't need to - # save vfp regs in this case. Besides the result location - regs_to_save = [] - vfp_regs_to_save = [] - if save_loc and save_loc in regalloc.rm.save_around_call_regs: - regs_to_save.append(save_loc) - regs_to_save.append(r.ip) # for alingment - elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs: - vfp_regs_to_save.append(save_loc) - assert gcrootmap.is_shadow_stack - # call the reopenstack() function (also reacquiring the GIL) - with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): - self._emit_call(imm(self.reacqgil_addr), [], fcond, - can_collect=False) - self._reload_frame_if_necessary(self.mc) - def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -34,6 +34,7 @@ from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr from rpython.rlib.rarithmetic import r_uint +from rpython.jit.backend.llsupport.descr import CallDescr # xxx hack: set a default value for TargetToken._ll_loop_code. If 0, we know @@ -555,9 +556,27 @@ return self._prepare_call(op) def _prepare_call(self, op, force_store=[], save_all_regs=False): - args = [None] * (op.numargs() + 1) + args = [None] * (op.numargs() + 3) + calldescr = op.getdescr() + assert isinstance(calldescr, CallDescr) + assert len(calldescr.arg_classes) == op.numargs() - 1 + for i in range(op.numargs()): - args[i + 1] = self.loc(op.getarg(i)) + args[i + 3] = self.loc(op.getarg(i)) + + size = calldescr.get_result_size() + sign = calldescr.is_result_signed() + if sign: + sign_loc = imm(1) + else: + sign_loc = imm(0) + args[1] = imm(size) + args[2] = sign_loc + + args[0] = self._call(op, args, force_store, save_all_regs) + return args + + def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls self.vfprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -565,11 +584,11 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(save_all_regs=save_all_regs) + self.before_call_called = True + resloc = None if op.result: resloc = self.after_call(op.result) - args[0] = resloc - self.before_call_called = True - return args + return resloc def prepare_op_call_malloc_gc(self, op, fcond): return self._prepare_call(op) @@ -1153,9 +1172,9 @@ def prepare_guard_call_assembler(self, op, guard_op, fcond): locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) - call_locs = self._prepare_call(op, save_all_regs=True) + resloc = self._call(op, locs + [tmploc], save_all_regs=True) self.possibly_free_vars(guard_op.getfailargs()) - return locs + [call_locs[0], tmploc] + return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -1,9 +1,10 @@ from rpython.rlib.objectmodel import instantiate from rpython.jit.backend.arm.assembler import AssemblerARM -from rpython.jit.backend.arm.locations import imm, ConstFloatLoc,\ - RegisterLocation, StackLocation, \ - VFPRegisterLocation, get_fp_offset -from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip +from rpython.jit.backend.arm.locations import imm, ConstFloatLoc +from rpython.jit.backend.arm.locations import RegisterLocation, StackLocation +from rpython.jit.backend.arm.locations import VFPRegisterLocation, get_fp_offset +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip, sp from rpython.jit.backend.arm.conditions import AL from rpython.jit.backend.arm.arch import WORD from rpython.jit.metainterp.history import FLOAT @@ -54,6 +55,12 @@ addr = int(value) # whatever return ConstFloatLoc(addr) +def raw_stack(i): + return RawSPStackLocation(i) + +def raw_stack_float(i): + return RawSPStackLocation(i, type=FLOAT) + class MockBuilder(object): def __init__(self): @@ -79,13 +86,13 @@ result = self.builder.instrs assert result == expected - -class TestRegallocMov(BaseMovTest): - def mov(self, a, b, expected=None): self.asm.regalloc_mov(a, b) self.validate(expected) + +class TestRegallocMov(BaseMovTest): + def test_mov_imm_to_reg(self): val = imm(123) reg = r(7) @@ -102,45 +109,37 @@ val = imm(100) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 100, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_stacklock(self): val = imm(65536) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 65536, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] - + ] self.mov(val, s, expected) def test_mov_imm_to_big_stacklock(self): val = imm(100) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 100, cond=AL), - mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 100, cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_big_stacklock(self): val = imm(65536) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 65536, cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_reg_to_reg(self): @@ -158,10 +157,10 @@ def test_mov_reg_to_big_stackloc(self): s = stack(8191) r6 = r(6) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r6.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r6, s, expected) def test_mov_stack_to_reg(self): @@ -174,10 +173,8 @@ s = stack(8191) r6 = r(6) expected = [ - mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 32940, cond=AL), - mi('LDR_rr', r6.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), + mi('gen_load_int', ip.value, 32940, cond=AL), + mi('LDR_rr', r6.value, fp.value, ip.value, cond=AL), ] self.mov(s, r6, expected) @@ -185,10 +182,9 @@ f = imm_float(3.5) reg = vfp(5) expected = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, f.value, cond=AL), mi('VLDR', 5, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(f, reg, expected) def test_mov_vfp_reg_to_vfp_reg(self): @@ -206,11 +202,11 @@ def test_mov_vfp_reg_to_large_stackloc(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_mov_stack_to_vfp_reg(self): @@ -222,11 +218,11 @@ def test_mov_big_stackloc_to_vfp_reg(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_unsopported_cases(self): @@ -265,8 +261,6 @@ py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), vfp(2))') py.test.raises(AssertionError, - 'self.asm.regalloc_mov(stack(1), lr)') - py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm(2))') py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm_float(2))') @@ -312,12 +306,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('LDR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=WORD, cond=AL), mi('LDR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(s, r1, r2, e) def test_from_imm_float(self): @@ -325,11 +318,10 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, i.value, cond=AL), mi('LDR_ri', r1.value, ip.value, cond=AL), mi('LDR_ri', r2.value, ip.value, imm=4, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(i, r1, r2, e) def test_unsupported(self): @@ -369,12 +361,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=4, cond=AL), mi('STR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r1, r2, s, e) def unsupported(self): @@ -408,10 +399,9 @@ def test_push_imm_float(self): f = imm_float(7) - e = [mi('PUSH', [ip.value], cond=AL), + e = [ mi('gen_load_int', ip.value, 7, cond=AL), mi('VLDR', vfp_ip.value, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL) ] self.push(f, e) @@ -426,10 +416,8 @@ def test_push_big_stack(self): s = stack(1025) e = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('LDR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), mi('PUSH', [ip.value], cond=AL) ] self.push(s, e) @@ -450,11 +438,9 @@ def test_push_large_stackfloat(self): sf = stack_float(100) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, sf.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VLDR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL), ] self.push(sf, e) @@ -486,10 +472,8 @@ s = stack(1200) e = [ mi('POP', [ip.value], cond=AL), - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('STR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL) ] self.pop(s, e) @@ -505,13 +489,88 @@ s = stack_float(1200) e = [ mi('VPOP', [vfp_ip.value], cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.pop(s, e) def test_unsupported(self): py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm(1))') py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm_float(1))') + +class TestRawStackLocs(BaseMovTest): + def test_unsupported(self): + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm_float(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), r(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), vfp(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(r(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), raw_stack_float(1))') + + def test_from_imm(self): + s = raw_stack(1024) + i = imm(999) + e = [ + mi('gen_load_int', lr.value, i.value, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', lr.value, sp.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_vfp_imm(self): + s = raw_stack_float(1024) + i = imm_float(999) + e = [ + mi('gen_load_int', ip.value, i.value, cond=AL), + mi('VLDR', vfp_ip.value, ip.value, cond=AL, imm=0), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_reg(self): + s = raw_stack(1024) + reg = r(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', reg.value, sp.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_reg(self): + s = raw_stack_float(1024) + reg = vfp(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', reg.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_stack(self): + s = raw_stack(1024) + reg = stack(10) + e = [mi('LDR_ri', ip.value, fp.value, imm=216, cond=AL), + mi('gen_load_int', lr.value, s.value, cond=AL), + mi('STR_rr', ip.value, sp.value, lr.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_stack(self): + s = raw_stack_float(1024) + reg = stack_float(10) + e = [mi('VLDR', vfp_ip.value, fp.value, imm=220, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) 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 @@ -372,6 +372,9 @@ self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + def _is_asmgcc(self): + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + return bool(gcrootmap) and not gcrootmap.is_shadow_stack def debug_bridge(descr_number, rawstart, codeendpos): diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/llsupport/callbuilder.py @@ -0,0 +1,92 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI + +class AbstractCallBuilder(object): + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + + def __init__(self, assembler, fnloc, arglocs, resloc, restype, ressize): + self.fnloc = fnloc + self.arglocs = arglocs + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_stack_pointer() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def call_releasegil_addr_and_move_real_arguments(self): + raise NotImplementedError + + def move_real_result_and_call_reacqgil_addr(self): + raise NotImplementedError + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + + def prepare_arguments(self): + raise NotImplementedError + + def push_gcmap(self): + raise NotImplementedError + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + raise NotImplementedError + + def emit_raw_call(self): + raise NotImplementedError + + def restore_stack_pointer(self): + raise NotImplementedError + + def load_result(self): + raise NotImplementedError diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -999,10 +999,6 @@ self.implement_guard(guard_token, checkfalsecond) return genop_cmp_guard_float - def _is_asmgcc(self): - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: result_type = FLOAT diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -8,6 +8,7 @@ r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) from rpython.jit.backend.x86.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder # darwin requires the stack to be 16 bytes aligned on calls. @@ -18,77 +19,30 @@ return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - -class AbstractCallBuilder(object): +class CallBuilderX86(AbstractCallBuilder): # max number of words we have room in esp; if we need more for # arguments, we need to decrease esp temporarily stack_max = PASS_ON_MY_FRAME - # this can be set to guide more complex calls: gives the detailed - # type of the arguments - argtypes = "" - ressign = False - - # this is the calling convention (can be FFI_STDCALL on Windows) - callconv = FFI_DEFAULT_ABI - - # is it for the main CALL of a call_release_gil? - is_call_release_gil = False - # set by save_result_value() tmpresloc = None - def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT, ressize=WORD): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) # Avoid tons of issues with a non-immediate fnloc by sticking it # as an extra argument if needed self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) - if self.fnloc_is_immediate: - self.fnloc = fnloc - self.arglocs = arglocs - else: + if not self.fnloc_is_immediate: + self.fnloc = None self.arglocs = arglocs + [fnloc] - self.asm = assembler - self.mc = assembler.mc - self.resloc = resloc - self.restype = restype - self.ressize = ressize self.current_esp = 0 # 0 or (usually) negative, counted in bytes - def emit_no_collect(self): - """Emit a call that cannot collect.""" - self.prepare_arguments() - self.emit_raw_call() - self.restore_esp() - self.load_result() - - def emit(self): - """Emit a regular call; not for CALL_RELEASE_GIL.""" - self.prepare_arguments() - self.push_gcmap() - self.emit_raw_call() - self.restore_esp() - self.pop_gcmap() - self.load_result() - - def emit_call_release_gil(self): - """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr - and reacqgil_addr.""" - self.select_call_release_gil_mode() - self.prepare_arguments() - self.push_gcmap_for_call_release_gil() - self.call_releasegil_addr_and_move_real_arguments() - self.emit_raw_call() - self.restore_esp() - self.move_real_result_and_call_reacqgil_addr() - self.pop_gcmap() - self.load_result() - def select_call_release_gil_mode(self): """Overridden in CallBuilder64""" - self.is_call_release_gil = True + AbstractCallBuilder.select_call_release_gil_mode(self) if self.asm._is_asmgcc(): from rpython.memory.gctransform import asmgcroot self.stack_max = PASS_ON_MY_FRAME - asmgcroot.JIT_USE_WORDS @@ -105,7 +59,7 @@ self.current_esp -= align * WORD self.mc.SUB_ri(esp.value, align * WORD) - def restore_esp(self, target_esp=0): + def restore_stack_pointer(self, target_esp=0): if self.current_esp != target_esp: self.mc.ADD_ri(esp.value, target_esp - self.current_esp) self.current_esp = target_esp @@ -140,17 +94,6 @@ gcmap = self.asm._regalloc.get_gcmap([eax], noregs=noregs) self.asm.push_gcmap(self.mc, gcmap, store=True) - def push_gcmap_for_call_release_gil(self): - assert self.is_call_release_gil - # we put the gcmap now into the frame before releasing the GIL, - # and pop it after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self.asm._regalloc.get_gcmap(noregs=True) - self.asm.push_gcmap(self.mc, gcmap, store=True) - def pop_gcmap(self): self.asm._reload_frame_if_necessary(self.mc) if self.change_extra_stack_depth: @@ -204,7 +147,7 @@ self.mc.ADD(ebp, imm(1)) # ebp any more # self.restore_register_arguments() - self.restore_esp(initial_esp) + self.restore_stack_pointer(initial_esp) def save_register_arguments(self): """Overridden in CallBuilder64""" @@ -248,7 +191,7 @@ raise NotImplementedError -class CallBuilder32(AbstractCallBuilder): +class CallBuilder32(CallBuilderX86): def prepare_arguments(self): arglocs = self.arglocs @@ -318,7 +261,7 @@ else: self.mc.MOV(resloc, self.tmpresloc) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP+4]. We use "+4" @@ -343,7 +286,7 @@ self.mc.MOV_sr(4, eax.value) -class CallBuilder64(AbstractCallBuilder): +class CallBuilder64(CallBuilderX86): ARGUMENTS_GPR = [edi, esi, edx, ecx, r8, r9] ARGUMENTS_XMM = [xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7] @@ -389,7 +332,7 @@ i += 1 def select_call_release_gil_mode(self): - AbstractCallBuilder.select_call_release_gil_mode(self) + CallBuilderX86.select_call_release_gil_mode(self) # We have to copy the arguments around a bit more in this mode, # but on the other hand we don't need prepare_arguments() moving # them in precisely the final registers. Here we look around for @@ -502,7 +445,7 @@ # from the lower 32 bits of XMM0 self.mc.MOVD(self.resloc, xmm0) else: - AbstractCallBuilder.load_result(self) + CallBuilderX86.load_result(self) def save_result_value(self): # Temporarily save the result value into [ESP]. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -189,7 +189,7 @@ carry = ival >> SHIFT if carry: return rbigint([_store_digit(ival & MASK), - _store_digit(carry & MASK)], sign, 2) + _store_digit(carry)], sign, 2) else: return rbigint([_store_digit(ival & MASK)], sign, 1) @@ -566,7 +566,7 @@ res = b.widedigit(0) * a.widedigit(0) carry = res >> SHIFT if carry: - return rbigint([_store_digit(res & MASK), _store_digit(carry & MASK)], a.sign * b.sign, 2) + return rbigint([_store_digit(res & MASK), _store_digit(carry)], a.sign * b.sign, 2) else: return rbigint([_store_digit(res & MASK)], a.sign * b.sign, 1) From noreply at buildbot.pypy.org Mon May 27 18:12:52 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Mon, 27 May 2013 18:12:52 +0200 (CEST) Subject: [pypy-commit] pypy default: Don't construct a long object just to throw it away (this is a backpor tof a change in python3) Message-ID: <20130527161252.B71AA1C1464@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64585:1d88edfd578c Date: 2013-05-22 17:01 -0700 http://bitbucket.org/pypy/pypy/changeset/1d88edfd578c/ Log: Don't construct a long object just to throw it away (this is a backpor tof a change in python3) diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py --- a/lib-python/2.7/logging/__init__.py +++ b/lib-python/2.7/logging/__init__.py @@ -279,7 +279,7 @@ self.lineno = lineno self.funcName = func self.created = ct - self.msecs = (ct - long(ct)) * 1000 + self.msecs = (ct - int(ct)) * 1000 self.relativeCreated = (self.created - _startTime) * 1000 if logThreads and thread: self.thread = thread.get_ident() From noreply at buildbot.pypy.org Mon May 27 18:59:30 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 18:59:30 +0200 (CEST) Subject: [pypy-commit] stmgc default: Phew. Found a bug, fixed it by preventing collapse of h_revision Message-ID: <20130527165930.714CF1C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r45:bcc91b3b1338 Date: 2013-05-27 18:59 +0200 http://bitbucket.org/pypy/stmgc/changeset/bcc91b3b1338/ Log: Phew. Found a bug, fixed it by preventing collapse of h_revision chains from a GCFLAG_STOLEN object. diff --git a/c3/Makefile b/c3/Makefile --- a/c3/Makefile +++ b/c3/Makefile @@ -28,7 +28,7 @@ H_FILES = et.h lists.h nursery.h gcpage.h stmsync.h dbgmem.h fprintcolor.h stmgc.h atomic_ops.h stmimpl.h C_FILES = et.c lists.c nursery.c gcpage.c stmsync.c dbgmem.c fprintcolor.c -DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=2 +DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 build-%: %.c ${H_FILES} ${C_FILES} diff --git a/c3/demo1.c b/c3/demo1.c --- a/c3/demo1.c +++ b/c3/demo1.c @@ -8,9 +8,10 @@ #include "stmgc.h" +#include "fprintcolor.h" -#define UPPER_BOUND 10 +#define UPPER_BOUND 100 #define NUMTHREADS 4 @@ -45,7 +46,7 @@ struct node *do_a_check(int seen[], int stress_gc) { int i; - for (i=0; inext); long v = r_n->value; - assert(0 <= v && v < UPPER_BOUND); - if (v == 0) - assert(seen[v] < NUMTHREADS); - else - assert(seen[v] < seen[v-1]); - seen[v]++; + fprintf(stderr, "\t\t\t\t{ %ld, %p }\n", v, r_n->next); + assert(0 <= v && v < UPPER_BOUND * NUMTHREADS); + int tn = v / UPPER_BOUND; + assert(seen[tn] == v % UPPER_BOUND); + seen[tn]++; } return r_n; } int insert1(gcptr arg1, int retry_counter) { - int seen[UPPER_BOUND]; + int seen[NUMTHREADS]; long nvalue; struct node *r_arg; @@ -92,10 +92,13 @@ GCTID_STRUCT_NODE); last = (struct node *)stm_pop_root(); + assert(seen[nvalue / UPPER_BOUND] == nvalue % UPPER_BOUND); w_newnode->value = nvalue; w_newnode->next = NULL; + fprintf(stderr, "DEMO1: %p->value = %ld\n", w_newnode, nvalue); struct node *w_last = (struct node *)stm_write_barrier((gcptr)last); + fprintf(stderr, "DEMO1: %p->next = %p\n", w_last, w_newnode); w_last->next = w_newnode; return 0; /* return from stm_perform_transaction() */ @@ -105,18 +108,24 @@ extern void stmgcpage_possibly_major_collect(int force); /* temp */ +static int thr_mynum = 0; + void *demo1(void *arg) { - int i, status; + int i, status, start; struct node *w_node; stm_initialize(); + start = thr_mynum++; /* protected by being inevitable here */ + start *= UPPER_BOUND; + fprintf(stderr, "THREAD STARTING: start = %d\n", start); + w_node = (struct node *)stm_allocate(sizeof(struct node), GCTID_STRUCT_NODE); for (i=0; ivalue = i; + w_node->value = start + i; stm_push_root((gcptr)w_node); stm_perform_transaction((gcptr)w_node, insert1); stmgcpage_possibly_major_collect(0); /* temp */ @@ -131,11 +140,15 @@ void final_check(void) { - int seen[UPPER_BOUND]; + int i; + int seen[NUMTHREADS]; stm_initialize(); do_a_check(seen, 0); - assert(seen[UPPER_BOUND-1] == NUMTHREADS); + + for (i=0; ih_revision); if (!(v & 1)) // "is a pointer", i.e. { // "has a more recent revision" @@ -103,15 +103,23 @@ /* we update R_prev->h_revision as a shortcut */ /* XXX check if this really gives a worse performance than only doing this write occasionally based on a counter in d */ - R = (gcptr)v; - if (R->h_revision == stm_local_revision) + gcptr R_next = (gcptr)v; + if (R_next->h_revision == stm_local_revision) { /* must not update an older h_revision to go directly to the private copy at the end of a chain of protected objects! */ - return R; + return R_next; + } + if (R_prev->h_tid & GCFLAG_STOLEN) + { + /* must not update the h_revision of a stolen object! */ + R_prev = R; + R = R_next; + goto retry_threelevels; } R_prev->h_revision = v; + R = R_next; goto retry; } } @@ -505,7 +513,14 @@ gcptrlist_clear(&d->list_of_read_objects); stmgc_abort_transaction(d); - fprintf(stderr, "[%lx] abort %d\n", (long)d->my_lock, num); + fprintf(stderr, + "\n" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + "!!!!!!!!!!!!!!!!!!!!! [%lx] abort %d\n" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" + "\n", (long)d->my_lock, num); if (num != ABRT_MANUAL && d->max_aborts >= 0 && !d->max_aborts--) { fprintf(stderr, "unexpected abort!\n"); diff --git a/c3/nursery.c b/c3/nursery.c --- a/c3/nursery.c +++ b/c3/nursery.c @@ -1116,7 +1116,7 @@ g2l_insert(&d->public_to_private, N, L); gcptrlist_insert(&d->public_to_young, N); } - recdump1("STOLEN", R); + recdump1("WAS STOLEN", R); /* then all items from i+2 up to the first NULL are new stubs that must be added to d->public_to_young, in the first part From noreply at buildbot.pypy.org Mon May 27 19:03:37 2013 From: noreply at buildbot.pypy.org (bivab) Date: Mon, 27 May 2013 19:03:37 +0200 (CEST) Subject: [pypy-commit] pypy default: same_as doesn't generate a mov in this case anymore Message-ID: <20130527170337.A7CFA1C0189@cobra.cs.uni-duesseldorf.de> Author: David Schneider Branch: Changeset: r64586:33e0d8d007a9 Date: 2013-05-27 11:59 -0500 http://bitbucket.org/pypy/pypy/changeset/33e0d8d007a9/ Log: same_as doesn't generate a mov in this case anymore diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -24,7 +24,7 @@ # for the individual tests see # ====> ../../test/runner_test.py - add_loop_instructions = ['ldr', 'mov', 'adds', 'cmp', 'beq', 'b'] + add_loop_instructions = ['ldr', 'adds', 'cmp', 'beq', 'b'] bridge_loop_instructions = ['ldr', 'mov', 'nop', 'cmp', 'bge', 'push', 'mov', 'mov', 'push', 'mov', 'mov', 'blx', 'mov', 'mov', 'bx'] From noreply at buildbot.pypy.org Mon May 27 19:20:18 2013 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 27 May 2013 19:20:18 +0200 (CEST) Subject: [pypy-commit] stmgc default: Bug fix Message-ID: <20130527172018.37D261C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r46:232756021e7d Date: 2013-05-27 19:20 +0200 http://bitbucket.org/pypy/stmgc/changeset/232756021e7d/ Log: Bug fix diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -209,6 +209,10 @@ gcptr _stm_nonrecord_barrier(gcptr obj, int *result) { /* warning, this is for tests only, and it is not thread-safe! */ + struct tx_descriptor *d = thread_descriptor; + if (gcptrlist_size(&d->stolen_objects) > 0) + stmgc_normalize_stolen_objects(); + enum protection_class_t e = stmgc_classify(obj); if (e == K_PRIVATE) { @@ -228,7 +232,6 @@ return obj; } - struct tx_descriptor *d = thread_descriptor; wlog_t *item; G2L_LOOP_FORWARD(d->public_to_private, item) { From noreply at buildbot.pypy.org Mon May 27 20:17:52 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Mon, 27 May 2013 20:17:52 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Implement pickling for boxes Message-ID: <20130527181752.65E2E1C13EB@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64587:ee6ad678d7a1 Date: 2013-05-27 20:17 +0200 http://bitbucket.org/pypy/pypy/changeset/ee6ad678d7a1/ Log: Implement pickling for boxes diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -13,7 +13,7 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', '_reconstruct' : 'interp_numarray._reconstruct', - 'scalar' : 'interp_numarray.scalar', + 'scalar' : 'interp_numarray.build_scalar', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -11,6 +11,7 @@ from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from rpython.rlib.objectmodel import specialize from pypy.interpreter.mixedmodule import MixedModule MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else () @@ -50,13 +51,24 @@ return '%s(%s)' % (self.__class__.__name__, self.value) def descr_reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + numpypy = space.getbuiltinmodule("_numpypy") assert isinstance(numpypy, MixedModule) multiarray = numpypy.get("multiarray") assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") - return space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space))])]) + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, "raw") + value[0] = self.value + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.value))) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, "raw") + return ret class ComplexBox(object): _mixin_ = True @@ -75,13 +87,25 @@ return dtype.box(self.imag) def descr_reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + numpypy = space.getbuiltinmodule("_numpypy") assert isinstance(numpypy, MixedModule) multiarray = numpypy.get("multiarray") assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") - return space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space))])]) + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, "raw") + value[0] = self.real + value[1] = self.imag + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.real)) * 2) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, "raw") + return ret class W_GenericBox(W_Root): _attrs_ = () diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,8 +1051,15 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) -def scalar(space, w_dtype): - pass +def build_scalar(space, w_dtype, w_state): + from rpython.rtyper.lltypesystem import rffi, lltype + + assert isinstance(w_dtype, interp_dtype.W_Dtype) + + state = rffi.str2charp(space.str_w(w_state)) + box = w_dtype.itemtype.box_raw_data(state) + lltype.free(state, "raw") + return box W_FlatIterator.typedef = TypeDef( 'flatiter', diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py --- a/pypy/module/micronumpy/test/test_scalar.py +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -4,7 +4,7 @@ spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) def test_pickle(self): - from numpypy import dtype, int32, float64, complex128 + from numpypy import dtype, int32, float64, complex128, zeros, sum from numpypy.core.multiarray import scalar from cPickle import loads, dumps i = int32(1337) @@ -18,3 +18,6 @@ assert loads(dumps(i)) == i assert loads(dumps(f)) == f assert loads(dumps(c)) == c + + a = zeros(3) + assert loads(dumps(sum(a))) == sum(a) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -145,6 +145,11 @@ #XXX this is the place to display a warning return self.box(real) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box(array[0]) + @specialize.argtype(1) def unbox(self, box): assert isinstance(box, self.BoxType) @@ -1108,6 +1113,11 @@ rffi.cast(self.T, real), rffi.cast(self.T, imag)) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box_complex(array[0], array[1]) + def unbox(self, box): assert isinstance(box, self.BoxType) # do this in two stages since real, imag are read only From noreply at buildbot.pypy.org Mon May 27 20:54:12 2013 From: noreply at buildbot.pypy.org (mattip) Date: Mon, 27 May 2013 20:54:12 +0200 (CEST) Subject: [pypy-commit] pypy win32-fixes3: back out changeset b4eed482703d Message-ID: <20130527185412.C30A51C13EB@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: win32-fixes3 Changeset: r64588:34ac4baf64a6 Date: 2013-05-27 21:42 +0300 http://bitbucket.org/pypy/pypy/changeset/34ac4baf64a6/ Log: back out changeset b4eed482703d diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -64,15 +64,14 @@ self.args = args class CallDescr(AbstractDescr): - def __init__(self, RESULT, ARGS, extrainfo, abi): + def __init__(self, RESULT, ARGS, extrainfo): self.RESULT = RESULT self.ARGS = ARGS self.extrainfo = extrainfo - self.abi = abi def __repr__(self): - return 'CallDescr(%r, %r, %r %r)' % (self.RESULT, self.ARGS, - self.extrainfo, self.abi) + return 'CallDescr(%r, %r, %r)' % (self.RESULT, self.ARGS, + self.extrainfo) def get_extra_info(self): return self.extrainfo @@ -291,14 +290,13 @@ # ------------------------------------------------------------ def calldescrof(self, FUNC, ARGS, RESULT, effect_info): - abi = 0 key = ('call', getkind(RESULT), tuple([getkind(A) for A in ARGS]), - effect_info, abi) + effect_info) try: return self.descrs[key] except KeyError: - descr = CallDescr(RESULT, ARGS, effect_info, abi) + descr = CallDescr(RESULT, ARGS, effect_info) self.descrs[key] = descr return descr @@ -364,7 +362,7 @@ try: return self.descrs[key] except KeyError: - descr = CallDescr(RESULT, ARGS, extrainfo, cif_description.abi) + descr = CallDescr(RESULT, ARGS, extrainfo) self.descrs[key] = descr return descr @@ -867,7 +865,7 @@ # graph, not to directly execute the python function result = self.cpu.maybe_on_top_of_llinterp(func, call_args, descr.RESULT) else: - FUNC = lltype.FuncType(descr.ARGS, descr.RESULT, descr.abi) + FUNC = lltype.FuncType(descr.ARGS, descr.RESULT) func_to_call = rffi.cast(lltype.Ptr(FUNC), func) result = func_to_call(*call_args) del self.force_guard_op diff --git a/rpython/rlib/clibffi.py b/rpython/rlib/clibffi.py --- a/rpython/rlib/clibffi.py +++ b/rpython/rlib/clibffi.py @@ -503,7 +503,6 @@ def __init__(self, name, argtypes, restype, flags=FUNCFLAG_CDECL): self.name = name - print 'AbstractFuncPtr of',name,'flags',flags,'FUNCFLAG_CDECL',FUNCFLAG_CDECL self.argtypes = argtypes self.restype = restype self.flags = flags diff --git a/rpython/rtyper/lltypesystem/ll2ctypes.py b/rpython/rtyper/lltypesystem/ll2ctypes.py --- a/rpython/rtyper/lltypesystem/ll2ctypes.py +++ b/rpython/rtyper/lltypesystem/ll2ctypes.py @@ -362,16 +362,12 @@ restype = None else: restype = get_ctypes_type(T.TO.RESULT) - if T.TO.CALL_CONV == ctypes._FUNCFLAG_STDCALL: - rettype = ctypes.WINFUNCTYPE - else: - rettype = ctypes.CFUNCTYPE try: kwds = {'use_errno': True} - return rettype(restype, *argtypes, **kwds) + return ctypes.CFUNCTYPE(restype, *argtypes, **kwds) except TypeError: # unexpected 'use_errno' argument, old ctypes version - return rettype(restype, *argtypes) + return ctypes.CFUNCTYPE(restype, *argtypes) elif isinstance(T.TO, lltype.OpaqueType): return ctypes.c_void_p else: diff --git a/rpython/rtyper/lltypesystem/lltype.py b/rpython/rtyper/lltypesystem/lltype.py --- a/rpython/rtyper/lltypesystem/lltype.py +++ b/rpython/rtyper/lltypesystem/lltype.py @@ -540,7 +540,7 @@ class FuncType(ContainerType): _gckind = 'raw' __name__ = 'func' - def __init__(self, args, result, call_conv=0): + def __init__(self, args, result): for arg in args: assert isinstance(arg, LowLevelType) # There are external C functions eating raw structures, not @@ -550,7 +550,6 @@ if isinstance(result, ContainerType): raise TypeError, "function result can only be primitive or pointer" self.RESULT = result - self.CALL_CONV = call_conv def __str__(self): args = ', '.join(map(str, self.ARGS)) From noreply at buildbot.pypy.org Mon May 27 20:54:18 2013 From: noreply at buildbot.pypy.org (mattip) Date: Mon, 27 May 2013 20:54:18 +0200 (CEST) Subject: [pypy-commit] pypy win32-fixes3: merge default into branch Message-ID: <20130527185418.E887A1C13EB@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: win32-fixes3 Changeset: r64589:46d9c5a52217 Date: 2013-05-27 21:43 +0300 http://bitbucket.org/pypy/pypy/changeset/46d9c5a52217/ Log: merge default into branch diff too long, truncating to 2000 out of 22795 lines diff --git a/lib-python/2.7/distutils/command/install.py b/lib-python/2.7/distutils/command/install.py --- a/lib-python/2.7/distutils/command/install.py +++ b/lib-python/2.7/distutils/command/install.py @@ -474,8 +474,8 @@ def select_scheme (self, name): # it's the caller's problem if they supply a bad name! - if hasattr(sys, 'pypy_version_info') and not ( - name.endswith('_user') or name.endswith('_home')): + if (hasattr(sys, 'pypy_version_info') and + not name.endswith(('_user', '_home'))): name = 'pypy' scheme = INSTALL_SCHEMES[name] for key in SCHEME_KEYS: diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py --- a/lib-python/2.7/distutils/sysconfig.py +++ b/lib-python/2.7/distutils/sysconfig.py @@ -1,30 +1,16 @@ -"""Provide access to Python's configuration information. The specific -configuration variables available depend heavily on the platform and -configuration. The values may be retrieved using -get_config_var(name), and the list of variables is available via -get_config_vars().keys(). Additional convenience functions are also -available. - -Written by: Fred L. Drake, Jr. -Email: -""" - -__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" - -import sys - # The content of this file is redirected from # sysconfig_cpython or sysconfig_pypy. +# All underscore names are imported too, because +# people like to use undocumented sysconfig._xxx +# directly. +import sys if '__pypy__' in sys.builtin_module_names: - from distutils.sysconfig_pypy import * - from distutils.sysconfig_pypy import _config_vars # needed by setuptools - from distutils.sysconfig_pypy import _variable_rx # read_setup_file() + from distutils import sysconfig_pypy as _sysconfig_module else: - from distutils.sysconfig_cpython import * - from distutils.sysconfig_cpython import _config_vars # needed by setuptools - from distutils.sysconfig_cpython import _variable_rx # read_setup_file() + from distutils import sysconfig_cpython as _sysconfig_module +globals().update(_sysconfig_module.__dict__) _USE_CLANG = None diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py --- a/lib-python/2.7/distutils/sysconfig_cpython.py +++ b/lib-python/2.7/distutils/sysconfig_cpython.py @@ -9,7 +9,7 @@ Email: """ -__revision__ = "$Id$" +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" import os import re 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 @@ -1,6 +1,15 @@ -"""PyPy's minimal configuration information. +"""Provide access to Python's configuration information. +This is actually PyPy's minimal configuration information. + +The specific configuration variables available depend heavily on the +platform and configuration. The values may be retrieved using +get_config_var(name), and the list of variables is available via +get_config_vars().keys(). Additional convenience functions are also +available. """ +__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $" + import sys import os import imp @@ -119,13 +128,13 @@ optional C speedup components. """ if compiler.compiler_type == "unix": - compiler.compiler_so.extend(['-fPIC', '-Wimplicit']) + compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit']) compiler.shared_lib_extension = get_config_var('SO') if "CFLAGS" in os.environ: - cflags = os.environ["CFLAGS"] - compiler.compiler.append(cflags) - compiler.compiler_so.append(cflags) - compiler.linker_so.append(cflags) + cflags = os.environ["CFLAGS"].split() + compiler.compiler.extend(cflags) + compiler.compiler_so.extend(cflags) + compiler.linker_so.extend(cflags) from sysconfig_cpython import ( diff --git a/lib-python/2.7/pydoc.py b/lib-python/2.7/pydoc.py --- a/lib-python/2.7/pydoc.py +++ b/lib-python/2.7/pydoc.py @@ -1953,7 +1953,11 @@ if key is None: callback(None, modname, '') else: - desc = split(__import__(modname).__doc__ or '', '\n')[0] + try: + module_doc = __import__(modname).__doc__ + except ImportError: + module_doc = None + desc = split(module_doc or '', '\n')[0] if find(lower(modname + ' - ' + desc), key) >= 0: callback(None, modname, desc) diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -324,7 +324,12 @@ if self._close: self._sock.close() else: - self._sock._decref_socketios() + try: + self._sock._decref_socketios() + except AttributeError: + pass # bah, someone built a _fileobject manually + # with some unexpected replacement of the + # _socketobject class self._sock = None def __del__(self): diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py --- a/lib-python/2.7/test/test_codecs.py +++ b/lib-python/2.7/test/test_codecs.py @@ -2,7 +2,11 @@ import unittest import codecs import locale -import sys, StringIO, _testcapi +import sys, StringIO +try: + import _testcapi +except ImportError: + _testcapi = None class Queue(object): """ @@ -1387,7 +1391,7 @@ decodedresult += reader.read() self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding)) - if encoding not in broken_incremental_coders: + if encoding not in broken_incremental_coders and _testcapi: # check incremental decoder/encoder (fetched via the Python # and C API) and iterencode()/iterdecode() try: diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py --- a/lib-python/2.7/test/test_sysconfig.py +++ b/lib-python/2.7/test/test_sysconfig.py @@ -7,7 +7,8 @@ import subprocess from copy import copy, deepcopy -from test.test_support import run_unittest, TESTFN, unlink, get_attribute +from test.test_support import (run_unittest, TESTFN, unlink, get_attribute, + import_module) import sysconfig from sysconfig import (get_paths, get_platform, get_config_vars, @@ -236,7 +237,10 @@ def test_get_config_h_filename(self): config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) + # import_module skips the test when the CPython C Extension API + # appears to not be supported + self.assertTrue(os.path.isfile(config_h) or + not import_module('_testcapi'), config_h) def test_get_scheme_names(self): wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py --- a/lib-python/2.7/test/test_traceback.py +++ b/lib-python/2.7/test/test_traceback.py @@ -1,6 +1,9 @@ """Test cases for traceback module""" -from _testcapi import traceback_print +try: + from _testcapi import traceback_print +except ImportError: + traceback_print = None from StringIO import StringIO import sys import unittest @@ -176,6 +179,8 @@ class TracebackFormatTests(unittest.TestCase): def test_traceback_format(self): + if traceback_print is None: + raise unittest.SkipTest('Requires _testcapi') try: raise KeyError('blah') except KeyError: diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py --- a/lib-python/2.7/test/test_unicode.py +++ b/lib-python/2.7/test/test_unicode.py @@ -1609,7 +1609,10 @@ self.assertEqual("{}".format(u), '__unicode__ overridden') def test_encode_decimal(self): - from _testcapi import unicode_encodedecimal + try: + from _testcapi import unicode_encodedecimal + except ImportError: + raise unittest.SkipTest('Requires _testcapi') self.assertEqual(unicode_encodedecimal(u'123'), b'123') self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'), diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -130,7 +130,7 @@ RegrTest('test_bz2.py', usemodules='bz2'), RegrTest('test_calendar.py'), RegrTest('test_call.py', core=True), - RegrTest('test_capi.py'), + RegrTest('test_capi.py', usemodules='cpyext'), RegrTest('test_cd.py'), RegrTest('test_cfgparser.py'), RegrTest('test_cgi.py'), @@ -177,7 +177,7 @@ RegrTest('test_cprofile.py'), RegrTest('test_crypt.py', usemodules='crypt'), RegrTest('test_csv.py', usemodules='_csv'), - RegrTest('test_ctypes.py', usemodules="_rawffi thread"), + RegrTest('test_ctypes.py', usemodules="_rawffi thread cpyext"), RegrTest('test_curses.py'), RegrTest('test_datetime.py', usemodules='binascii struct'), RegrTest('test_dbm.py'), diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -166,9 +166,7 @@ if self is StructOrUnion: return if '_fields_' not in self.__dict__: - self._fields_ = [] - self._names = [] - _set_shape(self, [], self._is_union) + self._fields_ = [] # As a side-effet, this also sets the ffishape. __setattr__ = struct_setattr diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py --- a/lib_pypy/_testcapi.py +++ b/lib_pypy/_testcapi.py @@ -54,4 +54,9 @@ fp, filename, description = imp.find_module('_testcapi', path=[output_dir]) imp.load_module('_testcapi', fp, filename, description) -compile_shared() +try: + import cpyext +except ImportError: + raise ImportError("No module named '_testcapi'") +else: + compile_shared() 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,5 +4,5 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "0.6" -__version_info__ = (0, 6) +__version__ = "0.7" +__version_info__ = (0, 7) 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 @@ -73,15 +73,15 @@ if name.startswith('RTLD_'): setattr(self, name, getattr(backend, name)) # - BVoidP = self._get_cached_btype(model.voidp_type) + self.BVoidP = self._get_cached_btype(model.voidp_type) if isinstance(backend, types.ModuleType): # _cffi_backend: attach these constants to the class if not hasattr(FFI, 'NULL'): - FFI.NULL = self.cast(BVoidP, 0) + FFI.NULL = self.cast(self.BVoidP, 0) FFI.CData, FFI.CType = backend._get_types() else: # ctypes backend: attach these constants to the instance - self.NULL = self.cast(BVoidP, 0) + self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() def cdef(self, csource, override=False): @@ -346,6 +346,12 @@ self._cdefsources.extend(ffi_to_include._cdefsources) self._cdefsources.append(']') + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + def _make_ffi_library(ffi, libname, flags): import os @@ -370,7 +376,10 @@ if key in ffi._parser._declarations: tp = ffi._parser._declarations[key] BType = ffi._get_cached_btype(tp) - value = backendlib.load_function(BType, name) + try: + value = backendlib.load_function(BType, name) + except KeyError as e: + raise AttributeError('%s: %s' % (name, e)) library.__dict__[name] = value return # diff --git a/lib_pypy/cffi/backend_ctypes.py b/lib_pypy/cffi/backend_ctypes.py --- a/lib_pypy/cffi/backend_ctypes.py +++ b/lib_pypy/cffi/backend_ctypes.py @@ -16,6 +16,7 @@ class CTypesData(object): __metaclass__ = CTypesType __slots__ = ['__weakref__'] + __name__ = '' def __init__(self, *args): raise TypeError("cannot instantiate %r" % (self.__class__,)) @@ -491,6 +492,8 @@ elif BItem in (getbtype(model.PrimitiveType('signed char')), getbtype(model.PrimitiveType('unsigned char'))): kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' else: kind = 'generic' # @@ -546,13 +549,13 @@ def __setitem__(self, index, value): self._as_ctype_ptr[index] = BItem._to_ctypes(value) - if kind == 'charp': + if kind == 'charp' or kind == 'voidp': @classmethod - def _arg_to_ctypes(cls, value): - if isinstance(value, bytes): - return ctypes.c_char_p(value) + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) else: - return super(CTypesPtr, cls)._arg_to_ctypes(value) + return super(CTypesPtr, cls)._arg_to_ctypes(*value) if kind == 'charp' or kind == 'bytep': def _to_string(self, maxlen): diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -15,6 +15,20 @@ def patch_extension_kwds(self, kwds): pass + def find_module(self, module_name, path, so_suffix): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] != so_suffix: + return None + return filename + def collect_types(self): self._typesdict = {} self._generate("collecttype") @@ -427,9 +441,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -1,4 +1,4 @@ -import sys +import sys, os import types from . import model, ffiplatform @@ -20,6 +20,16 @@ # up in kwds['export_symbols']. kwds.setdefault('export_symbols', self.export_symbols) + def find_module(self, module_name, path, so_suffix): + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + return None + def collect_types(self): pass # not needed in the generic engine @@ -216,9 +226,9 @@ prnt('static void %s(%s *p)' % (checkfuncname, cname)) prnt('{') prnt(' /* only to generate compile-time warnings or errors */') - for fname, ftype, _ in tp.enumfields(): + for fname, ftype, fbitsize in tp.enumfields(): if (isinstance(ftype, model.PrimitiveType) - and ftype.is_integer_type()): + and ftype.is_integer_type()) or fbitsize >= 0: # accept all integers, but complain on float or double prnt(' (void)((p->%s) << 1);' % fname) else: diff --git a/lib_pypy/cffi/verifier.py b/lib_pypy/cffi/verifier.py --- a/lib_pypy/cffi/verifier.py +++ b/lib_pypy/cffi/verifier.py @@ -102,21 +102,10 @@ path = pkg.__path__ else: path = None - try: - f, filename, descr = imp.find_module(self.get_module_name(), - path) - except ImportError: + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffix()) + if filename is None: return - if f is not None: - f.close() - if filename.lower().endswith('.py'): - # on PyPy, if there are both .py and .pypy-19.so files in - # the same directory, the .py file is returned. That's the - # case after a setuptools installation. We never want to - # load the .py file here... - filename = filename[:-3] + _get_so_suffix() - if not os.path.isfile(filename): - return self.modulefilename = filename self._vengine.collect_types() self._has_module = True diff --git a/lib_pypy/ctypes_config_cache/dumpcache.py b/lib_pypy/ctypes_config_cache/dumpcache.py --- a/lib_pypy/ctypes_config_cache/dumpcache.py +++ b/lib_pypy/ctypes_config_cache/dumpcache.py @@ -1,25 +1,21 @@ -import os +import sys, os from ctypes_configure import dumpcache -from rpython.jit.backend import detect_cpu def dumpcache2(basename, config): - model = detect_cpu.autodetect_main_model_and_size() - filename = '_%s_%s_.py' % (basename, model) + size = 32 if sys.maxint <= 2**32 else 64 + filename = '_%s_%s_.py' % (basename, size) dumpcache.dumpcache(__file__, filename, config) # filename = os.path.join(os.path.dirname(__file__), '_%s_cache.py' % (basename,)) g = open(filename, 'w') print >> g, '''\ -try: - from __pypy__ import cpumodel -except ImportError: - from rpython.jit.backend import detect_cpu - cpumodel = detect_cpu.autodetect_main_model_and_size() +import sys +_size = 32 if sys.maxint <= 2**32 else 64 # XXX relative import, should be removed together with # XXX the relative imports done e.g. by lib_pypy/pypy_test/test_hashlib -mod = __import__("_%s_%%s_" %% (cpumodel,), - globals(), locals(), ["*"]) -globals().update(mod.__dict__)\ +_mod = __import__("_%s_%%s_" %% (_size,), + globals(), locals(), ["*"]) +globals().update(_mod.__dict__)\ ''' % (basename,) g.close() diff --git a/lib_pypy/ctypes_config_cache/rebuild.py b/lib_pypy/ctypes_config_cache/rebuild.py --- a/lib_pypy/ctypes_config_cache/rebuild.py +++ b/lib_pypy/ctypes_config_cache/rebuild.py @@ -25,13 +25,12 @@ sys.path[:] = path def try_rebuild(): - from rpython.jit.backend import detect_cpu - model = detect_cpu.autodetect_main_model_and_size() - # remove the files '_*_model_.py' + size = 32 if sys.maxint <= 2**32 else 64 + # remove the files '_*_size_.py' left = {} for p in os.listdir(_dirpath): - if p.startswith('_') and (p.endswith('_%s_.py' % model) or - p.endswith('_%s_.pyc' % model)): + if p.startswith('_') and (p.endswith('_%s_.py' % size) or + p.endswith('_%s_.pyc' % size)): os.unlink(os.path.join(_dirpath, p)) elif p.startswith('_') and (p.endswith('_.py') or p.endswith('_.pyc')): diff --git a/py/_path/local.py b/py/_path/local.py --- a/py/_path/local.py +++ b/py/_path/local.py @@ -655,7 +655,8 @@ mkdtemp = classmethod(mkdtemp) def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3, - lock_timeout = 172800): # two days + lock_timeout = 172800, # two days + min_timeout = 300): # five minutes """ return unique directory with a number greater than the current maximum one. The number is assumed to start directly after prefix. if keep is true directories with a number less than (maxnum-keep) @@ -723,6 +724,20 @@ for path in rootdir.listdir(): num = parse_num(path) if num is not None and num <= (maxnum - keep): + if min_timeout: + # NB: doing this is needed to prevent (or reduce + # a lot the chance of) the following situation: + # 'keep+1' processes call make_numbered_dir() at + # the same time, they create dirs, but then the + # last process notices the first dir doesn't have + # (yet) a .lock in it and kills it. + try: + t1 = path.lstat().mtime + t2 = lockfile.lstat().mtime + if abs(t2-t1) < min_timeout: + continue # skip directories too recent + except py.error.Error: + continue # failure to get a time, better skip lf = path.join('.lock') try: t1 = lf.lstat().mtime diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,10 +32,11 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", - "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", + "thread", "itertools", "pyexpat", "_ssl", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_ffi", - "_continuation", "_cffi_backend", "_csv", "cppyy"] + "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"] +# disabled until problems are fixed )) translation_modules = default_modules.copy() @@ -64,7 +65,8 @@ del working_modules["termios"] del working_modules["_minimal_curses"] - del working_modules["cppyy"] # not tested on win32 + if "cppyy" in working_modules: + del working_modules["cppyy"] # not tested on win32 # The _locale module is needed by site.py on Windows default_modules["_locale"] = None @@ -77,20 +79,22 @@ del working_modules["_minimal_curses"] del working_modules["termios"] del working_modules["_multiprocessing"] # depends on rctime - del working_modules["cppyy"] # depends on ctypes + if "cppyy" in working_modules: + del working_modules["cppyy"] # depends on ctypes module_dependencies = { '_multiprocessing': [('objspace.usemodules.rctime', True), ('objspace.usemodules.thread', True)], 'cpyext': [('objspace.usemodules.array', True)], + 'cppyy': [('objspace.usemodules.cpyext', True)], } module_suggests = { # the reason you want _rawffi is for ctypes, which # itself needs the interp-level struct module # because 'P' is missing from the app-level one "_rawffi": [("objspace.usemodules.struct", True)], - "cpyext": [("translation.secondaryentrypoints", "cpyext"), + "cpyext": [("translation.secondaryentrypoints", "cpyext,main"), ("translation.shared", sys.platform == "win32")], } @@ -119,12 +123,10 @@ __import__(name) except (ImportError, CompilationError, py.test.skip.Exception), e: errcls = e.__class__.__name__ - config.add_warning( + raise Exception( "The module %r is disabled\n" % (modname,) + "because importing %s raised %s\n" % (name, errcls) + str(e)) - raise ConflictConfigError("--withmod-%s: %s" % (modname, - errcls)) return validator else: return None @@ -215,10 +217,6 @@ "(the empty string and potentially single-char strings)", default=False), - BoolOption("withsmalltuple", - "use small tuples", - default=False), - BoolOption("withspecialisedtuple", "use specialised tuples", default=False), @@ -363,6 +361,7 @@ # ignore names from 'essential_modules', notably 'exceptions', which # may not be present in config.objspace.usemodules at all modules = [name for name in modules if name not in essential_modules] + config.objspace.usemodules.suggest(**dict.fromkeys(modules, True)) def enable_translationmodules(config): diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst --- a/pypy/doc/coding-guide.rst +++ b/pypy/doc/coding-guide.rst @@ -339,8 +339,9 @@ + methods and other class attributes do not change after startup + single inheritance is fully supported -+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True`` - class attribute ++ simple mixins somewhat work too, but the mixed in class needs a + ``_mixin_ = True`` class attribute. isinstance checks against the + mixin type will fail when translated. + classes are first-class objects too diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py --- a/pypy/doc/conf.py +++ b/pypy/doc/conf.py @@ -47,7 +47,7 @@ # The short X.Y version. version = '2.0' # The full version, including alpha/beta/rc tags. -release = '2.0-beta1' +release = '2.0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst --- a/pypy/doc/cppyy.rst +++ b/pypy/doc/cppyy.rst @@ -163,6 +163,9 @@ $ genreflex MyClass.h $ g++ -fPIC -rdynamic -O2 -shared -I$REFLEXHOME/include MyClass_rflx.cpp -o libMyClassDict.so -L$REFLEXHOME/lib -lReflex +Next, make sure that the library can be found through the dynamic lookup path +(the ``LD_LIBRARY_PATH`` environment variable on Linux, ``PATH`` on Windows), +for example by adding ".". Now you're ready to use the bindings. Since the bindings are designed to look pythonistic, it should be straightforward:: diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst --- a/pypy/doc/getting-started-python.rst +++ b/pypy/doc/getting-started-python.rst @@ -46,7 +46,7 @@ 2. Install build-time dependencies. On a Debian box these are:: [user at debian-box ~]$ sudo apt-get install \ - gcc make python-dev libffi-dev lib-sqlite3-dev pkg-config \ + gcc make python-dev libffi-dev libsqlite3-dev pkg-config \ libz-dev libbz2-dev libncurses-dev libexpat1-dev \ libssl-dev libgc-dev python-sphinx python-greenlet @@ -105,7 +105,7 @@ $ ./pypy-c Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``RPython magically makes you rich and famous (says so on the tin)'' @@ -235,7 +235,7 @@ the ``bin/pypy`` executable. To install PyPy system wide on unix-like systems, it is recommended to put the -whole hierarchy alone (e.g. in ``/opt/pypy2.0-beta1``) and put a symlink to the +whole hierarchy alone (e.g. in ``/opt/pypy2.0``) and put a symlink to the ``pypy`` executable into ``/usr/bin`` or ``/usr/local/bin`` If the executable fails to find suitable libraries, it will report diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst --- a/pypy/doc/getting-started.rst +++ b/pypy/doc/getting-started.rst @@ -53,10 +53,10 @@ PyPy is ready to be executed as soon as you unpack the tarball or the zip file, with no need to install it in any specific location:: - $ tar xf pypy-2.0-beta1-linux.tar.bz2 - $ ./pypy-2.0-beta1/bin/pypy + $ tar xf pypy-2.0.tar.bz2 + $ ./pypy-2.0/bin/pypy Python 2.7.3 (7e4f0faa3d51, Nov 22 2012, 10:35:18) - [PyPy 2.0.0-beta1 with GCC 4.7.1] on linux2 + [PyPy 2.0.0 with GCC 4.7.1] on linux2 Type "help", "copyright", "credits" or "license" for more information. And now for something completely different: ``PyPy is an exciting technology that lets you to write fast, portable, multi-platform interpreters with less @@ -75,14 +75,14 @@ $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ ./pypy-2.0-beta1/bin/pypy distribute_setup.py + $ ./pypy-2.0/bin/pypy distribute_setup.py - $ ./pypy-2.0-beta1/bin/pypy get-pip.py + $ ./pypy-2.0/bin/pypy get-pip.py - $ ./pypy-2.0-beta1/bin/pip install pygments # for example + $ ./pypy-2.0/bin/pip install pygments # for example -3rd party libraries will be installed in ``pypy-2.0-beta1/site-packages``, and -the scripts in ``pypy-2.0-beta1/bin``. +3rd party libraries will be installed in ``pypy-2.0/site-packages``, and +the scripts in ``pypy-2.0/bin``. Installing using virtualenv --------------------------- diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst --- a/pypy/doc/how-to-contribute.rst +++ b/pypy/doc/how-to-contribute.rst @@ -28,7 +28,8 @@ Layers ------ -PyPy has layers. Those layers help us keep the respective parts separated enough +PyPy has layers. Just like Ogres or onions. +Those layers help us keep the respective parts separated enough to be worked on independently and make the complexity manageable. This is, again, just a sanity requirement for such a complex project. For example writing a new optimization for the JIT usually does **not** involve touching a Python diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst --- a/pypy/doc/how-to-release.rst +++ b/pypy/doc/how-to-release.rst @@ -22,7 +22,8 @@ will capture the revision number of this change for the release; some of the next updates may be done before or after branching; make sure things are ported back to the trunk and to the branch as - necessary + necessary; also update the version number in pypy/doc/conf.py, + and in pypy/doc/index.rst * update pypy/doc/contributor.rst (and possibly LICENSE) * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst and create a fresh whatsnew_head.rst after the release diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst --- a/pypy/doc/index.rst +++ b/pypy/doc/index.rst @@ -40,7 +40,7 @@ * `FAQ`_: some frequently asked questions. -* `Release 2.0 beta 2`_: the latest official release +* `Release 2.0.2`_: the latest official release * `PyPy Blog`_: news and status info about PyPy @@ -110,7 +110,7 @@ .. _`Getting Started`: getting-started.html .. _`Papers`: extradoc.html .. _`Videos`: video-index.html -.. _`Release 2.0 beta 2`: http://pypy.org/download.html +.. _`Release 2.0.2`: http://pypy.org/download.html .. _`speed.pypy.org`: http://speed.pypy.org .. _`RPython toolchain`: translation.html .. _`potential project ideas`: project-ideas.html diff --git a/pypy/doc/release-2.0.0.rst b/pypy/doc/release-2.0.0.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.0.rst @@ -0,0 +1,71 @@ +============================ +PyPy 2.0 - Einstein Sandwich +============================ + +We're pleased to announce PyPy 2.0. This is a stable release that brings +a swath of bugfixes, small performance improvements and compatibility fixes. +PyPy 2.0 is a big step for us and we hope in the future we'll be able to +provide stable releases more often. + +You can download the PyPy 2.0 release here: + + http://pypy.org/download.html + +The two biggest changes since PyPy 1.9 are: + +* stackless is now supported including greenlets, which means eventlet + and gevent should work (but read below about gevent) + +* PyPy now contains release 0.6 of `cffi`_ as a builtin module, which + is preferred way of calling C from Python that works well on PyPy + +.. _`cffi`: http://cffi.readthedocs.org + +If you're using PyPy for anything, it would help us immensely if you fill out +the following survey: http://bit.ly/pypysurvey This is for the developers +eyes and we will not make any information public without your agreement. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Windows 64 work is still stalling, we would welcome a volunteer +to handle that. ARM support is on the way, as you can see from the recently +released alpha for ARM. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +* Stackless including greenlets should work. For gevent, you need to check + out `pypycore`_ and use the `pypy-hacks`_ branch of gevent. + +* cffi is now a module included with PyPy. (`cffi`_ also exists for + CPython; the two versions should be fully compatible.) It is the + preferred way of calling C from Python that works on PyPy. + +* Callbacks from C are now JITted, which means XML parsing is much faster. + +* A lot of speed improvements in various language corners, most of them small, + but speeding up some particular corners a lot. + +* The JIT was refactored to emit machine code which manipulates a "frame" + that lives on the heap rather than on the stack. This is what makes + Stackless work, and it could bring another future speed-up (not done yet). + +* A lot of stability issues fixed. + +* Refactoring much of the numpypy array classes, which resulted in removal of + lazy expression evaluation. On the other hand, we now have more complete + dtype support and support more array attributes. + +.. _`pypycore`: https://github.com/gevent-on-pypy/pypycore/ +.. _`pypy-hacks`: https://github.com/schmir/gevent/tree/pypy-hacks + +Cheers, +fijal, arigo and the PyPy team diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.1.rst @@ -0,0 +1,46 @@ +============================== +PyPy 2.0.1 - Bohr Smørrebrød +============================== + +We're pleased to announce PyPy 2.0.1. This is a stable bugfix release +over `2.0`_. You can download it here: + + http://pypy.org/download.html + +The fixes are mainly about fatal errors or crashes in our stdlib. See +below for more details. + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +- fix an occasional crash in the JIT that ends in `RPython Fatal error: + NotImplementedError`__. + +- `id(x)` is now always a positive number (except on int/float/long/complex). + This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux). + +- fix crashes of callback-from-C-functions (with cffi) when used together + with Stackless features, on asmgcc (i.e. Linux only). Now `gevent should + work better`__. + +- work around an eventlet issue with `socket._decref_socketios()`__. + +.. __: https://bugs.pypy.org/issue1482 +.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html +.. __: https://bugs.pypy.org/issue1468 +.. _2.0: release-2.0.0.html + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst new file mode 100644 --- /dev/null +++ b/pypy/doc/release-2.0.2.rst @@ -0,0 +1,46 @@ +========================= +PyPy 2.0.2 - Fermi Panini +========================= + +We're pleased to announce PyPy 2.0.2. This is a stable bugfix release +over `2.0`_ and `2.0.1`_. You can download it here: + + http://pypy.org/download.html + +It fixes a crash in the JIT when calling external C functions (with +ctypes/cffi) in a multithreaded context. + +.. _2.0: release-2.0.0.html +.. _2.0.1: release-2.0.1.html + +What is PyPy? +============= + +PyPy is a very compliant Python interpreter, almost a drop-in replacement for +CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison) +due to its integrated tracing JIT compiler. + +This release supports x86 machines running Linux 32/64, Mac OS X 64 or +Windows 32. Support for ARM is progressing but not bug-free yet. + +.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org + +Highlights +========== + +This release contains only the fix described above. A crash (or wrong +results) used to occur if all these conditions were true: + +- your program is multithreaded; + +- it runs on a single-core machine or a heavily-loaded multi-core one; + +- it uses ctypes or cffi to issue external calls to C functions. + +This was fixed in the branch `emit-call-x86`__ (see the example file +``bug1.py``). + +.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4 + +Cheers, +arigo et. al. for the PyPy team diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py --- a/pypy/doc/test/test_whatsnew.py +++ b/pypy/doc/test/test_whatsnew.py @@ -19,23 +19,28 @@ branches.discard('default') return startrev, branches -def get_merged_branches(path, startrev, endrev): - if getstatusoutput('hg root')[0]: +def get_merged_branches(path, startrev, endrev, current_branch=None): + errcode, wc_branch = getstatusoutput('hg branch') + if errcode != 0: py.test.skip('no Mercurial repo') + if current_branch is None: + current_branch = wc_branch # X = take all the merges which are descendants of startrev and are on default # revset = all the parents of X which are not on default # ===> # revset contains all the branches which have been merged to default since # startrev - revset = 'parents(%s::%s and \ + revset = "parents(%s::%s and \ merge() and \ - branch(default)) and \ - not branch(default)' % (startrev, endrev) + branch('%s')) and \ + not branch('%s')" % (startrev, endrev, + current_branch, current_branch) cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset) out = getoutput(cmd) branches = set(map(str.strip, out.splitlines())) - return branches + branches.discard("default") + return branches, current_branch def test_parse_doc(): @@ -65,7 +70,8 @@ assert branches == set(['foobar', 'hello']) def test_get_merged_branches(): - branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93') + branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93', + 'default') assert branches == set(['numpy-indexing-by-arrays-bool', 'better-jit-hooks-2', 'numpypy-ufuncs']) @@ -76,7 +82,9 @@ whatsnew_list.sort() last_whatsnew = whatsnew_list[-1].read() startrev, documented = parse_doc(last_whatsnew) - merged = get_merged_branches(ROOT, startrev, '') + merged, branch = get_merged_branches(ROOT, startrev, '') + merged.discard('default') + merged.discard('') not_documented = merged.difference(documented) not_merged = documented.difference(merged) print 'Branches merged but not documented:' @@ -85,4 +93,6 @@ print 'Branches documented but not merged:' print '\n'.join(not_merged) print - assert not not_documented and not not_merged + assert not not_documented + if branch == 'default': + assert not not_merged diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-2.0.rst copy from pypy/doc/whatsnew-head.rst copy to pypy/doc/whatsnew-2.0.rst diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -1,140 +1,36 @@ ====================== -What's new in PyPy 2.0 +What's new in PyPy 2.1 ====================== -.. this is a revision shortly after release-2.0-beta1 -.. startrev: 0e6161a009c6 +.. this is a revision shortly after release-2.0 +.. startrev: a13c07067613 -.. branch: split-rpython -Split rpython and pypy into seperate directories +.. branch: numpy-pickle +Pickling of numpy arrays and dtypes (including record dtypes) -.. branch: callback-jit -Callbacks from C are now better JITted +.. branch: remove-array-smm +Remove multimethods in the arraymodule -.. branch: fix-jit-logs +.. branch: callback-stacklet +Fixed bug when switching stacklets from a C callback -.. branch: remove-globals-in-jit +.. branch: remove-set-smm +Remove multi-methods on sets -.. branch: length-hint -Implement __lenght_hint__ according to PEP 424 +.. branch: numpy-subarrays +Implement subarrays for numpy -.. branch: numpypy-longdouble -Long double support for numpypy +.. branch: remove-dict-smm +Remove multi-methods on dict -.. branch: numpypy-disable-longdouble -Since r_longdouble support is missing, disable all longdouble and derivative -dtypes using ENABLED_LONG_DOUBLE = False +.. branch: remove-list-smm-2 +Remove remaining multi-methods on list -.. branch: numpypy-real-as-view -Convert real, imag from ufuncs to views. This involves the beginning of -view() functionality +.. branch: arm-stacklet +Stacklet support for ARM, enables _continuation support -.. branch: indexing-by-array -Adds indexing by scalar, adds int conversion from scalar and single element array, -fixes compress, indexing by an array with a smaller shape and the indexed object. +.. branch: remove-tuple-smm +Remove multi-methods on tuple -.. branch: str-dtype-improvement -Allow concatenation of str and numeric arrays - -.. branch: signatures -Improved RPython typing - -.. branch: rpython-bytearray -Rudimentary support for bytearray in RPython - -.. branch: refactor-call_release_gil -Fix a bug which caused cffi to return the wrong result when calling a C -function which calls a Python callback which forces the frames - -.. branch: virtual-raw-mallocs -JIT optimizations which make cffi calls even faster, by removing the need to -allocate a temporary buffer where to store the arguments. - -.. branch: improve-docs-2 -Improve documents and straighten out links - -.. branch: fast-newarray -Inline the fast path of newarray in the assembler. -Disabled on ARM until we fix issues. - -.. branch: reflex-support -Allow dynamic loading of a (Reflex) backend that implements the C-API needed -to provide reflection information - -.. branches we don't care about -.. branch: autoreds -.. branch: kill-faking -.. branch: improved_ebnfparse_error -.. branch: task-decorator -.. branch: fix-e4fa0b2 -.. branch: win32-fixes -.. branch: numpy-unify-methods -.. branch: fix-version-tool -.. branch: popen2-removal -.. branch: pickle-dumps -.. branch: scalar_get_set - -.. branch: release-2.0-beta1 - -.. branch: remove-PYPY_NOT_MAIN_FILE - -.. branch: missing-jit-operations - -.. branch: fix-lookinside-iff-oopspec -Fixed the interaction between two internal tools for controlling the JIT. - -.. branch: inline-virtualref-2 -Better optimized certain types of frame accesses in the JIT, particularly -around exceptions that escape the function they were raised in. - -.. branch: missing-ndarray-attributes -Some missing attributes from ndarrays - -.. branch: cleanup-tests -Consolidated the lib_pypy/pypy_test and pypy/module/test_lib_pypy tests into -one directory for reduced confusion and so they all run nightly. - -.. branch: unquote-faster -.. branch: urlparse-unquote-faster - -.. branch: signal-and-thread -Add "__pypy__.thread.signals_enabled", a context manager. Can be used in a -non-main thread to enable the processing of signal handlers in that thread. - -.. branch: coding-guide-update-rlib-refs -.. branch: rlib-doc-rpython-refs -.. branch: clean-up-remaining-pypy-rlib-refs - -.. branch: enumerate-rstr -Support enumerate() over rstr types. - -.. branch: cleanup-numpypy-namespace -Cleanup _numpypy and numpypy namespaces to more closely resemble numpy. - -.. branch: kill-flowobjspace -Random cleanups to hide FlowObjSpace from public view. - -.. branch: vendor-rename - -.. branch: jitframe-on-heap -Moves optimized JIT frames from stack to heap. As a side effect it enables -stackless to work well with the JIT on PyPy. Also removes a bunch of code from -the GC which fixes cannot find gc roots. - -.. branch: pycon2013-doc-fixes -Documentation fixes after going through the docs at PyCon 2013 sprint. - -.. branch: extregistry-refactor - -.. branch: remove-list-smm -.. branch: bridge-logging -.. branch: curses_cffi -cffi implementation of _curses - -.. branch: sqlite-cffi -cffi implementation of sqlite3 - -.. branch: release-2.0-beta2 -.. branch: unbreak-freebsd - -.. branch: virtualref-virtualizable +.. branch: remove-iter-smm +Remove multi-methods on iterators diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -6,8 +6,16 @@ if sys.platform.startswith('linux'): arch = 'linux' + cmd = 'wget "%s"' + tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" + if os.uname()[-1].startswith('arm'): + arch += '-armhf-raspbian' +elif sys.platform.startswith('darwin'): + arch = 'osx' + cmd = 'curl -O "%s"' + tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'" else: - print 'Cannot determine the platform, please update this scrip' + print 'Cannot determine the platform, please update this script' sys.exit(1) if sys.maxint == 2**63 - 1: @@ -23,10 +31,9 @@ tmp = py.path.local.mkdtemp() mydir = tmp.chdir() print 'Downloading pypy to', tmp -if os.system('wget "%s"' % url) != 0: +if os.system(cmd % url) != 0: sys.exit(1) print 'Extracting pypy binary' mydir.chdir() -os.system("tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'" % tmp.join(filename)) - +os.system(tar % tmp.join(filename)) diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -2,6 +2,7 @@ import os, sys +import pypy from pypy.interpreter import gateway from pypy.interpreter.error import OperationError from pypy.tool.ann_override import PyPyAnnotatorPolicy @@ -9,6 +10,8 @@ from rpython.config.config import ConflictConfigError from pypy.tool.option import make_objspace from pypy.conftest import pypydir +from rpython.rlib import rthread +from pypy.module.thread import os_thread thisdir = py.path.local(__file__).dirpath() @@ -22,20 +25,22 @@ # __________ Entry point __________ + def create_entry_point(space, w_dict): - w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) - w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) - w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) - w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) - withjit = space.config.objspace.usemodules.pypyjit + if w_dict is not None: # for tests + w_entry_point = space.getitem(w_dict, space.wrap('entry_point')) + w_run_toplevel = space.getitem(w_dict, space.wrap('run_toplevel')) + w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish)) + w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup)) + withjit = space.config.objspace.usemodules.pypyjit def entry_point(argv): if withjit: from rpython.jit.backend.hlinfo import highleveljitinfo highleveljitinfo.sys_executable = argv[0] - #debug("entry point starting") - #for arg in argv: + #debug("entry point starting") + #for arg in argv: # debug(" argv -> " + arg) if len(argv) > 2 and argv[1] == '--heapsize': # Undocumented option, handled at interp-level. @@ -71,7 +76,90 @@ debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) return 1 return exitcode - return entry_point + + # register the minimal equivalent of running a small piece of code. This + # should be used as sparsely as possible, just to register callbacks + + from rpython.rlib.entrypoint import entrypoint + from rpython.rtyper.lltypesystem import rffi, lltype + + w_pathsetter = space.appexec([], """(): + def f(path): + import sys + sys.path[:] = path + return f + """) + + @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home') + def pypy_setup_home(ll_home, verbose): + from pypy.module.sys.initpath import pypy_find_stdlib + if ll_home: + home = rffi.charp2str(ll_home) + else: + home = pypydir + w_path = pypy_find_stdlib(space, home) + if space.is_none(w_path): + if verbose: + debug("Failed to find library based on pypy_find_stdlib") + return 1 + space.startup() + space.call_function(w_pathsetter, w_path) + # import site + try: + import_ = space.getattr(space.getbuiltinmodule('__builtin__'), + space.wrap('__import__')) + space.call_function(import_, space.wrap('site')) + return 0 + except OperationError, e: + if verbose: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + + @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source') + def pypy_execute_source(ll_source): + source = rffi.charp2str(ll_source) + return _pypy_execute_source(source) + + @entrypoint('main', [], c_name='pypy_init_threads') + def pypy_init_threads(): + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + rffi.aroundstate.before() + + @entrypoint('main', [], c_name='pypy_thread_attach') + def pypy_thread_attach(): + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + os_thread.bootstrapper.acquire(space, None, None) + rthread.gc_thread_start() + os_thread.bootstrapper.nbthreads += 1 + os_thread.bootstrapper.release() + rffi.aroundstate.before() + + w_globals = space.newdict() + space.setitem(w_globals, space.wrap('__builtins__'), + space.builtin_modules['__builtin__']) + + def _pypy_execute_source(source): + try: + compiler = space.createcompiler() + stmt = compiler.compile(source, 'c callback', 'exec', 0) + stmt.exec_code(space, w_globals, w_globals) + except OperationError, e: + debug("OperationError:") + debug(" operror-type: " + e.w_type.getname(space)) + debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space)))) + return 1 + return 0 + + return entry_point, {'pypy_execute_source': pypy_execute_source, + 'pypy_init_threads': pypy_init_threads, + 'pypy_thread_attach': pypy_thread_attach, + 'pypy_setup_home': pypy_setup_home} def call_finish(space): space.finish() @@ -219,7 +307,7 @@ def jitpolicy(self, driver): from pypy.module.pypyjit.policy import PyPyJitPolicy, pypy_hooks return PyPyJitPolicy(pypy_hooks) - + def get_entry_point(self, config): from pypy.tool.lib_pypy import import_from_lib_pypy rebuild = import_from_lib_pypy('ctypes_config_cache/rebuild') @@ -232,7 +320,7 @@ app = gateway.applevel(open(filename).read(), 'app_main.py', 'app_main') app.hidden_applevel = False w_dict = app.getwdict(space) - entry_point = create_entry_point(space, w_dict) + entry_point, _ = create_entry_point(space, w_dict) return entry_point, None, PyPyAnnotatorPolicy(single_space = space) diff --git a/pypy/interpreter/app_main.py b/pypy/interpreter/app_main.py --- a/pypy/interpreter/app_main.py +++ b/pypy/interpreter/app_main.py @@ -1,20 +1,40 @@ #! /usr/bin/env python # App-level version of py.py. # See test/test_app_main. + +# Missing vs CPython: -d, -OO, -t, -v, -x, -3 +"""\ +Options and arguments (and corresponding environment variables): +-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x +-c cmd : program passed in as string (terminates option list) +-E : ignore PYTHON* environment variables (such as PYTHONPATH) +-h : print this help message and exit (also --help) +-i : inspect interactively after running script; forces a prompt even + if stdin does not appear to be a terminal; also PYTHONINSPECT=x +-m mod : run library module as a script (terminates option list) +-O : dummy optimization flag for compatibility with CPython +-R : ignored (see http://bugs.python.org/issue14621) +-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew +-s : don't add user site directory to sys.path; also PYTHONNOUSERSITE +-S : don't imply 'import site' on initialization +-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x +-V : print the Python version number and exit (also --version) +-W arg : warning control; arg is action:message:category:module:lineno + also PYTHONWARNINGS=arg +file : program read from script file +- : program read from stdin (default; interactive mode if a tty) +arg ...: arguments passed to program in sys.argv[1:] +PyPy options and arguments: +--info : print translation information about this PyPy executable """ -options: - -i inspect interactively after running script - -O dummy optimization flag for compatibility with C Python - -c cmd program passed in as CMD (terminates option list) - -S do not 'import site' on initialization - -u unbuffered binary stdout and stderr - -h, --help show this help message and exit - -m mod library module to be run as a script (terminates option list) - -W arg warning control (arg is action:message:category:module:lineno) - -E ignore environment variables (such as PYTHONPATH) - -R ignored (see http://bugs.python.org/issue14621) - --version print the PyPy version - --info print translation information about this PyPy executable +USAGE1 = __doc__ +# Missing vs CPython: PYTHONHOME, PYTHONCASEOK +USAGE2 = """ +Other environment variables: +PYTHONSTARTUP: file executed on interactive startup (no default) +PYTHONPATH : %r-separated list of directories prefixed to the + default module search path. The result is sys.path. +PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr. """ import sys @@ -136,12 +156,13 @@ raise SystemExit def print_help(*args): - print 'usage: %s [options] [-c cmd|-m mod|file.py|-] [arg...]' % ( + import os + print 'usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...' % ( sys.executable,) - print __doc__.rstrip() + print USAGE1, if 'pypyjit' in sys.builtin_module_names: - print " --jit OPTIONS advanced JIT options: try 'off' or 'help'" - print + print "--jit options: advanced JIT options: try 'off' or 'help'" + print (USAGE2 % (os.pathsep,)), raise SystemExit def _print_jit_help(): diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -853,9 +853,10 @@ self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True) if i < (ops_count - 1): comp.comparators[i].walkabout(self) - comp.comparators[-1].walkabout(self) - last_kind = compare_operations(comp.ops[-1]) - self.emit_op_arg(ops.COMPARE_OP, last_kind) + last_op, last_comparator = comp.ops[-1], comp.comparators[-1] + if not self._optimize_comparator(last_op, last_comparator): + last_comparator.walkabout(self) + self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op)) if ops_count > 1: end = self.new_block() self.emit_jump(ops.JUMP_FORWARD, end) @@ -864,6 +865,37 @@ self.emit_op(ops.POP_TOP) self.use_next_block(end) + def _optimize_comparator(self, op, node): + """Fold lists/sets of constants in the context of "in"/"not in". + + lists are folded into tuples, sets into frozensets, otherwise + returns False + """ + if op in (ast.In, ast.NotIn): + is_list = isinstance(node, ast.List) + if is_list or isinstance(node, ast.Set): + w_const = self._tuple_of_consts(node.elts) + if w_const is not None: + if not is_list: + from pypy.objspace.std.setobject import ( + W_FrozensetObject) + w_const = W_FrozensetObject(self.space, w_const) + self.load_const(w_const) + return True + return False + + def _tuple_of_consts(self, elts): + """Return a tuple of consts from elts if possible, or None""" + count = len(elts) if elts is not None else 0 + consts_w = [None] * count + for i in range(count): + w_value = elts[i].as_constant() + if w_value is None: + # Not all constants + return None + consts_w[i] = w_value + return self.space.newtuple(consts_w) + def visit_IfExp(self, ifexp): self.update_position(ifexp.lineno) end = self.new_block() diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -973,3 +973,30 @@ counts = self.count_instructions(source3) assert counts[ops.BUILD_LIST] == 1 assert ops.BUILD_LIST_FROM_ARG not in counts + + def test_folding_of_list_constants(self): + for source in ( + # in/not in constants with BUILD_LIST should be folded to a tuple: + 'a in [1,2,3]', + 'a not in ["a","b","c"]', + 'a in [None, 1, None]', + 'a not in [(1, 2), 3, 4]', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_LIST not in counts + assert ops.LOAD_CONST in counts + + def test_folding_of_set_constants(self): + for source in ( + # in/not in constants with BUILD_SET should be folded to a frozenset: + 'a in {1,2,3}', + 'a not in {"a","b","c"}', + 'a in {None, 1, None}', + 'a not in {(1, 2), 3, 4}', + 'a in {1, 2, 3, 3, 2, 1}', + ): + source = 'def f(): %s' % source + counts = self.count_instructions(source) + assert ops.BUILD_SET not in counts + assert ops.LOAD_CONST in counts diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -242,6 +242,11 @@ def __spacebind__(self, space): return self + def unwrap(self, space): + """NOT_RPYTHON""" + # _____ this code is here to support testing only _____ + return self + class W_InterpIterable(W_Root): def __init__(self, space, w_iterable): @@ -666,7 +671,8 @@ def id(self, w_obj): w_result = w_obj.immutable_unique_id(self) if w_result is None: - w_result = self.wrap(compute_unique_id(w_obj)) + # in the common case, returns an unsigned value + w_result = self.wrap(r_uint(compute_unique_id(w_obj))) return w_result def hash_w(self, w_obj): diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -803,7 +803,6 @@ args = inspect.getargs(func.func_code) if args.varargs or args.keywords: raise TypeError("Varargs and keywords not supported in unwrap_spec") - assert not func.func_defaults argspec = ', '.join([arg for arg in args.args[1:]]) func_code = py.code.Source(""" def f(w_obj, %(args)s): @@ -812,11 +811,13 @@ d = {} exec func_code.compile() in d f = d['f'] + f.func_defaults = unbound_meth.func_defaults + f.func_doc = unbound_meth.func_doc f.__module__ = func.__module__ # necessary for unique identifiers for pickling f.func_name = func.func_name if unwrap_spec is None: - unwrap_spec = {} + unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {}) else: assert isinstance(unwrap_spec, dict) unwrap_spec = unwrap_spec.copy() diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -27,7 +27,7 @@ new_inst = mod.get('generator_new') w = space.wrap if self.frame: - w_frame = w(self.frame) + w_frame = self.frame._reduce_state(space) else: w_frame = space.w_None @@ -36,7 +36,20 @@ w(self.running), ] - return space.newtuple([new_inst, space.newtuple(tup)]) + return space.newtuple([new_inst, space.newtuple([]), + space.newtuple(tup)]) + + def descr__setstate__(self, space, w_args): + from rpython.rlib.objectmodel import instantiate + args_w = space.unpackiterable(w_args) + w_framestate, w_running = args_w + if space.is_w(w_framestate, space.w_None): + self.frame = None + else: + frame = instantiate(space.FrameClass) # XXX fish + frame.descr__setstate__(space, w_framestate) + GeneratorIterator.__init__(self, frame) + self.running = self.space.is_true(w_running) def descr__iter__(self): """x.__iter__() <==> iter(x)""" diff --git a/pypy/interpreter/mixedmodule.py b/pypy/interpreter/mixedmodule.py --- a/pypy/interpreter/mixedmodule.py +++ b/pypy/interpreter/mixedmodule.py @@ -13,6 +13,7 @@ # imported yet, and when it has been, it is mod.__dict__.items() just # after startup(). w_initialdict = None + lazy = False def __init__(self, space, w_name): """ NOT_RPYTHON """ diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -16,10 +16,9 @@ from rpython.tool.stdlib_opcode import host_bytecode_spec # Define some opcodes used -g = globals() for op in '''DUP_TOP POP_TOP SETUP_LOOP SETUP_EXCEPT SETUP_FINALLY POP_BLOCK END_FINALLY'''.split(): - g[op] = stdlib_opcode.opmap[op] + globals()[op] = stdlib_opcode.opmap[op] HAVE_ARGUMENT = stdlib_opcode.HAVE_ARGUMENT class PyFrame(eval.Frame): @@ -304,11 +303,17 @@ @jit.dont_look_inside def descr__reduce__(self, space): from pypy.interpreter.mixedmodule import MixedModule - from pypy.module._pickle_support import maker # helper fns w_mod = space.getbuiltinmodule('_pickle_support') mod = space.interp_w(MixedModule, w_mod) new_inst = mod.get('frame_new') - w = space.wrap + w_tup_state = self._reduce_state(space) + nt = space.newtuple + return nt([new_inst, nt([]), w_tup_state]) + + @jit.dont_look_inside + def _reduce_state(self, space): + from pypy.module._pickle_support import maker # helper fns + w = space.wrap nt = space.newtuple cells = self._getcells() @@ -359,8 +364,7 @@ w(self.instr_prev_plus_one), w_cells, ] - - return nt([new_inst, nt([]), nt(tup_state)]) + return nt(tup_state) @jit.dont_look_inside def descr__setstate__(self, space, w_args): diff --git a/pypy/interpreter/pyparser/future.py b/pypy/interpreter/pyparser/future.py --- a/pypy/interpreter/pyparser/future.py +++ b/pypy/interpreter/pyparser/future.py @@ -1,307 +1,3 @@ -""" -This automaton is designed to be invoked on a Python source string -before the real parser starts working, in order to find all legal -'from __future__ import blah'. As soon as something is encountered that -would prevent more future imports, the analysis is aborted. -The resulting legal futures are avaliable in self.flags after the -pass has ended. - -Invocation is through get_futures(src), which returns a field of flags, one per -found correct future import. - -The flags can then be used to set up the parser. -All error detection is left to the parser. - -The reason we are not using the regular lexer/parser toolchain is that -we do not want the overhead of generating tokens for entire files just -to find information that resides in the first few lines of the file. -Neither do we require sane error messages, as this job is handled by -the parser. - -To make the parsing fast, especially when the module is translated to C, -the code has been written in a very serial fashion, using an almost -assembler like style. A further speedup could be achieved by replacing -the "in" comparisons with explicit numeric comparisons. -""" - -from pypy.interpreter.astcompiler.consts import CO_GENERATOR_ALLOWED, \ - CO_FUTURE_DIVISION, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_ABSOLUTE_IMPORT - -def get_futures(future_flags, source): - futures = FutureAutomaton(future_flags, source) - try: - futures.start() - except DoneException, e: - pass - return futures.flags, (futures.lineno, futures.col_offset) - -class DoneException(Exception): - pass - -whitespace = ' \t\f' -whitespace_or_newline = whitespace + '\n\r' -letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxyz_' -alphanumerics = letters + '1234567890' - -class FutureAutomaton(object): - """ - A future statement must appear near the top of the module. - The only lines that can appear before a future statement are: - - * the module docstring (if any), - * comments, - * blank lines, and - * other future statements. - - The features recognized by Python 2.5 are "generators", - "division", "nested_scopes" and "with_statement", "absolute_import". - "generators", "division" and "nested_scopes" are redundant - in 2.5 because they are always enabled. - - This module parses the input until it encounters something that is - not recognized as a valid future statement or something that may - precede a future statement. - """ - - def __init__(self, future_flags, string): - self.future_flags = future_flags - self.s = string - self.pos = 0 - self.current_lineno = 1 - self.lineno = -1 - self.line_start_pos = 0 - self.col_offset = 0 - self.docstring_consumed = False - self.flags = 0 - self.got_features = 0 - - def getc(self, offset=0): - try: - return self.s[self.pos + offset] - except IndexError: - raise DoneException - - def start(self): - c = self.getc() - if c in ("'", '"', "r", "u") and not self.docstring_consumed: - self.consume_docstring() - elif c == '\\' or c in whitespace_or_newline: - self.consume_empty_line() - elif c == '#': - self.consume_comment() - elif c == 'f': - self.consume_from() - else: - return - - def atbol(self): - self.current_lineno += 1 - self.line_start_pos = self.pos - - def consume_docstring(self): - self.docstring_consumed = True - if self.getc() == "r": - self.pos += 1 - if self.getc() == "u": - self.pos += 1 - endchar = self.getc() - if (self.getc() == self.getc(+1) and - self.getc() == self.getc(+2)): - self.pos += 3 - while 1: # Deal with a triple quoted docstring - c = self.getc() - if c == '\\': - self.pos += 1 - self._skip_next_char_from_docstring() - elif c != endchar: - self._skip_next_char_from_docstring() - else: - self.pos += 1 - if (self.getc() == endchar and - self.getc(+1) == endchar): - self.pos += 2 - self.consume_empty_line() - break - - else: # Deal with a single quoted docstring - self.pos += 1 - while 1: - c = self.getc() - self.pos += 1 - if c == endchar: - self.consume_empty_line() - return - elif c == '\\': - self._skip_next_char_from_docstring() - elif c in '\r\n': - # Syntax error - return - - def _skip_next_char_from_docstring(self): - c = self.getc() - self.pos += 1 - if c == '\n': - self.atbol() - elif c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - - def consume_continuation(self): - c = self.getc() - if c in '\n\r': - self.pos += 1 - self.atbol() - - def consume_empty_line(self): - """ - Called when the remainder of the line can only contain whitespace - and comments. - """ - while self.getc() in whitespace: - self.pos += 1 - if self.getc() == '#': - self.consume_comment() - elif self.getc() == ';': - self.pos += 1 - self.consume_whitespace() - self.start() - elif self.getc() in '\\': - self.pos += 1 - self.consume_continuation() - self.start() - elif self.getc() in '\r\n': - c = self.getc() - self.pos += 1 - if c == '\r': - if self.getc() == '\n': - self.pos += 1 - self.atbol() - else: - self.atbol() - self.start() - - def consume_comment(self): - self.pos += 1 - while self.getc() not in '\r\n': - self.pos += 1 - self.consume_empty_line() - - def consume_from(self): - col_offset = self.pos - self.line_start_pos - line = self.current_lineno - self.pos += 1 - if self.getc() == 'r' and self.getc(+1) == 'o' and self.getc(+2) == 'm': - self.docstring_consumed = True - self.pos += 3 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+10] != '__future__': - raise DoneException - self.pos += 10 - self.consume_mandatory_whitespace() - if self.s[self.pos:self.pos+6] != 'import': - raise DoneException - self.pos += 6 - self.consume_whitespace() - old_got = self.got_features - try: - if self.getc() == '(': - self.pos += 1 - self.consume_whitespace() - self.set_flag(self.get_name()) - # Set flag corresponding to name - self.get_more(paren_list=True) - else: - self.set_flag(self.get_name()) - self.get_more() - finally: - if self.got_features > old_got: - self.col_offset = col_offset - self.lineno = line - self.consume_empty_line() - - def consume_mandatory_whitespace(self): - if self.getc() not in whitespace + '\\': - raise DoneException - self.consume_whitespace() - - def consume_whitespace(self, newline_ok=False): - while 1: - c = self.getc() - if c in whitespace: - self.pos += 1 - continue - elif c == '\\' or newline_ok: - slash = c == '\\' - if slash: - self.pos += 1 - c = self.getc() - if c == '\n': - self.pos += 1 - self.atbol() - continue - elif c == '\r': - self.pos += 1 - if self.getc() == '\n': - self.pos += 1 - self.atbol() - elif slash: - raise DoneException - else: - return - else: - return - - def get_name(self): - if self.getc() not in letters: - raise DoneException - p = self.pos - try: - while self.getc() in alphanumerics: - self.pos += 1 - except DoneException: - # If there's any name at all, we want to call self.set_flag(). - # Something else while get the DoneException again. - if self.pos == p: - raise - end = self.pos - else: - end = self.pos - self.consume_whitespace() - return self.s[p:end] - - def get_more(self, paren_list=False): - if paren_list and self.getc() == ')': - self.pos += 1 - return From noreply at buildbot.pypy.org Mon May 27 21:11:43 2013 From: noreply at buildbot.pypy.org (Stian Andreassen) Date: Mon, 27 May 2013 21:11:43 +0200 (CEST) Subject: [pypy-commit] pypy default: - Use the same way to create longs on 32bit. Message-ID: <20130527191143.2F6971C1442@cobra.cs.uni-duesseldorf.de> Author: Stian Andreassen Branch: Changeset: r64590:6bb363cd7367 Date: 2013-05-27 21:10 +0200 http://bitbucket.org/pypy/pypy/changeset/6bb363cd7367/ Log: - Use the same way to create longs on 32bit. - Remove unnecesary left over special case from _x_sub. - Comment out one sign bit from _x_sub. Tests pass without it. Its an unsigned. Not a widedigit. diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py --- a/rpython/rlib/rbigint.py +++ b/rpython/rlib/rbigint.py @@ -180,34 +180,15 @@ ival = r_uint(intval) else: return NULLRBIGINT - # Count the number of Python digits. - # We used to pick 5 ("big enough for anything"), but that's a - # waste of time and space given that 5*15 = 75 bits are rarely - # needed. - # XXX: Even better! - if SHIFT >= 63: - carry = ival >> SHIFT - if carry: - return rbigint([_store_digit(ival & MASK), - _store_digit(carry)], sign, 2) - else: - return rbigint([_store_digit(ival & MASK)], sign, 1) + + carry = ival >> SHIFT + if carry: + return rbigint([_store_digit(ival & MASK), + _store_digit(carry)], sign, 2) + else: + return rbigint([_store_digit(ival & MASK)], sign, 1) - t = ival - ndigits = 0 - while t: - ndigits += 1 - t >>= SHIFT - v = rbigint([NULLDIGIT] * ndigits, sign, ndigits) - t = ival - p = 0 - while t: - v.setdigit(p, t) - t >>= SHIFT - p += 1 - - return v - + @staticmethod def frombool(b): # This function is marked as pure, so you must not call it and @@ -1107,10 +1088,6 @@ def _x_sub(a, b): """ Subtract the absolute values of two integers. """ - # Special casing. - if a is b: - return NULLRBIGINT - size_a = a.numdigits() size_b = b.numdigits() sign = 1 @@ -1141,13 +1118,13 @@ borrow = a.udigit(i) - b.udigit(i) - borrow z.setdigit(i, borrow) borrow >>= SHIFT - borrow &= 1 # Keep only one sign bit + #borrow &= 1 # Keep only one sign bit i += 1 while i < size_a: borrow = a.udigit(i) - borrow z.setdigit(i, borrow) borrow >>= SHIFT - borrow &= 1 + #borrow &= 1 i += 1 assert borrow == 0 From noreply at buildbot.pypy.org Mon May 27 21:36:36 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 27 May 2013 21:36:36 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: simplify: rearrange so _compute_value always gets a space, just avoid calling Message-ID: <20130527193636.51C4B1C1464@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64592:38b554a7b5de Date: 2013-05-27 12:32 -0700 http://bitbucket.org/pypy/pypy/changeset/38b554a7b5de/ Log: simplify: rearrange so _compute_value always gets a space, just avoid calling it in __str__ if we lack one diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -60,7 +60,9 @@ "NOT_RPYTHON: Convenience for tracebacks." s = self._w_value if self.__class__ is not OperationError and s is None: - s = self._compute_value() + space = getattr(self.w_type, 'space') + if space is not None: + s = self._compute_value(space) return '[%s: %s]' % (self.w_type, s) def errorstr(self, space, use_repr=False): @@ -267,11 +269,11 @@ def get_w_value(self, space): w_value = self._w_value if w_value is None: - value = self._compute_value() + value = self._compute_value(space) self._w_value = w_value = space.wrap(value) return w_value - def _compute_value(self): + def _compute_value(self, space): raise NotImplementedError def get_traceback(self): @@ -298,17 +300,6 @@ """ self._application_traceback = traceback -def _space_from_type(w_type): - """Grab a space if a W_TypeObject, or None""" - from pypy.objspace.std.typeobject import W_TypeObject - # HACK: isinstance(w_type, W_TypeObject) won't translate under the - # fake objspace, but w_type.__class__ is W_TypeObject does and short - # circuits to a False constant there, causing the isinstance to be - # ignored =[ - if (w_type is not None and w_type.__class__ is W_TypeObject and - isinstance(w_type, W_TypeObject)): - return w_type.space - # ____________________________________________________________ # optimization only: avoid the slowest operation -- the string # formatting with '%' -- in the common case were we don't @@ -339,25 +330,6 @@ assert len(formats) > 0, "unsupported: no % command found" return tuple(parts), tuple(formats) -def _format_NT(space, fmt, w_value): - """Process operationerrfmt's %N/T formats""" - if space is not None: - if fmt == 'T': - w_value = space.type(w_value) - return w_value.getname(space) - elif not we_are_translated(): - # may not be able to grab space due to testing environments, - # fallback - if fmt == 'T': - tp = type(w_value) - typedef = getattr(tp, 'typedef', None) - return tp.__name__ if typedef is None else typedef.name - for attr in 'name', '__name__': - name = getattr(w_value, attr, None) - if name is not None: - return name - return '?' - def get_operrcls2(valuefmt): strings, formats = decompose_valuefmt(valuefmt) assert len(strings) == len(formats) + 1 @@ -377,17 +349,18 @@ setattr(self, attr, args[i]) assert w_type is not None - def _compute_value(self): + def _compute_value(self, space): lst = [None] * (len(formats) + len(formats) + 1) for i, fmt, attr in entries: - string = self.xstrings[i] + lst[i + i] = self.xstrings[i] value = getattr(self, attr) - lst[i+i] = string if fmt in 'NT': - lst[i+i+1] = _format_NT(_space_from_type(self.w_type), - fmt, value) + if fmt == 'T': + value = space.type(value) + result = value.getname(space) else: - lst[i+i+1] = str(value) + result = str(value) + lst[i + i + 1] = result lst[-1] = self.xstrings[-1] return ''.join(lst) # diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -12,22 +12,22 @@ assert (decompose_valuefmt("%s%d%%%s") == (("", "", "%", ""), ('s', 'd', 's'))) -def test_get_operrcls2(): +def test_get_operrcls2(space): cls, strings = get_operrcls2('abc %s def %d') assert strings == ("abc ", " def ", "") assert issubclass(cls, OperationError) inst = cls("w_type", strings, "hello", 42) - assert inst._compute_value() == "abc hello def 42" + assert inst._compute_value(space) == "abc hello def 42" cls2, strings2 = get_operrcls2('a %s b %d c') assert cls2 is cls # caching assert strings2 == ("a ", " b ", " c") -def test_operationerrfmt(): +def test_operationerrfmt(space): operr = operationerrfmt("w_type", "abc %s def %d", "foo", 42) assert isinstance(operr, OperationError) assert operr.w_type == "w_type" assert operr._w_value is None - assert operr._compute_value() == "abc foo def 42" + assert operr._compute_value(space) == "abc foo def 42" operr2 = operationerrfmt("w_type2", "a %s b %d c", "bar", 43) assert operr2.__class__ is operr.__class__ operr3 = operationerrfmt("w_type2", "a %s b %s c", "bar", "4b") @@ -37,29 +37,29 @@ operr = operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", space.wrap('foo'), 'foo') - assert operr._compute_value() == "'str' object has no attribute 'foo'" + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" operr = operationerrfmt("w_type", "'%T' object has no attribute '%s'", space.wrap('foo'), 'foo') - assert operr._compute_value() == "'str' object has no attribute 'foo'" + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" def test_operationerrfmt_N(space): operr = operationerrfmt(space.w_AttributeError, "'%N' object has no attribute '%s'", space.type(space.wrap('foo')), 'foo') - assert operr._compute_value() == "'str' object has no attribute 'foo'" + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" operr = operationerrfmt("w_type", "'%N' object has no attribute '%s'", space.type(space.wrap('foo')), 'foo') - assert operr._compute_value() == "'str' object has no attribute 'foo'" + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" operr = operationerrfmt(space.w_AttributeError, "'%N' object has no attribute '%s'", space.wrap('foo'), 'foo') - assert operr._compute_value() == "'?' object has no attribute 'foo'" + assert operr._compute_value(space) == "'?' object has no attribute 'foo'" operr = operationerrfmt("w_type", "'%N' object has no attribute '%s'", space.wrap('foo'), 'foo') - assert operr._compute_value() == "'?' object has no attribute 'foo'" + assert operr._compute_value(space) == "'?' object has no attribute 'foo'" def test_operationerrfmt_empty(): py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") From noreply at buildbot.pypy.org Mon May 27 21:36:35 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 27 May 2013 21:36:35 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: merge default Message-ID: <20130527193635.4177B1C1442@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64591:0e147cc62211 Date: 2013-05-27 12:16 -0700 http://bitbucket.org/pypy/pypy/changeset/0e147cc62211/ Log: merge default diff too long, truncating to 2000 out of 2164 lines diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py --- a/lib-python/2.7/logging/__init__.py +++ b/lib-python/2.7/logging/__init__.py @@ -134,20 +134,22 @@ DEBUG = 10 NOTSET = 0 -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO : 'INFO', - DEBUG : 'DEBUG', - NOTSET : 'NOTSET', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARNING, - 'WARNING' : WARNING, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'NOTSET' : NOTSET, +_levelToName = { + CRITICAL: 'CRITICAL', + ERROR: 'ERROR', + WARNING: 'WARNING', + INFO: 'INFO', + DEBUG: 'DEBUG', + NOTSET: 'NOTSET', +} +_nameToLevel = { + 'CRITICAL': CRITICAL, + 'ERROR': ERROR, + 'WARN': WARNING, + 'WARNING': WARNING, + 'INFO': INFO, + 'DEBUG': DEBUG, + 'NOTSET': NOTSET, } def getLevelName(level): @@ -164,7 +166,7 @@ Otherwise, the string "Level %s" % level is returned. """ - return _levelNames.get(level, ("Level %s" % level)) + return _levelToName.get(level, ("Level %s" % level)) def addLevelName(level, levelName): """ @@ -174,8 +176,8 @@ """ _acquireLock() try: #unlikely to cause an exception, but you never know... - _levelNames[level] = levelName - _levelNames[levelName] = level + _levelToName[level] = levelName + _nameToLevel[levelName] = level finally: _releaseLock() @@ -183,9 +185,9 @@ if isinstance(level, int): rv = level elif str(level) == level: - if level not in _levelNames: + if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) - rv = _levelNames[level] + rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv @@ -277,7 +279,7 @@ self.lineno = lineno self.funcName = func self.created = ct - self.msecs = (ct - long(ct)) * 1000 + self.msecs = (ct - int(ct)) * 1000 self.relativeCreated = (self.created - _startTime) * 1000 if logThreads and thread: self.thread = thread.get_ident() diff --git a/lib-python/2.7/logging/config.py b/lib-python/2.7/logging/config.py --- a/lib-python/2.7/logging/config.py +++ b/lib-python/2.7/logging/config.py @@ -156,7 +156,7 @@ h = klass(*args) if "level" in opts: level = cp.get(sectname, "level") - h.setLevel(logging._levelNames[level]) + h.setLevel(level) if len(fmt): h.setFormatter(formatters[fmt]) if issubclass(klass, logging.handlers.MemoryHandler): @@ -187,7 +187,7 @@ opts = cp.options(sectname) if "level" in opts: level = cp.get(sectname, "level") - log.setLevel(logging._levelNames[level]) + log.setLevel(level) for h in root.handlers[:]: root.removeHandler(h) hlist = cp.get(sectname, "handlers") @@ -237,7 +237,7 @@ existing.remove(qn) if "level" in opts: level = cp.get(sectname, "level") - logger.setLevel(logging._levelNames[level]) + logger.setLevel(level) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate diff --git a/lib-python/2.7/test/test_logging.py b/lib-python/2.7/test/test_logging.py --- a/lib-python/2.7/test/test_logging.py +++ b/lib-python/2.7/test/test_logging.py @@ -65,7 +65,8 @@ self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] self.saved_loggers = logger_dict.copy() - self.saved_level_names = logging._levelNames.copy() + self.saved_name_to_level = logging._nameToLevel.copy() + self.saved_level_to_name = logging._levelToName.copy() finally: logging._releaseLock() @@ -97,8 +98,10 @@ self.root_logger.setLevel(self.original_logging_level) logging._acquireLock() try: - logging._levelNames.clear() - logging._levelNames.update(self.saved_level_names) + logging._levelToName.clear() + logging._levelToName.update(self.saved_level_to_name) + logging._nameToLevel.clear() + logging._nameToLevel.update(self.saved_name_to_level) logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -16,6 +16,11 @@ else: return space.int_w(w_size) +def unsupported(space, message): + w_exc = space.getattr(space.getbuiltinmodule('_io'), + space.wrap('UnsupportedOperation')) + return OperationError(w_exc, space.wrap(message)) + # May be called with any object def check_readable_w(space, w_obj): if not space.is_true(space.call_method(w_obj, 'readable')): @@ -86,6 +91,9 @@ # attribute as returned by whatever subclass. return self.__IOBase_closed + def _unsupportedoperation(self, space, message): + raise unsupported(space, message) + def _check_closed(self, space, message=None): if message is None: message = "I/O operation on closed file" @@ -111,9 +119,18 @@ space.w_ValueError, space.wrap("I/O operation on closed file")) + def seek_w(self, space, w_offset, w_whence=None): + self._unsupportedoperation(space, "seek") + def tell_w(self, space): return space.call_method(self, "seek", space.wrap(0), space.wrap(1)) + def truncate_w(self, space, w_size=None): + self._unsupportedoperation(space, "truncate") + + def fileno_w(self, space): + self._unsupportedoperation(space, "fileno") + def enter_w(self, space): self._check_closed(space) return space.wrap(self) @@ -248,11 +265,15 @@ next = interp2app(W_IOBase.next_w), close = interp2app(W_IOBase.close_w), flush = interp2app(W_IOBase.flush_w), + seek = interp2app(W_IOBase.seek_w), tell = interp2app(W_IOBase.tell_w), + truncate = interp2app(W_IOBase.truncate_w), + fileno = interp2app(W_IOBase.fileno_w), isatty = interp2app(W_IOBase.isatty_w), readable = interp2app(W_IOBase.readable_w), writable = interp2app(W_IOBase.writable_w), seekable = interp2app(W_IOBase.seekable_w), + _checkReadable = interp2app(check_readable_w), _checkWritable = interp2app(check_writable_w), _checkSeekable = interp2app(check_seekable_w), diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -196,11 +196,6 @@ def __init__(self, space): W_IOBase.__init__(self, space) - def _unsupportedoperation(self, space, message): - w_exc = space.getattr(space.getbuiltinmodule('_io'), - space.wrap('UnsupportedOperation')) - raise OperationError(w_exc, space.wrap(message)) - def read_w(self, space, w_size=None): self._unsupportedoperation(space, "read") diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -43,6 +43,13 @@ import _io e = _io.UnsupportedOperation("seek") + def test_default_implementations(self): + import _io + file = _io._IOBase() + raises(_io.UnsupportedOperation, file.seek, 0, 1) + raises(_io.UnsupportedOperation, file.fileno) + raises(_io.UnsupportedOperation, file.truncate) + def test_blockingerror(self): import _io try: diff --git a/pypy/module/_io/test/test_textio.py b/pypy/module/_io/test/test_textio.py --- a/pypy/module/_io/test/test_textio.py +++ b/pypy/module/_io/test/test_textio.py @@ -26,6 +26,14 @@ assert t.readable() assert t.seekable() + def test_default_implementations(self): + import _io + file = _io._TextIOBase() + raises(_io.UnsupportedOperation, file.read) + raises(_io.UnsupportedOperation, file.seek, 0) + raises(_io.UnsupportedOperation, file.readline) + raises(_io.UnsupportedOperation, file.detach) + def test_unreadable(self): import _io class UnReadable(_io.BytesIO): diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -254,6 +254,8 @@ descr__new__, _get_dtype = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): + _attrs_ = ['ofs', 'dtype', 'arr'] + _immutable_fields_ = ['ofs'] def __init__(self, arr, ofs, dtype): self.arr = arr # we have to keep array alive self.ofs = ofs diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -786,7 +786,7 @@ def test_create_subarrays(self): from numpypy import dtype - d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + d = dtype([("x", "float", (2,)), ("y", "int64", (2,))]) assert d.itemsize == 32 assert d.name == "void256" keys = d.fields.keys() diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2715,7 +2715,7 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") @@ -2735,7 +2735,7 @@ def test_multidim_subarray(self): from numpypy import dtype, array - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -1705,8 +1705,10 @@ def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match + from interp_dtype import W_Dtype items_w = space.fixedview(w_items) subdtype = dtype.subdtype + assert isinstance(subdtype, W_Dtype) itemtype = subdtype.itemtype if len(shape) <= 1: for i in range(len(items_w)): diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT, VOID from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -27,6 +27,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.arm import callbuilder class AssemblerARM(ResOpAssembler): @@ -934,23 +935,6 @@ asm_math_operations[oopspecindex](self, op, arglocs, regalloc, fcond) return fcond - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 4: - return - if size == 1: - if not signed: # unsigned char - self.mc.AND_ri(resloc.value, resloc.value, 0xFF) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 24) - self.mc.ASR_ri(resloc.value, resloc.value, 24) - elif size == 2: - if not signed: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.LSR_ri(resloc.value, resloc.value, 16) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.ASR_ri(resloc.value, resloc.value, 16) - def patch_trace(self, faildescr, looptoken, bridge_addr, regalloc): b = InstrBuilder(self.cpu.cpuinfo.arch_version) patch_addr = faildescr._arm_failure_recovery_block @@ -1012,20 +996,32 @@ mc.gen_load_int(helper.value, ofs, cond=cond) mc.STR_rr(source.value, base.value, helper.value, cond=cond) + def get_tmp_reg(self, forbidden_regs=None): + if forbidden_regs is None: + return r.ip, False + for x in [r.ip, r.lr]: + if x not in forbidden_regs: + return x, False + # pick some reg, that we need to save + for x in r.all_regs: + if x not in forbidden_regs: + return x, True + assert 0 + def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL): - if not loc.is_reg() and not (loc.is_stack() and loc.type != FLOAT): + if loc.type == FLOAT: raise AssertionError("invalid target for move from imm value") if loc.is_reg(): new_loc = loc - elif loc.is_stack(): - self.mc.PUSH([r.lr.value], cond=cond) + elif loc.is_stack() or loc.is_raw_sp(): new_loc = r.lr else: raise AssertionError("invalid target for move from imm value") self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond) if loc.is_stack(): self.regalloc_mov(new_loc, loc) - self.mc.POP([r.lr.value], cond=cond) + elif loc.is_raw_sp(): + self.store_reg(self.mc, new_loc, r.sp, loc.value, cond=cond, helper=r.ip) def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_imm(): @@ -1034,60 +1030,77 @@ self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond) elif loc.is_stack() and loc.type != FLOAT: # spill a core register - if prev_loc is r.ip: - temp = r.lr - else: - temp = r.ip + temp, save = self.get_tmp_reg([prev_loc, loc]) offset = loc.value is_imm = check_imm_arg(offset, size=0xFFF) - if not is_imm: + if not is_imm and save: self.mc.PUSH([temp.value], cond=cond) self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) - if not is_imm: + if not is_imm and save: self.mc.POP([temp.value], cond=cond) + elif loc.is_raw_sp() and loc.type != FLOAT: + temp, save = self.get_tmp_reg([prev_loc]) + assert not save + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) else: assert 0, 'unsupported case' def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL): - # disabled for now, has side effects in combination with remap_frame_layout when called from a jump - helper = None # self._regalloc.get_free_reg() + helper = None + offset = prev_loc.value + tmp = None if loc.is_reg(): assert prev_loc.type != FLOAT, 'trying to load from an \ incompatible location into a core register' - assert loc is not r.lr, 'lr is not supported as a target \ - when moving from the stack' # unspill a core register - offset = prev_loc.value is_imm = check_imm_arg(offset, size=0xFFF) - helper = r.lr if helper is None else helper - save_helper = not is_imm and helper is r.lr + helper, save = self.get_tmp_reg([loc]) + save_helper = not is_imm and save elif loc.is_vfp_reg(): assert prev_loc.type == FLOAT, 'trying to load from an \ incompatible location into a float register' # load spilled value into vfp reg - offset = prev_loc.value is_imm = check_imm_arg(offset) - helper = r.ip if helper is None else helper - save_helper = not is_imm and helper is r.ip + helper, save = self.get_tmp_reg() + save_helper = not is_imm and save + elif loc.is_raw_sp(): + assert (loc.type == prev_loc.type == FLOAT + or (loc.type != FLOAT and prev_loc.type != FLOAT)) + tmp = loc + if loc.is_float(): + loc = r.vfp_ip + else: + loc, save_helper = self.get_tmp_reg() + assert not save_helper + helper, save_helper = self.get_tmp_reg([loc]) + assert not save_helper else: assert 0, 'unsupported case' + if save_helper: self.mc.PUSH([helper.value], cond=cond) self.load_reg(self.mc, loc, r.fp, offset, cond=cond, helper=helper) if save_helper: self.mc.POP([helper.value], cond=cond) + if tmp and tmp.is_raw_sp(): + self.store_reg(self.mc, loc, r.sp, tmp.value, cond=cond, helper=helper) + def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_vfp_reg(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond) - self.load_reg(self.mc, loc, r.ip, 0, cond=cond) - self.mc.POP([r.ip.value], cond=cond) - elif loc.is_stack(): - self.regalloc_push(r.vfp_ip) + helper, save_helper = self.get_tmp_reg([loc]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, prev_loc.getint(), cond=cond) + self.load_reg(self.mc, loc, helper, 0, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) + elif loc.is_stack() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - self.regalloc_pop(r.vfp_ip) + elif loc.is_raw_sp() and loc.type == FLOAT: + self.regalloc_mov(prev_loc, r.vfp_ip, cond) + self.regalloc_mov(r.vfp_ip, loc, cond) else: assert 0, 'unsupported case' @@ -1100,11 +1113,11 @@ # spill vfp register offset = loc.value is_imm = check_imm_arg(offset) - if not is_imm: - self.mc.PUSH([r.ip.value], cond=cond) - self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond) - if not is_imm: - self.mc.POP([r.ip.value], cond=cond) + self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) + elif loc.is_raw_sp(): + assert loc.type == FLOAT, 'trying to store to an \ + incompatible location from a float register' + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' @@ -1120,6 +1133,8 @@ self._mov_imm_float_to_loc(prev_loc, loc, cond) elif prev_loc.is_vfp_reg(): self._mov_vfp_reg_to_loc(prev_loc, loc, cond) + elif prev_loc.is_raw_sp(): + assert 0, 'raw sp locs are not supported as source loc' else: assert 0, 'unsupported case' mov_loc_loc = regalloc_mov @@ -1131,23 +1146,29 @@ if vfp_loc.is_vfp_reg(): self.mc.VMOV_rc(reg1.value, reg2.value, vfp_loc.value, cond=cond) elif vfp_loc.is_imm_float(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, vfp_loc.getint(), cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, vfp_loc.getint(), cond=cond) # we need to load one word to loc and one to loc+1 which are # two 32-bit core registers - self.mc.LDR_ri(reg1.value, r.ip.value, cond=cond) - self.mc.LDR_ri(reg2.value, r.ip.value, imm=WORD, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + self.mc.LDR_ri(reg1.value, helper.value, cond=cond) + self.mc.LDR_ri(reg2.value, helper.value, imm=WORD, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif vfp_loc.is_stack() and vfp_loc.type == FLOAT: # load spilled vfp value into two core registers offset = vfp_loc.value if not check_imm_arg(offset, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.LDR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.LDR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.LDR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.LDR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.LDR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.LDR_ri(reg2.value, r.fp.value, @@ -1165,12 +1186,15 @@ # move from two core registers to a float stack location offset = vfp_loc.value if not check_imm_arg(offset + WORD, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.STR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.STR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.STR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.STR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.STR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.STR_ri(reg2.value, r.fp.value, @@ -1417,6 +1441,26 @@ # return shiftsize + def simple_call(self, fnloc, arglocs, result_loc=r.r0): + if result_loc is None: + result_type = VOID + result_size = 0 + elif result_loc.is_vfp_reg(): + result_type = FLOAT + result_size = DOUBLE_WORD + else: + result_type = INT + result_size = WORD + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() + + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs) + cb.emit_no_collect() + + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/callbuilder.py @@ -0,0 +1,304 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT, REF +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.assembler import saved_registers +from rpython.jit.backend.arm.helper.regalloc import check_imm_arg + + +class ARMCallbuilder(AbstractCallBuilder): + def __init__(self, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) + self.current_sp = 0 + + def push_gcmap(self): + assert not self.is_call_release_gil + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r0], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + self.asm.pop_gcmap(self.mc) + + def emit_raw_call(self): + #the actual call + if self.fnloc.is_imm(): + self.mc.BL(self.fnloc.value) + return + if self.fnloc.is_stack(): + self.asm.mov_loc_loc(self.fnloc, r.ip) + self.fnloc = r.ip + assert self.fnloc.is_reg() + self.mc.BLX(self.fnloc.value) + + def restore_stack_pointer(self): + # readjust the sp in case we passed some args on the stack + assert self.current_sp % 8 == 0 # sanity check + if self.current_sp != 0: + self._adjust_sp(self.current_sp) + self.current_sp = 0 + + def _push_stack_args(self, stack_args, on_stack): + assert on_stack % 8 == 0 + self._adjust_sp(-on_stack) + self.current_sp = on_stack + ofs = 0 + for i, arg in enumerate(stack_args): + if arg is not None: + sp_loc = RawSPStackLocation(ofs, arg.type) + self.asm.regalloc_mov(arg, sp_loc) + ofs += sp_loc.width + else: # alignment word + ofs += WORD + + def _adjust_sp(self, n): + # adjust the current stack pointer by n bytes + if n > 0: + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value) + else: + n = abs(n) + if check_imm_arg(n): + self.mc.SUB_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value) + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + + def call_releasegil_addr_and_move_real_arguments(self): + assert not self.asm._is_asmgcc() + from rpython.jit.backend.arm.regalloc import CoreRegisterManager + with saved_registers(self.mc, + CoreRegisterManager.save_around_call_regs): + self.mc.BL(self.asm.releasegil_addr) + + if not we_are_translated(): # for testing: we should not access + self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got + assert not self.asm._is_asmgcc() + gpr_to_save, vfp_to_save = self.get_result_locs() + with saved_registers(self.mc, gpr_to_save, vfp_to_save): + self.mc.BL(self.asm.reacqgil_addr) + + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again + + # for shadowstack, done for us by _reload_frame_if_necessary() + + def get_result_locs(self): + raise NotImplementedError + + def _ensure_result_bit_extension(self, resloc, size, signed): + if size == 4: + return + if size == 1: + if not signed: # unsigned char + self.mc.AND_ri(resloc.value, resloc.value, 0xFF) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 24) + self.mc.ASR_ri(resloc.value, resloc.value, 24) + elif size == 2: + if not signed: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.LSR_ri(resloc.value, resloc.value, 16) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.ASR_ri(resloc.value, resloc.value, 16) + + + +class SoftFloatCallBuilder(ARMCallbuilder): + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [r.r0, r.r1], [] + assert self.resloc.is_reg() + return [r.r0], [] + + def load_result(self): + # ensure the result is wellformed and stored in the correct location + resloc = self.resloc + if resloc is None: + return + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + # move result to the allocated register + if resloc is not r.r0: + self.asm.mov_loc_loc(r.r0, resloc) + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + + def _collect_and_push_stack_args(self, arglocs): + n_args = len(arglocs) + reg_args = count_reg_args(arglocs) + # all arguments past the 4th go on the stack + # first we need to prepare the list so it stays aligned + stack_args = [] + count = 0 + on_stack = 0 + if n_args > reg_args: + for i in range(reg_args, n_args): + arg = arglocs[i] + if arg.type != FLOAT: + count += 1 + on_stack += 1 + else: + on_stack += 2 + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + if count % 2 != 0: + on_stack += 1 + stack_args.append(None) + if on_stack > 0: + self._push_stack_args(stack_args, on_stack*WORD) + + def prepare_arguments(self): + arglocs = self.arglocs + reg_args = count_reg_args(arglocs) + self._collect_and_push_stack_args(arglocs) + # collect variables that need to go in registers and the registers they + # will be stored in + num = 0 + count = 0 + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(reg_args): + arg = arglocs[i] + if arg.type == FLOAT and count % 2 != 0: + num += 1 + count = 0 + reg = r.caller_resp[num] + + if arg.type == FLOAT: + float_locs.append((arg, reg)) + else: + non_float_locs.append(arg) + non_float_regs.append(reg) + + if arg.type == FLOAT: + num += 2 + else: + num += 1 + count += 1 + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in r.argument_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + + for loc, reg in float_locs: + self.asm.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) + +class HardFloatCallBuilder(ARMCallbuilder): + + def prepare_arguments(self): + non_float_locs = [] + non_float_regs = [] + float_locs = [] + float_regs = [] + stack_args = [] + + arglocs = self.arglocs + argtypes = self.argtypes + + count = 0 # stack alignment counter + on_stack = 0 + for arg in arglocs: + if arg.type != FLOAT: + if len(non_float_regs) < len(r.argument_regs): + reg = r.argument_regs[len(non_float_regs)] + non_float_locs.append(arg) + non_float_regs.append(reg) + else: # non-float argument that needs to go on the stack + count += 1 + on_stack += 1 + stack_args.append(arg) + else: + if len(float_regs) < len(r.vfp_argument_regs): + reg = r.vfp_argument_regs[len(float_regs)] + float_locs.append(arg) + float_regs.append(reg) + else: # float argument that needs to go on the stack + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + on_stack += 2 + # align the stack + if count % 2 != 0: + stack_args.append(None) + on_stack += 1 + self._push_stack_args(stack_args, on_stack*WORD) + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + # remap values stored in vfp registers + remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip) + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None and resloc.is_reg(): + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [], [r.d0] + assert self.resloc.is_reg() + return [r.r0], [] + + +def get_callbuilder(cpu, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + if cpu.cpuinfo.hf_abi: + return HardFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) + else: + return SoftFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) diff --git a/rpython/jit/backend/arm/locations.py b/rpython/jit/backend/arm/locations.py --- a/rpython/jit/backend/arm/locations.py +++ b/rpython/jit/backend/arm/locations.py @@ -12,6 +12,9 @@ def is_stack(self): return False + def is_raw_sp(self): + return False + def is_reg(self): return False @@ -145,7 +148,27 @@ return self.position + 10000 def is_float(self): - return type == FLOAT + return self.type == FLOAT + +class RawSPStackLocation(AssemblerLocation): + _immutable_ = True + + def __init__(self, sp_offset, type=INT): + if type == FLOAT: + self.width = DOUBLE_WORD + else: + self.width = WORD + self.value = sp_offset + self.type = type + + def __repr__(self): + return 'SP(%s)+%d' % (self.type, self.value,) + + def is_raw_sp(self): + return True + + def is_float(self): + return self.type == FLOAT def imm(i): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -13,8 +13,7 @@ gen_emit_float_cmp_op, gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, - saved_registers, - count_reg_args) + saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout @@ -31,8 +30,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.arm import callbuilder class ArmGuardToken(GuardToken): @@ -339,217 +337,36 @@ return fcond def emit_op_call(self, op, arglocs, regalloc, fcond): - resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + return self._emit_call(op, arglocs, fcond=fcond) + + def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): + # args = [resloc, size, sign, args...] + from rpython.jit.backend.llsupport.descr import CallDescr + + cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3], arglocs[4:], arglocs[0]) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - cond = self._emit_call(adr, arglist, - fcond, resloc, (size, signed)) - return cond + assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[1] + assert sizeloc.is_imm() + cb.ressize = sizeloc.value + signloc = arglocs[2] + assert signloc.is_imm() + cb.ressign = signloc.value - def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None, - result_info=(-1, -1), - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True): - if self.cpu.cpuinfo.hf_abi: - stack_args, adr = self._setup_call_hf(adr, arglocs, fcond, - resloc, result_info) + if is_call_release_gil: + cb.emit_call_release_gil() else: - stack_args, adr = self._setup_call_sf(adr, arglocs, fcond, - resloc, result_info) - - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - #the actual call - if adr.is_imm(): - self.mc.BL(adr.value) - elif adr.is_stack(): - self.mov_loc_loc(adr, r.ip) - adr = r.ip - else: - assert adr.is_reg() - if adr.is_reg(): - self.mc.BLX(adr.value) - self._restore_sp(stack_args, fcond) - - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg() and not self.cpu.cpuinfo.hf_abi: - # move result to the allocated register - self.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg() and result_info != (-1, -1): - self._ensure_result_bit_extension(resloc, result_info[0], - result_info[1]) - if can_collect: - self._reload_frame_if_necessary(self.mc) - self.pop_gcmap(self.mc) + cb.emit() return fcond - def _restore_sp(self, stack_args, fcond): - # readjust the sp in case we passed some args on the stack - if len(stack_args) > 0: - n = 0 - for arg in stack_args: - if arg is None or arg.type != FLOAT: - n += WORD - else: - n += DOUBLE_WORD - self._adjust_sp(-n, fcond=fcond) - assert n % 8 == 0 # sanity check - - def _adjust_sp(self, n, cb=None, fcond=c.AL, base_reg=r.sp): - if cb is None: - cb = self.mc - if n < 0: - n = -n - rev = True - else: - rev = False - if n <= 0xFF and fcond == c.AL: - if rev: - cb.ADD_ri(r.sp.value, base_reg.value, n) - else: - cb.SUB_ri(r.sp.value, base_reg.value, n) - else: - cb.gen_load_int(r.ip.value, n, cond=fcond) - if rev: - cb.ADD_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - else: - cb.SUB_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - - - def _collect_stack_args_sf(self, arglocs): - n_args = len(arglocs) - reg_args = count_reg_args(arglocs) - # all arguments past the 4th go on the stack - # first we need to prepare the list so it stays aligned - stack_args = [] - count = 0 - if n_args > reg_args: - for i in range(reg_args, n_args): - arg = arglocs[i] - if arg.type != FLOAT: - count += 1 - else: - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - if count % 2 != 0: - stack_args.append(None) - return stack_args - - def _push_stack_args(self, stack_args): - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.regalloc_push(arg) - - def _setup_call_sf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - reg_args = count_reg_args(arglocs) - stack_args = self._collect_stack_args_sf(arglocs) - self._push_stack_args(stack_args) - # collect variables that need to go in registers and the registers they - # will be stored in - num = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - for i in range(reg_args): - arg = arglocs[i] - if arg.type == FLOAT and count % 2 != 0: - num += 1 - count = 0 - reg = r.caller_resp[num] - - if arg.type == FLOAT: - float_locs.append((arg, reg)) - else: - non_float_locs.append(arg) - non_float_regs.append(reg) - - if arg.type == FLOAT: - num += 2 - else: - num += 1 - count += 1 - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - - for loc, reg in float_locs: - self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) - return stack_args, adr - - def _setup_call_hf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - count = 0 # stack alignment counter - for arg in arglocs: - if arg.type != FLOAT: - if len(non_float_regs) < len(r.argument_regs): - reg = r.argument_regs[len(non_float_regs)] - non_float_locs.append(arg) - non_float_regs.append(reg) - else: # non-float argument that needs to go on the stack - count += 1 - stack_args.append(arg) - else: - if len(float_regs) < len(r.vfp_argument_regs): - reg = r.vfp_argument_regs[len(float_regs)] - float_locs.append(arg) - float_regs.append(reg) - else: # float argument that needs to go on the stack - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - # align the stack - if count % 2 != 0: - stack_args.append(None) - self._push_stack_args(stack_args) - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - # remap values stored in vfp registers - remap_frame_layout(self, float_locs, float_regs, r.vfp_ip) - - return stack_args, adr - def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs - self.mov_loc_loc(argloc, resloc) + if argloc is not resloc: + self.mov_loc_loc(argloc, resloc) return fcond emit_op_cast_ptr_to_int = emit_op_same_as @@ -1037,9 +854,8 @@ length_loc = bytes_loc # call memcpy() regalloc.before_call() - self._emit_call(imm(self.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.simple_call_no_collect(imm(self.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.rm.possibly_free_var(length_box) regalloc.rm.possibly_free_var(dstaddr_box) regalloc.rm.possibly_free_var(srcaddr_box) @@ -1127,14 +943,14 @@ vloc = imm(0) self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op), guard_op.numargs()) + regalloc._prepare_guard(guard_op)) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self._emit_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], result_loc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self._emit_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, result_loc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') @@ -1213,20 +1029,14 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed)) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) + self._emit_call(op, callargs, fcond=fcond) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def _emit_guard_may_force(self, guard_op, arglocs, numargs): + def _emit_guard_may_force(self, guard_op, arglocs): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) @@ -1235,68 +1045,14 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): - + numargs = op.numargs() + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - # do the call - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed), - can_collect=False) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - self.pop_gcmap(self.mc) # remove the gcmap saved above - - self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) + self._emit_call(op, callargs, is_call_release_gil=True) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): - # Save caller saved registers and do the call - # NOTE: We assume that the floating point registers won't be modified. - assert gcrootmap.is_shadow_stack - with saved_registers(self.mc, regalloc.rm.save_around_call_regs): - self._emit_call(imm(self.releasegil_addr), [], - fcond, can_collect=False) - - def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): - # save the previous result into the stack temporarily, in case it is in - # a caller saved register. - # NOTE: like with call_release_gil(), we assume that we don't need to - # save vfp regs in this case. Besides the result location - regs_to_save = [] - vfp_regs_to_save = [] - if save_loc and save_loc in regalloc.rm.save_around_call_regs: - regs_to_save.append(save_loc) - regs_to_save.append(r.ip) # for alingment - elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs: - vfp_regs_to_save.append(save_loc) - assert gcrootmap.is_shadow_stack - # call the reopenstack() function (also reacquiring the GIL) - with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): - self._emit_call(imm(self.reacqgil_addr), [], fcond, - can_collect=False) - self._reload_frame_if_necessary(self.mc) - def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -34,6 +34,7 @@ from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr from rpython.rlib.rarithmetic import r_uint +from rpython.jit.backend.llsupport.descr import CallDescr # xxx hack: set a default value for TargetToken._ll_loop_code. If 0, we know @@ -555,9 +556,27 @@ return self._prepare_call(op) def _prepare_call(self, op, force_store=[], save_all_regs=False): - args = [None] * (op.numargs() + 1) + args = [None] * (op.numargs() + 3) + calldescr = op.getdescr() + assert isinstance(calldescr, CallDescr) + assert len(calldescr.arg_classes) == op.numargs() - 1 + for i in range(op.numargs()): - args[i + 1] = self.loc(op.getarg(i)) + args[i + 3] = self.loc(op.getarg(i)) + + size = calldescr.get_result_size() + sign = calldescr.is_result_signed() + if sign: + sign_loc = imm(1) + else: + sign_loc = imm(0) + args[1] = imm(size) + args[2] = sign_loc + + args[0] = self._call(op, args, force_store, save_all_regs) + return args + + def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls self.vfprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -565,11 +584,11 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(save_all_regs=save_all_regs) + self.before_call_called = True + resloc = None if op.result: resloc = self.after_call(op.result) - args[0] = resloc - self.before_call_called = True - return args + return resloc def prepare_op_call_malloc_gc(self, op, fcond): return self._prepare_call(op) @@ -1153,9 +1172,9 @@ def prepare_guard_call_assembler(self, op, guard_op, fcond): locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) - call_locs = self._prepare_call(op, save_all_regs=True) + resloc = self._call(op, locs + [tmploc], save_all_regs=True) self.possibly_free_vars(guard_op.getfailargs()) - return locs + [call_locs[0], tmploc] + return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -1,9 +1,10 @@ from rpython.rlib.objectmodel import instantiate from rpython.jit.backend.arm.assembler import AssemblerARM -from rpython.jit.backend.arm.locations import imm, ConstFloatLoc,\ - RegisterLocation, StackLocation, \ - VFPRegisterLocation, get_fp_offset -from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip +from rpython.jit.backend.arm.locations import imm, ConstFloatLoc +from rpython.jit.backend.arm.locations import RegisterLocation, StackLocation +from rpython.jit.backend.arm.locations import VFPRegisterLocation, get_fp_offset +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip, sp from rpython.jit.backend.arm.conditions import AL from rpython.jit.backend.arm.arch import WORD from rpython.jit.metainterp.history import FLOAT @@ -54,6 +55,12 @@ addr = int(value) # whatever return ConstFloatLoc(addr) +def raw_stack(i): + return RawSPStackLocation(i) + +def raw_stack_float(i): + return RawSPStackLocation(i, type=FLOAT) + class MockBuilder(object): def __init__(self): @@ -79,13 +86,13 @@ result = self.builder.instrs assert result == expected - -class TestRegallocMov(BaseMovTest): - def mov(self, a, b, expected=None): self.asm.regalloc_mov(a, b) self.validate(expected) + +class TestRegallocMov(BaseMovTest): + def test_mov_imm_to_reg(self): val = imm(123) reg = r(7) @@ -102,45 +109,37 @@ val = imm(100) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 100, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_stacklock(self): val = imm(65536) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 65536, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] - + ] self.mov(val, s, expected) def test_mov_imm_to_big_stacklock(self): val = imm(100) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 100, cond=AL), - mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 100, cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_big_stacklock(self): val = imm(65536) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 65536, cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_reg_to_reg(self): @@ -158,10 +157,10 @@ def test_mov_reg_to_big_stackloc(self): s = stack(8191) r6 = r(6) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r6.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r6, s, expected) def test_mov_stack_to_reg(self): @@ -174,10 +173,8 @@ s = stack(8191) r6 = r(6) expected = [ - mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 32940, cond=AL), - mi('LDR_rr', r6.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), + mi('gen_load_int', ip.value, 32940, cond=AL), + mi('LDR_rr', r6.value, fp.value, ip.value, cond=AL), ] self.mov(s, r6, expected) @@ -185,10 +182,9 @@ f = imm_float(3.5) reg = vfp(5) expected = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, f.value, cond=AL), mi('VLDR', 5, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(f, reg, expected) def test_mov_vfp_reg_to_vfp_reg(self): @@ -206,11 +202,11 @@ def test_mov_vfp_reg_to_large_stackloc(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_mov_stack_to_vfp_reg(self): @@ -222,11 +218,11 @@ def test_mov_big_stackloc_to_vfp_reg(self): reg = vfp(7) s = stack_float(800) - expected = [mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', reg.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(reg, s, expected) def test_unsopported_cases(self): @@ -265,8 +261,6 @@ py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), vfp(2))') py.test.raises(AssertionError, - 'self.asm.regalloc_mov(stack(1), lr)') - py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm(2))') py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), imm_float(2))') @@ -312,12 +306,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('LDR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=WORD, cond=AL), mi('LDR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(s, r1, r2, e) def test_from_imm_float(self): @@ -325,11 +318,10 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, i.value, cond=AL), mi('LDR_ri', r1.value, ip.value, cond=AL), mi('LDR_ri', r2.value, ip.value, imm=4, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(i, r1, r2, e) def test_unsupported(self): @@ -369,12 +361,11 @@ r1 = r(1) r2 = r(2) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', r1.value, fp.value, ip.value, cond=AL), mi('ADD_ri', ip.value, ip.value, imm=4, cond=AL), mi('STR_rr', r2.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.mov(r1, r2, s, e) def unsupported(self): @@ -408,10 +399,9 @@ def test_push_imm_float(self): f = imm_float(7) - e = [mi('PUSH', [ip.value], cond=AL), + e = [ mi('gen_load_int', ip.value, 7, cond=AL), mi('VLDR', vfp_ip.value, ip.value, imm=0, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL) ] self.push(f, e) @@ -426,10 +416,8 @@ def test_push_big_stack(self): s = stack(1025) e = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('LDR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL), mi('PUSH', [ip.value], cond=AL) ] self.push(s, e) @@ -450,11 +438,9 @@ def test_push_large_stackfloat(self): sf = stack_float(100) e = [ - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, sf.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VLDR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), mi('VPUSH', [vfp_ip.value], cond=AL), ] self.push(sf, e) @@ -486,10 +472,8 @@ s = stack(1200) e = [ mi('POP', [ip.value], cond=AL), - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, s.value, cond=AL), mi('STR_rr', ip.value, fp.value, lr.value, cond=AL), - mi('POP', [lr.value], cond=AL) ] self.pop(s, e) @@ -505,13 +489,88 @@ s = stack_float(1200) e = [ mi('VPOP', [vfp_ip.value], cond=AL), - mi('PUSH', [ip.value], cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('ADD_rr', ip.value, fp.value, ip.value, cond=AL), mi('VSTR', vfp_ip.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL)] + ] self.pop(s, e) def test_unsupported(self): py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm(1))') py.test.raises(AssertionError, 'self.asm.regalloc_pop(imm_float(1))') + +class TestRawStackLocs(BaseMovTest): + def test_unsupported(self): + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), imm_float(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), r(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), vfp(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(raw_stack(0), stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(imm(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(vfp(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(r(1), raw_stack_float(1))') + + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack_float(1), raw_stack(1))') + py.test.raises(AssertionError, 'self.asm.regalloc_mov(stack(1), raw_stack_float(1))') + + def test_from_imm(self): + s = raw_stack(1024) + i = imm(999) + e = [ + mi('gen_load_int', lr.value, i.value, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', lr.value, sp.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_vfp_imm(self): + s = raw_stack_float(1024) + i = imm_float(999) + e = [ + mi('gen_load_int', ip.value, i.value, cond=AL), + mi('VLDR', vfp_ip.value, ip.value, cond=AL, imm=0), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(i, s, e) + + def test_from_reg(self): + s = raw_stack(1024) + reg = r(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('STR_rr', reg.value, sp.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_reg(self): + s = raw_stack_float(1024) + reg = vfp(10) + e = [mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', reg.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_stack(self): + s = raw_stack(1024) + reg = stack(10) + e = [mi('LDR_ri', ip.value, fp.value, imm=216, cond=AL), + mi('gen_load_int', lr.value, s.value, cond=AL), + mi('STR_rr', ip.value, sp.value, lr.value, cond=AL), + ] + self.mov(reg, s, e) + + def test_from_vfp_stack(self): + s = raw_stack_float(1024) + reg = stack_float(10) + e = [mi('VLDR', vfp_ip.value, fp.value, imm=220, cond=AL), + mi('gen_load_int', ip.value, s.value, cond=AL), + mi('ADD_rr', ip.value, sp.value, ip.value, cond=AL), + mi('VSTR', vfp_ip.value, ip.value, cond=AL), + ] + self.mov(reg, s, e) diff --git a/rpython/jit/backend/arm/test/test_runner.py b/rpython/jit/backend/arm/test/test_runner.py --- a/rpython/jit/backend/arm/test/test_runner.py +++ b/rpython/jit/backend/arm/test/test_runner.py @@ -24,7 +24,7 @@ # for the individual tests see # ====> ../../test/runner_test.py - add_loop_instructions = ['ldr', 'mov', 'adds', 'cmp', 'beq', 'b'] + add_loop_instructions = ['ldr', 'adds', 'cmp', 'beq', 'b'] bridge_loop_instructions = ['ldr', 'mov', 'nop', 'cmp', 'bge', 'push', 'mov', 'mov', 'push', 'mov', 'mov', 'blx', 'mov', 'mov', 'bx'] 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 @@ -372,6 +372,9 @@ self.releasegil_addr = self.cpu.cast_ptr_to_int(releasegil_func) self.reacqgil_addr = self.cpu.cast_ptr_to_int(reacqgil_func) + def _is_asmgcc(self): + gcrootmap = self.cpu.gc_ll_descr.gcrootmap + return bool(gcrootmap) and not gcrootmap.is_shadow_stack def debug_bridge(descr_number, rawstart, codeendpos): diff --git a/rpython/jit/backend/llsupport/callbuilder.py b/rpython/jit/backend/llsupport/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/llsupport/callbuilder.py @@ -0,0 +1,92 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI + +class AbstractCallBuilder(object): + + # this is the calling convention (can be FFI_STDCALL on Windows) + callconv = FFI_DEFAULT_ABI + + # is it for the main CALL of a call_release_gil? + is_call_release_gil = False + + # this can be set to guide more complex calls: gives the detailed + # type of the arguments + argtypes = "" + ressign = False + + + def __init__(self, assembler, fnloc, arglocs, resloc, restype, ressize): + self.fnloc = fnloc + self.arglocs = arglocs + self.asm = assembler + self.mc = assembler.mc + self.resloc = resloc + self.restype = restype + self.ressize = ressize + + def emit_no_collect(self): + """Emit a call that cannot collect.""" + self.prepare_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.load_result() + + def emit(self): + """Emit a regular call; not for CALL_RELEASE_GIL.""" + self.prepare_arguments() + self.push_gcmap() + self.emit_raw_call() + self.restore_stack_pointer() + self.pop_gcmap() + self.load_result() + + def emit_call_release_gil(self): + """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr + and reacqgil_addr.""" + self.select_call_release_gil_mode() + self.prepare_arguments() + self.push_gcmap_for_call_release_gil() + self.call_releasegil_addr_and_move_real_arguments() + self.emit_raw_call() + self.restore_stack_pointer() + self.move_real_result_and_call_reacqgil_addr() + self.pop_gcmap() + self.load_result() + + def call_releasegil_addr_and_move_real_arguments(self): + raise NotImplementedError + + def move_real_result_and_call_reacqgil_addr(self): + raise NotImplementedError + + def select_call_release_gil_mode(self): + """Overridden in CallBuilder64""" + self.is_call_release_gil = True + + def prepare_arguments(self): + raise NotImplementedError + + def push_gcmap(self): + raise NotImplementedError + + def push_gcmap_for_call_release_gil(self): + assert self.is_call_release_gil + # we put the gcmap now into the frame before releasing the GIL, + # and pop it after reacquiring the GIL. The assumption + # is that this gcmap describes correctly the situation at any + # point in-between: all values containing GC pointers should + # be safely saved out of registers by now, and will not be + # manipulated by any of the following CALLs. + gcmap = self.asm._regalloc.get_gcmap(noregs=True) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + raise NotImplementedError + + def emit_raw_call(self): + raise NotImplementedError + + def restore_stack_pointer(self): + raise NotImplementedError + + def load_result(self): + raise NotImplementedError diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -999,10 +999,6 @@ self.implement_guard(guard_token, checkfalsecond) return genop_cmp_guard_float - def _is_asmgcc(self): - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - return bool(gcrootmap) and not gcrootmap.is_shadow_stack - def simple_call(self, fnloc, arglocs, result_loc=eax): if result_loc is xmm0: result_type = FLOAT diff --git a/rpython/jit/backend/x86/callbuilder.py b/rpython/jit/backend/x86/callbuilder.py --- a/rpython/jit/backend/x86/callbuilder.py +++ b/rpython/jit/backend/x86/callbuilder.py @@ -8,6 +8,7 @@ r12, r13, r14, r15, X86_64_SCRATCH_REG, X86_64_XMM_SCRATCH_REG, RegLoc, RawEspLoc, RawEbpLoc, imm, ImmedLoc) from rpython.jit.backend.x86.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder # darwin requires the stack to be 16 bytes aligned on calls. @@ -18,77 +19,30 @@ return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1) - -class AbstractCallBuilder(object): +class CallBuilderX86(AbstractCallBuilder): # max number of words we have room in esp; if we need more for # arguments, we need to decrease esp temporarily stack_max = PASS_ON_MY_FRAME - # this can be set to guide more complex calls: gives the detailed - # type of the arguments - argtypes = "" - ressign = False - - # this is the calling convention (can be FFI_STDCALL on Windows) - callconv = FFI_DEFAULT_ABI - - # is it for the main CALL of a call_release_gil? - is_call_release_gil = False - # set by save_result_value() tmpresloc = None - def __init__(self, assembler, fnloc, arglocs, resloc=eax, restype=INT, ressize=WORD): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) # Avoid tons of issues with a non-immediate fnloc by sticking it # as an extra argument if needed self.fnloc_is_immediate = isinstance(fnloc, ImmedLoc) - if self.fnloc_is_immediate: - self.fnloc = fnloc - self.arglocs = arglocs - else: + if not self.fnloc_is_immediate: + self.fnloc = None self.arglocs = arglocs + [fnloc] - self.asm = assembler - self.mc = assembler.mc - self.resloc = resloc - self.restype = restype - self.ressize = ressize self.current_esp = 0 # 0 or (usually) negative, counted in bytes - def emit_no_collect(self): - """Emit a call that cannot collect.""" - self.prepare_arguments() - self.emit_raw_call() - self.restore_esp() - self.load_result() - - def emit(self): - """Emit a regular call; not for CALL_RELEASE_GIL.""" - self.prepare_arguments() - self.push_gcmap() - self.emit_raw_call() - self.restore_esp() - self.pop_gcmap() - self.load_result() - - def emit_call_release_gil(self): - """Emit a CALL_RELEASE_GIL, including calls to releasegil_addr - and reacqgil_addr.""" - self.select_call_release_gil_mode() - self.prepare_arguments() - self.push_gcmap_for_call_release_gil() - self.call_releasegil_addr_and_move_real_arguments() - self.emit_raw_call() - self.restore_esp() - self.move_real_result_and_call_reacqgil_addr() - self.pop_gcmap() - self.load_result() - def select_call_release_gil_mode(self): """Overridden in CallBuilder64""" - self.is_call_release_gil = True + AbstractCallBuilder.select_call_release_gil_mode(self) if self.asm._is_asmgcc(): from rpython.memory.gctransform import asmgcroot From noreply at buildbot.pypy.org Mon May 27 22:29:39 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Mon, 27 May 2013 22:29:39 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Fix translation Message-ID: <20130527202939.21E851C13EB@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64593:38aa177457d0 Date: 2013-05-27 22:26 +0200 http://bitbucket.org/pypy/pypy/changeset/38aa177457d0/ Log: Fix translation diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -35,7 +35,11 @@ def new(space, w_subtype, w_value): dtype = _get_dtype(space) return dtype.itemtype.coerce_subtype(space, w_subtype, w_value) - return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype) + + def descr_reduce(self, space): + return self.reduce(space) + + return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype), func_with_new_name(descr_reduce, "descr_reduce") class PrimitiveBox(object): @@ -50,7 +54,7 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.value) - def descr_reduce(self, space): + def reduce(self, space): from rpython.rlib.rstring import StringBuilder from rpython.rtyper.lltypesystem import rffi, lltype @@ -60,14 +64,14 @@ assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") - value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, "raw") + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, flavor="raw") value[0] = self.value builder = StringBuilder() builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.value))) ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) - lltype.free(value, "raw") + lltype.free(value, flavor="raw") return ret class ComplexBox(object): @@ -86,7 +90,7 @@ def convert_imag_to(self, dtype): return dtype.box(self.imag) - def descr_reduce(self, space): + def reduce(self, space): from rpython.rlib.rstring import StringBuilder from rpython.rtyper.lltypesystem import rffi, lltype @@ -96,7 +100,7 @@ assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") - value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, "raw") + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, flavor="raw") value[0] = self.real value[1] = self.imag @@ -104,7 +108,7 @@ builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.real)) * 2) ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) - lltype.free(value, "raw") + lltype.free(value, flavor="raw") return ret class W_GenericBox(W_Root): @@ -229,7 +233,7 @@ return convert_to_array(space, w_values) class W_BoolBox(W_GenericBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("bool") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("bool") class W_NumberBox(W_GenericBox): _attrs_ = () @@ -245,40 +249,40 @@ pass class W_Int8Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int8") class W_UInt8Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint8") class W_Int16Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int16") class W_UInt16Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint16") class W_Int32Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int32") class W_UInt32Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint32") class W_LongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("long") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("long") class W_ULongBox(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("ulong") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("ulong") class W_Int64Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int64") class W_LongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('longlong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('longlong') class W_UInt64Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint64") class W_ULongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('ulonglong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('ulonglong') class W_InexactBox(W_NumberBox): _attrs_ = () @@ -287,13 +291,13 @@ _attrs_ = () class W_Float16Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float16") class W_Float32Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float32") class W_Float64Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): def __init__(self, arr, ofs, dtype): @@ -396,33 +400,33 @@ class W_Complex64Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex64") _COMPONENTS_BOX = W_Float32Box class W_Complex128Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex128") _COMPONENTS_BOX = W_Float64Box if ENABLED_LONG_DOUBLE and long_double_size == 12: class W_Float96Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float96") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float96") W_LongDoubleBox = W_Float96Box class W_Complex192Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex192") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex192") _COMPONENTS_BOX = W_Float96Box W_CLongDoubleBox = W_Complex192Box elif ENABLED_LONG_DOUBLE and long_double_size == 16: class W_Float128Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float128") W_LongDoubleBox = W_Float128Box class W_Complex256Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex256") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex256") _COMPONENTS_BOX = W_Float128Box W_CLongDoubleBox = W_Complex256Box diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1058,7 +1058,7 @@ state = rffi.str2charp(space.str_w(w_state)) box = w_dtype.itemtype.box_raw_data(state) - lltype.free(state, "raw") + lltype.free(state, flavor="raw") return box W_FlatIterator.typedef = TypeDef( From noreply at buildbot.pypy.org Tue May 28 13:49:30 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Tue, 28 May 2013 13:49:30 +0200 (CEST) Subject: [pypy-commit] pypy numpy-pickle: Close branch Message-ID: <20130528114930.C9D0C1C00BD@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: numpy-pickle Changeset: r64604:e4f9bb0afad2 Date: 2013-05-28 13:43 +0200 http://bitbucket.org/pypy/pypy/changeset/e4f9bb0afad2/ Log: Close branch From noreply at buildbot.pypy.org Tue May 28 13:49:32 2013 From: noreply at buildbot.pypy.org (rguillebert) Date: Tue, 28 May 2013 13:49:32 +0200 (CEST) Subject: [pypy-commit] pypy default: Merge numpy-pickle Message-ID: <20130528114932.3B75A1C0189@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: Changeset: r64605:9f5435579221 Date: 2013-05-28 13:48 +0200 http://bitbucket.org/pypy/pypy/changeset/9f5435579221/ Log: Merge numpy-pickle diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -13,6 +13,7 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', '_reconstruct' : 'interp_numarray._reconstruct', + 'scalar' : 'interp_numarray.build_scalar', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -11,6 +11,8 @@ from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from rpython.rlib.objectmodel import specialize +from pypy.interpreter.mixedmodule import MixedModule MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else () MIXIN_64 = (int_typedef,) if LONG_BIT == 64 else () @@ -33,7 +35,11 @@ def new(space, w_subtype, w_value): dtype = _get_dtype(space) return dtype.itemtype.coerce_subtype(space, w_subtype, w_value) - return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype) + + def descr_reduce(self, space): + return self.reduce(space) + + return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype), func_with_new_name(descr_reduce, "descr_reduce") class PrimitiveBox(object): @@ -48,6 +54,26 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.value) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, flavor="raw") + value[0] = self.value + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.value))) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret + class ComplexBox(object): _mixin_ = True @@ -64,6 +90,26 @@ def convert_imag_to(self, dtype): return dtype.box(self.imag) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, flavor="raw") + value[0] = self.real + value[1] = self.imag + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.real)) * 2) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret class W_GenericBox(W_Root): _attrs_ = () @@ -187,7 +233,7 @@ return convert_to_array(space, w_values) class W_BoolBox(W_GenericBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("bool") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("bool") class W_NumberBox(W_GenericBox): _attrs_ = () @@ -203,40 +249,40 @@ pass class W_Int8Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int8") class W_UInt8Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint8") class W_Int16Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int16") class W_UInt16Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint16") class W_Int32Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int32") class W_UInt32Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint32") class W_LongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("long") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("long") class W_ULongBox(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("ulong") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("ulong") class W_Int64Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int64") class W_LongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('longlong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('longlong') class W_UInt64Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint64") class W_ULongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('ulonglong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('ulonglong') class W_InexactBox(W_NumberBox): _attrs_ = () @@ -245,13 +291,13 @@ _attrs_ = () class W_Float16Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float16") class W_Float32Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float32") class W_Float64Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): _attrs_ = ['ofs', 'dtype', 'arr'] @@ -356,33 +402,33 @@ class W_Complex64Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex64") _COMPONENTS_BOX = W_Float32Box class W_Complex128Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex128") _COMPONENTS_BOX = W_Float64Box if ENABLED_LONG_DOUBLE and long_double_size == 12: class W_Float96Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float96") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float96") W_LongDoubleBox = W_Float96Box class W_Complex192Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex192") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex192") _COMPONENTS_BOX = W_Float96Box W_CLongDoubleBox = W_Complex192Box elif ENABLED_LONG_DOUBLE and long_double_size == 16: class W_Float128Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float128") W_LongDoubleBox = W_Float128Box class W_Complex256Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex256") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex256") _COMPONENTS_BOX = W_Float128Box W_CLongDoubleBox = W_Complex256Box @@ -458,6 +504,7 @@ __module__ = "numpypy", __new__ = interp2app(W_BoolBox.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_BoolBox.descr_reduce), ) W_NumberBox.typedef = TypeDef("number", W_GenericBox.typedef, @@ -480,42 +527,49 @@ __module__ = "numpypy", __new__ = interp2app(W_Int8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int8Box.descr_reduce), ) W_UInt8Box.typedef = TypeDef("uint8", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt8Box.descr_reduce), ) W_Int16Box.typedef = TypeDef("int16", W_SignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Int16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int16Box.descr_reduce), ) W_UInt16Box.typedef = TypeDef("uint16", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt16Box.descr_reduce), ) W_Int32Box.typedef = TypeDef("int32", (W_SignedIntegerBox.typedef,) + MIXIN_32, __module__ = "numpypy", __new__ = interp2app(W_Int32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int32Box.descr_reduce), ) W_UInt32Box.typedef = TypeDef("uint32", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt32Box.descr_reduce), ) W_Int64Box.typedef = TypeDef("int64", (W_SignedIntegerBox.typedef,) + MIXIN_64, __module__ = "numpypy", __new__ = interp2app(W_Int64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int64Box.descr_reduce), ) if LONG_BIT == 32: @@ -529,6 +583,7 @@ __module__ = "numpypy", __new__ = interp2app(W_UInt64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt64Box.descr_reduce), ) W_InexactBox.typedef = TypeDef("inexact", W_NumberBox.typedef, @@ -543,23 +598,27 @@ __module__ = "numpypy", __new__ = interp2app(W_Float16Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float16Box.descr_reduce), ) W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Float32Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float32Box.descr_reduce), ) W_Float64Box.typedef = TypeDef("float64", (W_FloatingBox.typedef, float_typedef), __module__ = "numpypy", __new__ = interp2app(W_Float64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float64Box.descr_reduce), ) if ENABLED_LONG_DOUBLE and long_double_size == 12: W_Float96Box.typedef = TypeDef("float96", (W_FloatingBox.typedef), __module__ = "numpypy", + __reduce__ = interp2app(W_Float96Box.descr_reduce), __new__ = interp2app(W_Float96Box.descr__new__.im_func), ) @@ -567,6 +626,7 @@ W_Complex192Box.typedef = TypeDef("complex192", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex192Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex192Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -576,11 +636,13 @@ __module__ = "numpypy", __new__ = interp2app(W_Float128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float128Box.descr_reduce), ) W_Complex256Box.typedef = TypeDef("complex256", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex256Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex256Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -618,6 +680,7 @@ W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex128Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -625,6 +688,7 @@ W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex64Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox .descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,6 +1051,17 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) + def build_scalar(space, w_dtype, w_state): + from rpython.rtyper.lltypesystem import rffi, lltype + + assert isinstance(w_dtype, interp_dtype.W_Dtype) + + state = rffi.str2charp(space.str_w(w_state)) + box = w_dtype.itemtype.box_raw_data(state) + lltype.free(state, flavor="raw") + return box + + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -0,0 +1,23 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +class AppTestScalar(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) + + def test_pickle(self): + from numpypy import dtype, int32, float64, complex128, zeros, sum + from numpypy.core.multiarray import scalar + from cPickle import loads, dumps + i = int32(1337) + f = float64(13.37) + c = complex128(13 + 37.j) + + assert i.__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) + assert f.__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) + assert c.__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) + + assert loads(dumps(i)) == i + assert loads(dumps(f)) == f + assert loads(dumps(c)) == c + + a = zeros(3) + assert loads(dumps(sum(a))) == sum(a) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -145,6 +145,11 @@ #XXX this is the place to display a warning return self.box(real) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box(array[0]) + @specialize.argtype(1) def unbox(self, box): assert isinstance(box, self.BoxType) @@ -1108,6 +1113,11 @@ rffi.cast(self.T, real), rffi.cast(self.T, imag)) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box_complex(array[0], array[1]) + def unbox(self, box): assert isinstance(box, self.BoxType) # do this in two stages since real, imag are read only From noreply at buildbot.pypy.org Tue May 28 14:37:27 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 14:37:27 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: grumble grumble grumble Message-ID: <20130528123727.4BC421C2FC0@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64606:b59812edf3d1 Date: 2013-05-28 14:36 +0200 http://bitbucket.org/pypy/pypy/changeset/b59812edf3d1/ Log: grumble grumble grumble diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py --- a/rpython/jit/backend/x86/regalloc.py +++ b/rpython/jit/backend/x86/regalloc.py @@ -1337,7 +1337,7 @@ # self._compute_hint_frame_locations_from_descr(descr) def consider_guard_not_forced_2(self, op): - self.rm.before_call([], save_all_regs=True) + self.rm.before_call(op.getfailargs(), save_all_regs=True) fail_locs = [self.loc(v) for v in op.getfailargs()] self.assembler.store_force_descr(op, fail_locs, self.fm.get_frame_depth()) From noreply at buildbot.pypy.org Tue May 28 14:55:29 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:29 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: Merge stringobject.py and stringtype.py into new file bytesobject.py. Message-ID: <20130528125529.DD9D81C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64607:6ebcb3858085 Date: 2013-05-24 22:20 +0200 http://bitbucket.org/pypy/pypy/changeset/6ebcb3858085/ Log: Merge stringobject.py and stringtype.py into new file bytesobject.py. diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -714,7 +714,7 @@ @unwrap_spec(data=str, errors='str_or_None') def escape_encode(space, data, errors='strict'): - from pypy.objspace.std.stringobject import string_escape_encode + from pypy.objspace.std.bytesobject import string_escape_encode result = string_escape_encode(data, quote="'") start = 1 end = len(result) - 1 diff --git a/pypy/module/clr/boxing_rules.py b/pypy/module/clr/boxing_rules.py --- a/pypy/module/clr/boxing_rules.py +++ b/pypy/module/clr/boxing_rules.py @@ -4,7 +4,7 @@ from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.boolobject import W_BoolObject from pypy.objspace.std.noneobject import W_NoneObject -from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.bytesobject import W_StringObject from rpython.translator.cli.dotnet import box class __extend__(W_Root): diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -12,7 +12,7 @@ from pypy.module.cpyext.stringobject import PyString_Check from pypy.module.sys.interp_encoding import setdefaultencoding from pypy.module._codecs.interp_codecs import CodecState -from pypy.objspace.std import unicodeobject, unicodetype, stringtype +from pypy.objspace.std import unicodeobject, unicodetype, bytesobject from rpython.rlib import runicode from rpython.tool.sourcetools import func_renamer import sys @@ -684,9 +684,9 @@ str = space.unicode_w(w_str) substr = space.unicode_w(w_substr) if rffi.cast(lltype.Signed, direction) <= 0: - return stringtype.stringstartswith(str, substr, start, end) + return bytesobject.stringstartswith(str, substr, start, end) else: - return stringtype.stringendswith(str, substr, start, end) + return bytesobject.stringendswith(str, substr, start, end) @cpython_api([PyObject, PyObject, Py_ssize_t, Py_ssize_t], Py_ssize_t, error=-1) def PyUnicode_Count(space, w_str, w_substr, start, end): diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -2,8 +2,8 @@ from pypy.interpreter.error import operationerrfmt, OperationError from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.objspace.std.bytesobject import str_typedef from pypy.objspace.std.floattype import float_typedef -from pypy.objspace.std.stringtype import str_typedef from pypy.objspace.std.unicodetype import unicode_typedef, unicode_from_object from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.complextype import complex_typedef diff --git a/pypy/module/micronumpy/stdobjspace.py b/pypy/module/micronumpy/stdobjspace.py --- a/pypy/module/micronumpy/stdobjspace.py +++ b/pypy/module/micronumpy/stdobjspace.py @@ -1,5 +1,5 @@ -from pypy.objspace.std import stringobject +from pypy.objspace.std import bytesobject from pypy.module.micronumpy import interp_boxes def delegate_stringbox2stringobj(space, w_box): @@ -7,5 +7,5 @@ def register_delegates(typeorder): typeorder[interp_boxes.W_StringBox] = [ - (stringobject.W_StringObject, delegate_stringbox2stringobj), + (bytesobject.W_StringObject, delegate_stringbox2stringobj), ] diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -3,7 +3,7 @@ from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.signature import Signature -from pypy.objspace.std import stringobject +from pypy.objspace.std import bytesobject from pypy.objspace.std.bytearraytype import ( getbytevalue, makebytearraydata_w, new_bytearray) from pypy.objspace.std.intobject import W_IntObject @@ -13,7 +13,7 @@ from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.bytesobject import W_StringObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.rstring import StringBuilder @@ -126,13 +126,13 @@ def contains__Bytearray_String(space, w_bytearray, w_str): # XXX slow - copies, needs rewriting w_str2 = str__Bytearray(space, w_bytearray) - return stringobject.contains__String_String(space, w_str2, w_str) + return bytesobject.contains__String_String(space, w_str2, w_str) def contains__Bytearray_ANY(space, w_bytearray, w_sub): # XXX slow - copies, needs rewriting w_str = space.wrap(space.bufferstr_new_w(w_sub)) w_str2 = str__Bytearray(space, w_bytearray) - return stringobject.contains__String_String(space, w_str2, w_str) + return bytesobject.contains__String_String(space, w_str2, w_str) def add__Bytearray_Bytearray(space, w_bytearray1, w_bytearray2): data1 = w_bytearray1.data @@ -237,7 +237,7 @@ def str_translate__Bytearray_ANY_ANY(space, w_bytearray1, w_table, w_deletechars): # XXX slow, copies *twice* needs proper implementation w_str_copy = str__Bytearray(space, w_bytearray1) - w_res = stringobject.str_translate__String_ANY_ANY(space, w_str_copy, + w_res = bytesobject.str_translate__String_ANY_ANY(space, w_str_copy, w_table, w_deletechars) return String2Bytearray(space, w_res) @@ -281,31 +281,31 @@ def str_count__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_char, w_start, w_stop): w_char = space.wrap(space.bufferstr_new_w(w_char)) w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_count__String_String_ANY_ANY(space, w_str, w_char, + return bytesobject.str_count__String_String_ANY_ANY(space, w_str, w_char, w_start, w_stop) def str_index__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_char, w_start, w_stop): w_char = space.wrap(space.bufferstr_new_w(w_char)) w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_index__String_String_ANY_ANY(space, w_str, w_char, + return bytesobject.str_index__String_String_ANY_ANY(space, w_str, w_char, w_start, w_stop) def str_rindex__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_char, w_start, w_stop): w_char = space.wrap(space.bufferstr_new_w(w_char)) w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_rindex__String_String_ANY_ANY(space, w_str, w_char, + return bytesobject.str_rindex__String_String_ANY_ANY(space, w_str, w_char, w_start, w_stop) def str_find__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_char, w_start, w_stop): w_char = space.wrap(space.bufferstr_new_w(w_char)) w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_find__String_String_ANY_ANY(space, w_str, w_char, + return bytesobject.str_find__String_String_ANY_ANY(space, w_str, w_char, w_start, w_stop) def str_rfind__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_char, w_start, w_stop): w_char = space.wrap(space.bufferstr_new_w(w_char)) w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_rfind__String_String_ANY_ANY(space, w_str, w_char, + return bytesobject.str_rfind__String_String_ANY_ANY(space, w_str, w_char, w_start, w_stop) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): @@ -313,12 +313,12 @@ w_str = str__Bytearray(space, w_bytearray) w_prefix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in space.fixedview(w_prefix)]) - return stringobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, + return bytesobject.str_startswith__String_ANY_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) w_prefix = space.wrap(space.bufferstr_new_w(w_prefix)) w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, + return bytesobject.str_startswith__String_String_ANY_ANY(space, w_str, w_prefix, w_start, w_stop) def str_endswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_suffix, w_start, w_stop): @@ -326,11 +326,11 @@ w_str = str__Bytearray(space, w_bytearray) w_suffix = space.newtuple([space.wrap(space.bufferstr_new_w(w_entry)) for w_entry in space.fixedview(w_suffix)]) - return stringobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, + return bytesobject.str_endswith__String_ANY_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) w_suffix = space.wrap(space.bufferstr_new_w(w_suffix)) w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, + return bytesobject.str_endswith__String_String_ANY_ANY(space, w_str, w_suffix, w_start, w_stop) def str_join__Bytearray_ANY(space, w_self, w_list): @@ -355,35 +355,35 @@ def str_decode__Bytearray_ANY_ANY(space, w_bytearray, w_encoding, w_errors): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_decode__String_ANY_ANY(space, w_str, w_encoding, w_errors) + return bytesobject.str_decode__String_ANY_ANY(space, w_str, w_encoding, w_errors) def str_islower__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_islower__String(space, w_str) + return bytesobject.str_islower__String(space, w_str) def str_isupper__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_isupper__String(space, w_str) + return bytesobject.str_isupper__String(space, w_str) def str_isalpha__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_isalpha__String(space, w_str) + return bytesobject.str_isalpha__String(space, w_str) def str_isalnum__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_isalnum__String(space, w_str) + return bytesobject.str_isalnum__String(space, w_str) def str_isdigit__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_isdigit__String(space, w_str) + return bytesobject.str_isdigit__String(space, w_str) def str_istitle__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_istitle__String(space, w_str) + return bytesobject.str_istitle__String(space, w_str) def str_isspace__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - return stringobject.str_isspace__String(space, w_str) + return bytesobject.str_isspace__String(space, w_str) def bytearray_insert__Bytearray_Int_ANY(space, w_bytearray, w_idx, w_other): where = space.int_w(w_idx) @@ -441,66 +441,66 @@ # but they have to return a bytearray. def str_replace__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_str1, w_str2, w_max): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_replace__String_ANY_ANY_ANY(space, w_str, w_str1, + w_res = bytesobject.str_replace__String_ANY_ANY_ANY(space, w_str, w_str1, w_str2, w_max) return String2Bytearray(space, w_res) def str_upper__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_upper__String(space, w_str) + w_res = bytesobject.str_upper__String(space, w_str) return String2Bytearray(space, w_res) def str_lower__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_lower__String(space, w_str) + w_res = bytesobject.str_lower__String(space, w_str) return String2Bytearray(space, w_res) def str_title__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_title__String(space, w_str) + w_res = bytesobject.str_title__String(space, w_str) return String2Bytearray(space, w_res) def str_swapcase__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_swapcase__String(space, w_str) + w_res = bytesobject.str_swapcase__String(space, w_str) return String2Bytearray(space, w_res) def str_capitalize__Bytearray(space, w_bytearray): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_capitalize__String(space, w_str) + w_res = bytesobject.str_capitalize__String(space, w_str) return String2Bytearray(space, w_res) def str_ljust__Bytearray_ANY_ANY(space, w_bytearray, w_width, w_fillchar): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_ljust__String_ANY_ANY(space, w_str, w_width, + w_res = bytesobject.str_ljust__String_ANY_ANY(space, w_str, w_width, w_fillchar) return String2Bytearray(space, w_res) def str_rjust__Bytearray_ANY_ANY(space, w_bytearray, w_width, w_fillchar): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_rjust__String_ANY_ANY(space, w_str, w_width, + w_res = bytesobject.str_rjust__String_ANY_ANY(space, w_str, w_width, w_fillchar) return String2Bytearray(space, w_res) def str_center__Bytearray_ANY_ANY(space, w_bytearray, w_width, w_fillchar): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_center__String_ANY_ANY(space, w_str, w_width, + w_res = bytesobject.str_center__String_ANY_ANY(space, w_str, w_width, w_fillchar) return String2Bytearray(space, w_res) def str_zfill__Bytearray_ANY(space, w_bytearray, w_width): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_zfill__String_ANY(space, w_str, w_width) + w_res = bytesobject.str_zfill__String_ANY(space, w_str, w_width) return String2Bytearray(space, w_res) def str_expandtabs__Bytearray_ANY(space, w_bytearray, w_tabsize): w_str = str__Bytearray(space, w_bytearray) - w_res = stringobject.str_expandtabs__String_ANY(space, w_str, w_tabsize) + w_res = bytesobject.str_expandtabs__String_ANY(space, w_str, w_tabsize) return String2Bytearray(space, w_res) def str_splitlines__Bytearray_ANY(space, w_bytearray, w_keepends): w_str = str__Bytearray(space, w_bytearray) - w_result = stringobject.str_splitlines__String_ANY(space, w_str, w_keepends) + w_result = bytesobject.str_splitlines__String_ANY(space, w_str, w_keepends) return space.newlist([ new_bytearray(space, space.w_bytearray, makebytearraydata_w(space, w_entry)) for w_entry in space.unpackiterable(w_result) @@ -531,7 +531,7 @@ def str_partition__Bytearray_ANY(space, w_bytearray, w_sub): w_str = str__Bytearray(space, w_bytearray) w_sub = space.wrap(space.bufferstr_new_w(w_sub)) - w_tuple = stringobject.str_partition__String_String(space, w_str, w_sub) + w_tuple = bytesobject.str_partition__String_String(space, w_str, w_sub) w_a, w_b, w_c = space.fixedview(w_tuple, 3) return space.newtuple([ String2Bytearray(space, w_a), @@ -541,7 +541,7 @@ def str_rpartition__Bytearray_ANY(space, w_bytearray, w_sub): w_str = str__Bytearray(space, w_bytearray) w_sub = space.wrap(space.bufferstr_new_w(w_sub)) - w_tuple = stringobject.str_rpartition__String_String(space, w_str, w_sub) + w_tuple = bytesobject.str_rpartition__String_String(space, w_str, w_sub) w_a, w_b, w_c = space.fixedview(w_tuple, 3) return space.newtuple([ String2Bytearray(space, w_a), @@ -677,7 +677,7 @@ start += step def _strip(space, w_bytearray, u_chars, left, right): - # note: mostly copied from stringobject._strip + # note: mostly copied from bytesobject._strip # should really be shared u_self = w_bytearray.data diff --git a/pypy/objspace/std/bytearraytype.py b/pypy/objspace/std/bytearraytype.py --- a/pypy/objspace/std/bytearraytype.py +++ b/pypy/objspace/std/bytearraytype.py @@ -4,7 +4,7 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.stringtype import ( +from pypy.objspace.std.bytesobject import ( str_decode, str_count, str_index, str_rindex, str_find, str_rfind, str_replace, str_startswith, str_endswith, str_islower, str_isupper, str_isalpha, diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/bytesobject.py rename from pypy/objspace/std/stringobject.py rename to pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -1,8 +1,11 @@ """The builtin str implementation""" +from sys import maxint from pypy.interpreter.buffer import StringBuffer from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.objspace.std import newformat, slicetype +from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.formatting import mod_format from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.model import W_Object, registerimplementation @@ -10,20 +13,20 @@ from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std.stringtype import ( - joined2, sliced, stringendswith, stringstartswith, wrapchar, wrapstr) +from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from rpython.rlib import jit -from rpython.rlib.objectmodel import ( - compute_hash, compute_unique_id, specialize) +from rpython.rlib.jit import we_are_jitted +from rpython.rlib.objectmodel import (compute_hash, compute_unique_id, + specialize) from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rstring import StringBuilder, split -class W_AbstractStringObject(W_Object): +class W_AbstractBytesObject(W_Object): __slots__ = () def is_w(self, space, w_other): - if not isinstance(w_other, W_AbstractStringObject): + if not isinstance(w_other, W_AbstractBytesObject): return False if self is w_other: return True @@ -49,8 +52,7 @@ return space.unicode_w(decode_object(space, w_self, encoding, errors)) -class W_StringObject(W_AbstractStringObject): - from pypy.objspace.std.stringtype import str_typedef as typedef +class W_BytesObject(W_AbstractBytesObject): _immutable_fields_ = ['_value'] def __init__(w_self, str): @@ -69,17 +71,326 @@ def listview_str(w_self): return _create_list_from_string(w_self._value) +W_StringObject = W_BytesObject + def _create_list_from_string(value): # need this helper function to allow the jit to look inside and inline # listview_str return [s for s in value] -registerimplementation(W_StringObject) +registerimplementation(W_BytesObject) -W_StringObject.EMPTY = W_StringObject('') -W_StringObject.PREBUILT = [W_StringObject(chr(i)) for i in range(256)] +W_BytesObject.EMPTY = W_BytesObject('') +W_BytesObject.PREBUILT = [W_BytesObject(chr(i)) for i in range(256)] del i + +def wrapstr(space, s): + if space.config.objspace.std.sharesmallstr: + if space.config.objspace.std.withprebuiltchar: + # share characters and empty string + if len(s) <= 1: + if len(s) == 0: + return W_BytesObject.EMPTY + else: + s = s[0] # annotator hint: a single char + return wrapchar(space, s) + else: + # only share the empty string + if len(s) == 0: + return W_BytesObject.EMPTY + return W_BytesObject(s) + +def wrapchar(space, c): + if space.config.objspace.std.withprebuiltchar and not we_are_jitted(): + return W_BytesObject.PREBUILT[ord(c)] + else: + return W_BytesObject(c) + +def sliced(space, s, start, stop, orig_obj): + assert start >= 0 + assert stop >= 0 + if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), space.w_str): + return orig_obj + return wrapstr(space, s[start:stop]) + +def joined2(space, str1, str2): + if space.config.objspace.std.withstrbuf: + from pypy.objspace.std.strbufobject import joined2 + return joined2(str1, str2) + else: + return wrapstr(space, str1 + str2) + +str_join = SMM('join', 2, + doc='S.join(sequence) -> string\n\nReturn a string which is' + ' the concatenation of the strings in the\nsequence. ' + ' The separator between elements is S.') +str_split = SMM('split', 3, defaults=(None,-1), + doc='S.split([sep [,maxsplit]]) -> list of strings\n\nReturn' + ' a list of the words in the string S, using sep as' + ' the\ndelimiter string. If maxsplit is given, at most' + ' maxsplit\nsplits are done. If sep is not specified or' + ' is None, any\nwhitespace string is a separator.') +str_rsplit = SMM('rsplit', 3, defaults=(None,-1), + doc='S.rsplit([sep [,maxsplit]]) -> list of' + ' strings\n\nReturn a list of the words in the string S,' + ' using sep as the\ndelimiter string, starting at the' + ' end of the string and working\nto the front. If' + ' maxsplit is given, at most maxsplit splits are\ndone.' + ' If sep is not specified or is None, any whitespace' + ' string\nis a separator.') +str_format = SMM('format', 1, general__args__=True) +str_isdigit = SMM('isdigit', 1, + doc='S.isdigit() -> bool\n\nReturn True if all characters' + ' in S are digits\nand there is at least one' + ' character in S, False otherwise.') +str_isalpha = SMM('isalpha', 1, + doc='S.isalpha() -> bool\n\nReturn True if all characters' + ' in S are alphabetic\nand there is at least one' + ' character in S, False otherwise.') +str_isspace = SMM('isspace', 1, + doc='S.isspace() -> bool\n\nReturn True if all characters' + ' in S are whitespace\nand there is at least one' + ' character in S, False otherwise.') +str_isupper = SMM('isupper', 1, + doc='S.isupper() -> bool\n\nReturn True if all cased' + ' characters in S are uppercase and there is\nat' + ' least one cased character in S, False otherwise.') +str_islower = SMM('islower', 1, + doc='S.islower() -> bool\n\nReturn True if all cased' + ' characters in S are lowercase and there is\nat' + ' least one cased character in S, False otherwise.') +str_istitle = SMM('istitle', 1, + doc='S.istitle() -> bool\n\nReturn True if S is a' + ' titlecased string and there is at least' + ' one\ncharacter in S, i.e. uppercase characters may' + ' only follow uncased\ncharacters and lowercase' + ' characters only cased ones. Return' + ' False\notherwise.') +str_isalnum = SMM('isalnum', 1, + doc='S.isalnum() -> bool\n\nReturn True if all characters' + ' in S are alphanumeric\nand there is at least one' + ' character in S, False otherwise.') +str_ljust = SMM('ljust', 3, defaults=(' ',), + doc='S.ljust(width[, fillchar]) -> string\n\nReturn S' + ' left justified in a string of length width. Padding' + ' is\ndone using the specified fill character' + ' (default is a space).') +str_rjust = SMM('rjust', 3, defaults=(' ',), + doc='S.rjust(width[, fillchar]) -> string\n\nReturn S' + ' right justified in a string of length width.' + ' Padding is\ndone using the specified fill character' + ' (default is a space)') +str_upper = SMM('upper', 1, + doc='S.upper() -> string\n\nReturn a copy of the string S' + ' converted to uppercase.') +str_lower = SMM('lower', 1, + doc='S.lower() -> string\n\nReturn a copy of the string S' + ' converted to lowercase.') +str_swapcase = SMM('swapcase', 1, + doc='S.swapcase() -> string\n\nReturn a copy of the' + ' string S with uppercase characters\nconverted to' + ' lowercase and vice versa.') +str_capitalize = SMM('capitalize', 1, + doc='S.capitalize() -> string\n\nReturn a copy of the' + ' string S with only its first' + ' character\ncapitalized.') +str_title = SMM('title', 1, + doc='S.title() -> string\n\nReturn a titlecased version' + ' of S, i.e. words start with uppercase\ncharacters,' + ' all remaining cased characters have lowercase.') +str_find = SMM('find', 4, defaults=(0, maxint), + doc='S.find(sub [,start [,end]]) -> int\n\nReturn the' + ' lowest index in S where substring sub is' + ' found,\nsuch that sub is contained within' + ' s[start,end]. Optional\narguments start and end' + ' are interpreted as in slice notation.\n\nReturn -1' + ' on failure.') +str_rfind = SMM('rfind', 4, defaults=(0, maxint), + doc='S.rfind(sub [,start [,end]]) -> int\n\nReturn the' + ' highest index in S where substring sub is' + ' found,\nsuch that sub is contained within' + ' s[start,end]. Optional\narguments start and end' + ' are interpreted as in slice notation.\n\nReturn -1' + ' on failure.') +str_partition = SMM('partition', 2, + doc='S.partition(sep) -> (head, sep, tail)\n\nSearches' + ' for the separator sep in S, and returns the part before' + ' it,\nthe separator itself, and the part after it. If' + ' the separator is not\nfound, returns S and two empty' + ' strings.') +str_rpartition = SMM('rpartition', 2, + doc='S.rpartition(sep) -> (tail, sep, head)\n\nSearches' + ' for the separator sep in S, starting at the end of S,' + ' and returns\nthe part before it, the separator itself,' + ' and the part after it. If the\nseparator is not found,' + ' returns two empty strings and S.') +str_index = SMM('index', 4, defaults=(0, maxint), + doc='S.index(sub [,start [,end]]) -> int\n\nLike S.find()' + ' but raise ValueError when the substring is not' + ' found.') +str_rindex = SMM('rindex', 4, defaults=(0, maxint), + doc='S.rindex(sub [,start [,end]]) -> int\n\nLike' + ' S.rfind() but raise ValueError when the substring' + ' is not found.') +str_replace = SMM('replace', 4, defaults=(-1,), + doc='S.replace (old, new[, count]) -> string\n\nReturn a' + ' copy of string S with all occurrences of' + ' substring\nold replaced by new. If the optional' + ' argument count is\ngiven, only the first count' + ' occurrences are replaced.') +str_zfill = SMM('zfill', 2, + doc='S.zfill(width) -> string\n\nPad a numeric string S' + ' with zeros on the left, to fill a field\nof the' + ' specified width. The string S is never truncated.') +str_strip = SMM('strip', 2, defaults=(None,), + doc='S.strip([chars]) -> string or unicode\n\nReturn a' + ' copy of the string S with leading and' + ' trailing\nwhitespace removed.\nIf chars is given' + ' and not None, remove characters in chars' + ' instead.\nIf chars is unicode, S will be converted' + ' to unicode before stripping') +str_rstrip = SMM('rstrip', 2, defaults=(None,), + doc='S.rstrip([chars]) -> string or unicode\n\nReturn a' + ' copy of the string S with trailing whitespace' + ' removed.\nIf chars is given and not None, remove' + ' characters in chars instead.\nIf chars is unicode,' + ' S will be converted to unicode before stripping') +str_lstrip = SMM('lstrip', 2, defaults=(None,), + doc='S.lstrip([chars]) -> string or unicode\n\nReturn a' + ' copy of the string S with leading whitespace' + ' removed.\nIf chars is given and not None, remove' + ' characters in chars instead.\nIf chars is unicode,' + ' S will be converted to unicode before stripping') +str_center = SMM('center', 3, defaults=(' ',), + doc='S.center(width[, fillchar]) -> string\n\nReturn S' + ' centered in a string of length width. Padding' + ' is\ndone using the specified fill character' + ' (default is a space)') +str_count = SMM('count', 4, defaults=(0, maxint), + doc='S.count(sub[, start[, end]]) -> int\n\nReturn the' + ' number of occurrences of substring sub in' + ' string\nS[start:end]. Optional arguments start and' + ' end are\ninterpreted as in slice notation.') +str_endswith = SMM('endswith', 4, defaults=(0, maxint), + doc='S.endswith(suffix[, start[, end]]) -> bool\n\nReturn' + ' True if S ends with the specified suffix, False' + ' otherwise.\nWith optional start, test S beginning' + ' at that position.\nWith optional end, stop' + ' comparing S at that position.') +str_expandtabs = SMM('expandtabs', 2, defaults=(8,), + doc='S.expandtabs([tabsize]) -> string\n\nReturn a copy' + ' of S where all tab characters are expanded using' + ' spaces.\nIf tabsize is not given, a tab size of 8' + ' characters is assumed.') +str_splitlines = SMM('splitlines', 2, defaults=(0,), + doc='S.splitlines([keepends]) -> list of' + ' strings\n\nReturn a list of the lines in S,' + ' breaking at line boundaries.\nLine breaks are not' + ' included in the resulting list unless keepends\nis' + ' given and true.') +str_startswith = SMM('startswith', 4, defaults=(0, maxint), + doc='S.startswith(prefix[, start[, end]]) ->' + ' bool\n\nReturn True if S starts with the specified' + ' prefix, False otherwise.\nWith optional start, test' + ' S beginning at that position.\nWith optional end,' + ' stop comparing S at that position.') +str_translate = SMM('translate', 3, defaults=('',), #unicode mimic not supported now + doc='S.translate(table [,deletechars]) -> string\n\n' + 'Return a copy of the string S, where all characters' + ' occurring\nin the optional argument deletechars are' + ' removed, and the\nremaining characters have been' + ' mapped through the given\ntranslation table, which' + ' must be a string of length 256.') +str_decode = SMM('decode', 3, defaults=(None, None), + argnames=['encoding', 'errors'], + doc='S.decode([encoding[,errors]]) -> object\n\nDecodes S' + ' using the codec registered for encoding. encoding' + ' defaults\nto the default encoding. errors may be' + ' given to set a different error\nhandling scheme.' + " Default is 'strict' meaning that encoding errors" + ' raise\na UnicodeDecodeError. Other possible values' + " are 'ignore' and 'replace'\nas well as any other" + ' name registerd with codecs.register_error that' + ' is\nable to handle UnicodeDecodeErrors.') +str_encode = SMM('encode', 3, defaults=(None, None), + argnames=['encoding', 'errors'], + doc='S.encode([encoding[,errors]]) -> object\n\nEncodes S' + ' using the codec registered for encoding. encoding' + ' defaults\nto the default encoding. errors may be' + ' given to set a different error\nhandling scheme.' + " Default is 'strict' meaning that encoding errors" + ' raise\na UnicodeEncodeError. Other possible values' + " are 'ignore', 'replace' and\n'xmlcharrefreplace' as" + ' well as any other name registered' + ' with\ncodecs.register_error that is able to handle' + ' UnicodeEncodeErrors.') + +str_formatter_parser = SMM('_formatter_parser', 1) +str_formatter_field_name_split = SMM('_formatter_field_name_split', 1) + +def str_formatter_parser__ANY(space, w_str): + from pypy.objspace.std.newformat import str_template_formatter + tformat = str_template_formatter(space, space.str_w(w_str)) + return tformat.formatter_parser() + +def str_formatter_field_name_split__ANY(space, w_str): + from pypy.objspace.std.newformat import str_template_formatter + tformat = str_template_formatter(space, space.str_w(w_str)) + return tformat.formatter_field_name_split() + +# ____________________________________________________________ + + at unwrap_spec(w_object = WrappedDefault("")) +def descr__new__(space, w_stringtype, w_object): + # NB. the default value of w_object is really a *wrapped* empty string: + # there is gateway magic at work + w_obj = space.str(w_object) + if space.is_w(w_stringtype, space.w_str): + return w_obj # XXX might be reworked when space.str() typechecks + value = space.str_w(w_obj) + w_obj = space.allocate_instance(W_BytesObject, w_stringtype) + W_BytesObject.__init__(w_obj, value) + return w_obj + +# ____________________________________________________________ + +str_typedef = W_BytesObject.typedef = StdTypeDef( + "str", basestring_typedef, + __new__ = interp2app(descr__new__), + __doc__ = '''str(object) -> string + +Return a nice string representation of the object. +If the argument is a string, the return value is the same object.''' + ) + +str_typedef.registermethods(globals()) + +# ____________________________________________________________ + +# Helpers for several string implementations + + at specialize.argtype(0) +def stringendswith(u_self, suffix, start, end): + begin = end - len(suffix) + if begin < start: + return False + for i in range(len(suffix)): + if u_self[begin+i] != suffix[i]: + return False + return True + + at specialize.argtype(0) +def stringstartswith(u_self, prefix, start, end): + stop = start + len(prefix) + if stop > end: + return False + for i in range(len(prefix)): + if u_self[start+i] != prefix[i]: + return False + return True + + @specialize.arg(2) def _is_generic(space, w_self, fun): v = w_self._value @@ -384,7 +695,7 @@ size = len(list_w) if size == 0: - return W_StringObject.EMPTY + return W_BytesObject.EMPTY if size == 1: w_s = list_w[0] @@ -881,7 +1192,7 @@ length = len(s) start, stop, step, sl = w_slice.indices4(space, length) if sl == 0: - return W_StringObject.EMPTY + return W_BytesObject.EMPTY elif step == 1: assert start >= 0 and stop >= 0 return sliced(space, s, start, stop, w_str) @@ -893,7 +1204,7 @@ s = w_str._value start, stop = normalize_simple_slice(space, len(s), w_start, w_stop) if start == stop: - return W_StringObject.EMPTY + return W_BytesObject.EMPTY else: return sliced(space, s, start, stop, w_str) @@ -905,13 +1216,13 @@ raise FailedToImplement raise if mul <= 0: - return W_StringObject.EMPTY + return W_BytesObject.EMPTY input = w_str._value if len(input) == 1: s = input[0] * mul else: s = input * mul - return W_StringObject(s) + return W_BytesObject(s) def mul__String_ANY(space, w_str, w_times): return mul_string_times(space, w_str, w_times) @@ -928,7 +1239,7 @@ return space.wrap(len(w_str._value)) def str__String(space, w_str): - if type(w_str) is W_StringObject: + if type(w_str) is W_BytesObject: return w_str return wrapstr(space, w_str._value) @@ -1033,7 +1344,7 @@ for char in string: if not deletion_table[ord(char)]: buf.append(table[ord(char)]) - return W_StringObject(buf.build()) + return W_BytesObject(buf.build()) def str_decode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None): from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \ @@ -1069,5 +1380,4 @@ return space.wrap(StringBuffer(w_string._value)) # register all methods -from pypy.objspace.std import stringtype -register_all(vars(), stringtype) +register_all(vars(), globals()) diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py --- a/pypy/objspace/std/formatting.py +++ b/pypy/objspace/std/formatting.py @@ -2,7 +2,6 @@ String formatting routines. """ from pypy.interpreter.error import OperationError -from pypy.objspace.std.unicodetype import unicode_from_object from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck from rpython.rlib.rfloat import formatd, DTSF_ALT, isnan, isinf @@ -442,6 +441,7 @@ if not got_unicode: w_value = space.call_function(space.w_unicode, w_value) else: + from pypy.objspace.std.unicodetype import unicode_from_object w_value = unicode_from_object(space, w_value) s = space.unicode_w(w_value) self.std_wp(s) diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -17,6 +17,7 @@ from pypy.interpreter.generator import GeneratorIterator from pypy.interpreter.signature import Signature from pypy.objspace.std import slicetype +from pypy.objspace.std.bytesobject import W_BytesObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint @@ -24,7 +25,6 @@ W_ReverseSeqIterObject) from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index, negate @@ -79,7 +79,7 @@ # check for strings for w_obj in list_w: - if not type(w_obj) is W_StringObject: + if not type(w_obj) is W_BytesObject: break else: return space.fromcache(StringListStrategy) @@ -877,7 +877,7 @@ def switch_to_correct_strategy(self, w_list, w_item): if type(w_item) is W_IntObject: strategy = self.space.fromcache(IntegerListStrategy) - elif type(w_item) is W_StringObject: + elif type(w_item) is W_BytesObject: strategy = self.space.fromcache(StringListStrategy) elif type(w_item) is W_UnicodeObject: strategy = self.space.fromcache(UnicodeListStrategy) @@ -1551,7 +1551,7 @@ unerase = staticmethod(unerase) def is_correct_type(self, w_obj): - return type(w_obj) is W_StringObject + return type(w_obj) is W_BytesObject def list_is_correct_type(self, w_list): return w_list.strategy is self.space.fromcache(StringListStrategy) diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -20,12 +20,12 @@ from rpython.rlib.rstring import StringBuilder from pypy.objspace.std.boolobject import W_BoolObject +from pypy.objspace.std.bytesobject import W_StringObject from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.listobject import W_ListObject -from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.typeobject import W_TypeObject from pypy.objspace.std.longobject import W_LongObject, newlong from pypy.objspace.std.noneobject import W_NoneObject diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -37,7 +37,7 @@ from pypy.objspace.std.floattype import float_typedef from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.basestringtype import basestring_typedef - from pypy.objspace.std.stringtype import str_typedef + from pypy.objspace.std.bytesobject import str_typedef from pypy.objspace.std.bytearraytype import bytearray_typedef from pypy.objspace.std.typeobject import type_typedef from pypy.objspace.std.slicetype import slice_typedef @@ -59,7 +59,7 @@ from pypy.objspace.std import listobject from pypy.objspace.std import dictmultiobject from pypy.objspace.std import setobject - from pypy.objspace.std import stringobject + from pypy.objspace.std import bytesobject from pypy.objspace.std import bytearrayobject from pypy.objspace.std import typeobject from pypy.objspace.std import sliceobject @@ -88,7 +88,7 @@ boolobject.W_BoolObject: [], intobject.W_IntObject: [], floatobject.W_FloatObject: [], - stringobject.W_StringObject: [], + bytesobject.W_BytesObject: [], bytearrayobject.W_BytearrayObject: [], typeobject.W_TypeObject: [], sliceobject.W_SliceObject: [], @@ -101,7 +101,7 @@ } self.imported_but_not_registered = { - stringobject.W_StringObject: True, + bytesobject.W_BytesObject: True, } for option, value in config.objspace.std: if option.startswith("with") and option in option_to_typename: @@ -171,13 +171,13 @@ complexobject.delegate_Float2Complex), ] - self.typeorder[stringobject.W_StringObject] += [ + self.typeorder[bytesobject.W_BytesObject] += [ (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode), ] if config.objspace.std.withstrbuf: from pypy.objspace.std import strbufobject self.typeorder[strbufobject.W_StringBufferObject] += [ - (stringobject.W_StringObject, + (bytesobject.W_BytesObject, strbufobject.delegate_buf2str), (unicodeobject.W_UnicodeObject, strbufobject.delegate_buf2unicode) diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -15,6 +15,7 @@ # Object imports from pypy.objspace.std.boolobject import W_BoolObject +from pypy.objspace.std.bytesobject import W_BytesObject, wrapstr from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.dictmultiobject import W_DictMultiObject from pypy.objspace.std.floatobject import W_FloatObject @@ -27,14 +28,12 @@ from pypy.objspace.std.iterobject import W_SeqIterObject from pypy.objspace.std.setobject import W_SetObject, W_FrozensetObject from pypy.objspace.std.sliceobject import W_SliceObject -from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.typeobject import W_TypeObject # types from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.stringtype import wrapstr from pypy.objspace.std.unicodetype import wrapunicode class StdObjSpace(ObjSpace, DescrOperation): @@ -47,7 +46,7 @@ self.model = model.StdTypeModel(self.config) self.FrameClass = frame.build_frame(self) - self.StringObjectCls = W_StringObject + self.StringObjectCls = W_BytesObject self.UnicodeObjectCls = W_UnicodeObject @@ -436,7 +435,7 @@ return w_obj.listview_str() if type(w_obj) is W_SetObject or type(w_obj) is W_FrozensetObject: return w_obj.listview_str() - if isinstance(w_obj, W_StringObject): + if isinstance(w_obj, W_BytesObject): return w_obj.listview_str() if isinstance(w_obj, W_ListObject) and self._uses_list_iter(w_obj): return w_obj.getitems_str() @@ -551,7 +550,7 @@ element or None on element not found. performance shortcut to avoid creating the OperationError(KeyError) - and allocating W_StringObject + and allocating W_BytesObject """ if (isinstance(w_obj, W_DictMultiObject) and not w_obj.user_overridden_class): diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py --- a/pypy/objspace/std/setobject.py +++ b/pypy/objspace/std/setobject.py @@ -2,9 +2,9 @@ from pypy.interpreter.error import OperationError from pypy.interpreter.signature import Signature from pypy.interpreter.baseobjspace import W_Root +from pypy.objspace.std.bytesobject import W_BytesObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.stdtypedef import StdTypeDef -from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.objectmodel import r_dict @@ -776,7 +776,7 @@ def add(self, w_set, w_key): if type(w_key) is W_IntObject: strategy = self.space.fromcache(IntegerSetStrategy) - elif type(w_key) is W_StringObject: + elif type(w_key) is W_BytesObject: strategy = self.space.fromcache(StringSetStrategy) elif type(w_key) is W_UnicodeObject: strategy = self.space.fromcache(UnicodeSetStrategy) @@ -1198,7 +1198,7 @@ return self.unerase(w_set.sstorage).keys() def is_correct_type(self, w_key): - return type(w_key) is W_StringObject + return type(w_key) is W_BytesObject def may_contain_equal_elements(self, strategy): if strategy is self.space.fromcache(IntegerSetStrategy): @@ -1525,7 +1525,7 @@ # check for strings for w_item in iterable_w: - if type(w_item) is not W_StringObject: + if type(w_item) is not W_BytesObject: break else: w_set.strategy = space.fromcache(StringSetStrategy) diff --git a/pypy/objspace/std/strbufobject.py b/pypy/objspace/std/strbufobject.py --- a/pypy/objspace/std/strbufobject.py +++ b/pypy/objspace/std/strbufobject.py @@ -1,13 +1,12 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stringobject import W_AbstractStringObject -from pypy.objspace.std.stringobject import W_StringObject +from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_StringObject from pypy.objspace.std.unicodeobject import delegate_String2Unicode from rpython.rlib.rstring import StringBuilder from pypy.interpreter.buffer import Buffer -class W_StringBufferObject(W_AbstractStringObject): - from pypy.objspace.std.stringtype import str_typedef as typedef +class W_StringBufferObject(W_AbstractBytesObject): + from pypy.objspace.std.bytesobject import str_typedef as typedef w_str = None @@ -73,5 +72,5 @@ assert type(w_self) is W_StringBufferObject return w_self -from pypy.objspace.std import stringtype -register_all(vars(), stringtype) +from pypy.objspace.std import bytesobject +register_all(vars(), bytesobject) diff --git a/pypy/objspace/std/stringtype.py b/pypy/objspace/std/stringtype.py deleted file mode 100644 --- a/pypy/objspace/std/stringtype.py +++ /dev/null @@ -1,318 +0,0 @@ -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.basestringtype import basestring_typedef -from pypy.objspace.std.register_all import register_all - - -from sys import maxint -from rpython.rlib.objectmodel import specialize -from rpython.rlib.jit import we_are_jitted - -def wrapstr(space, s): - from pypy.objspace.std.stringobject import W_StringObject - if space.config.objspace.std.sharesmallstr: - if space.config.objspace.std.withprebuiltchar: - # share characters and empty string - if len(s) <= 1: - if len(s) == 0: - return W_StringObject.EMPTY - else: - s = s[0] # annotator hint: a single char - return wrapchar(space, s) - else: - # only share the empty string - if len(s) == 0: - return W_StringObject.EMPTY - return W_StringObject(s) - -def wrapchar(space, c): - from pypy.objspace.std.stringobject import W_StringObject - if space.config.objspace.std.withprebuiltchar and not we_are_jitted(): - return W_StringObject.PREBUILT[ord(c)] - else: - return W_StringObject(c) - -def sliced(space, s, start, stop, orig_obj): - assert start >= 0 - assert stop >= 0 - if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), space.w_str): - return orig_obj - return wrapstr(space, s[start:stop]) - -def joined2(space, str1, str2): - if space.config.objspace.std.withstrbuf: - from pypy.objspace.std.strbufobject import joined2 - return joined2(str1, str2) - else: - return wrapstr(space, str1 + str2) - -str_join = SMM('join', 2, - doc='S.join(sequence) -> string\n\nReturn a string which is' - ' the concatenation of the strings in the\nsequence. ' - ' The separator between elements is S.') -str_split = SMM('split', 3, defaults=(None,-1), - doc='S.split([sep [,maxsplit]]) -> list of strings\n\nReturn' - ' a list of the words in the string S, using sep as' - ' the\ndelimiter string. If maxsplit is given, at most' - ' maxsplit\nsplits are done. If sep is not specified or' - ' is None, any\nwhitespace string is a separator.') -str_rsplit = SMM('rsplit', 3, defaults=(None,-1), - doc='S.rsplit([sep [,maxsplit]]) -> list of' - ' strings\n\nReturn a list of the words in the string S,' - ' using sep as the\ndelimiter string, starting at the' - ' end of the string and working\nto the front. If' - ' maxsplit is given, at most maxsplit splits are\ndone.' - ' If sep is not specified or is None, any whitespace' - ' string\nis a separator.') -str_format = SMM('format', 1, general__args__=True) -str_isdigit = SMM('isdigit', 1, - doc='S.isdigit() -> bool\n\nReturn True if all characters' - ' in S are digits\nand there is at least one' - ' character in S, False otherwise.') -str_isalpha = SMM('isalpha', 1, - doc='S.isalpha() -> bool\n\nReturn True if all characters' - ' in S are alphabetic\nand there is at least one' - ' character in S, False otherwise.') -str_isspace = SMM('isspace', 1, - doc='S.isspace() -> bool\n\nReturn True if all characters' - ' in S are whitespace\nand there is at least one' - ' character in S, False otherwise.') -str_isupper = SMM('isupper', 1, - doc='S.isupper() -> bool\n\nReturn True if all cased' - ' characters in S are uppercase and there is\nat' - ' least one cased character in S, False otherwise.') -str_islower = SMM('islower', 1, - doc='S.islower() -> bool\n\nReturn True if all cased' - ' characters in S are lowercase and there is\nat' - ' least one cased character in S, False otherwise.') -str_istitle = SMM('istitle', 1, - doc='S.istitle() -> bool\n\nReturn True if S is a' - ' titlecased string and there is at least' - ' one\ncharacter in S, i.e. uppercase characters may' - ' only follow uncased\ncharacters and lowercase' - ' characters only cased ones. Return' - ' False\notherwise.') -str_isalnum = SMM('isalnum', 1, - doc='S.isalnum() -> bool\n\nReturn True if all characters' - ' in S are alphanumeric\nand there is at least one' - ' character in S, False otherwise.') -str_ljust = SMM('ljust', 3, defaults=(' ',), - doc='S.ljust(width[, fillchar]) -> string\n\nReturn S' - ' left justified in a string of length width. Padding' - ' is\ndone using the specified fill character' - ' (default is a space).') -str_rjust = SMM('rjust', 3, defaults=(' ',), - doc='S.rjust(width[, fillchar]) -> string\n\nReturn S' - ' right justified in a string of length width.' - ' Padding is\ndone using the specified fill character' - ' (default is a space)') -str_upper = SMM('upper', 1, - doc='S.upper() -> string\n\nReturn a copy of the string S' - ' converted to uppercase.') -str_lower = SMM('lower', 1, - doc='S.lower() -> string\n\nReturn a copy of the string S' - ' converted to lowercase.') -str_swapcase = SMM('swapcase', 1, - doc='S.swapcase() -> string\n\nReturn a copy of the' - ' string S with uppercase characters\nconverted to' - ' lowercase and vice versa.') -str_capitalize = SMM('capitalize', 1, - doc='S.capitalize() -> string\n\nReturn a copy of the' - ' string S with only its first' - ' character\ncapitalized.') -str_title = SMM('title', 1, - doc='S.title() -> string\n\nReturn a titlecased version' - ' of S, i.e. words start with uppercase\ncharacters,' - ' all remaining cased characters have lowercase.') -str_find = SMM('find', 4, defaults=(0, maxint), - doc='S.find(sub [,start [,end]]) -> int\n\nReturn the' - ' lowest index in S where substring sub is' - ' found,\nsuch that sub is contained within' - ' s[start,end]. Optional\narguments start and end' - ' are interpreted as in slice notation.\n\nReturn -1' - ' on failure.') -str_rfind = SMM('rfind', 4, defaults=(0, maxint), - doc='S.rfind(sub [,start [,end]]) -> int\n\nReturn the' - ' highest index in S where substring sub is' - ' found,\nsuch that sub is contained within' - ' s[start,end]. Optional\narguments start and end' - ' are interpreted as in slice notation.\n\nReturn -1' - ' on failure.') -str_partition = SMM('partition', 2, - doc='S.partition(sep) -> (head, sep, tail)\n\nSearches' - ' for the separator sep in S, and returns the part before' - ' it,\nthe separator itself, and the part after it. If' - ' the separator is not\nfound, returns S and two empty' - ' strings.') -str_rpartition = SMM('rpartition', 2, - doc='S.rpartition(sep) -> (tail, sep, head)\n\nSearches' - ' for the separator sep in S, starting at the end of S,' - ' and returns\nthe part before it, the separator itself,' - ' and the part after it. If the\nseparator is not found,' - ' returns two empty strings and S.') -str_index = SMM('index', 4, defaults=(0, maxint), - doc='S.index(sub [,start [,end]]) -> int\n\nLike S.find()' - ' but raise ValueError when the substring is not' - ' found.') -str_rindex = SMM('rindex', 4, defaults=(0, maxint), - doc='S.rindex(sub [,start [,end]]) -> int\n\nLike' - ' S.rfind() but raise ValueError when the substring' - ' is not found.') -str_replace = SMM('replace', 4, defaults=(-1,), - doc='S.replace (old, new[, count]) -> string\n\nReturn a' - ' copy of string S with all occurrences of' - ' substring\nold replaced by new. If the optional' - ' argument count is\ngiven, only the first count' - ' occurrences are replaced.') -str_zfill = SMM('zfill', 2, - doc='S.zfill(width) -> string\n\nPad a numeric string S' - ' with zeros on the left, to fill a field\nof the' - ' specified width. The string S is never truncated.') -str_strip = SMM('strip', 2, defaults=(None,), - doc='S.strip([chars]) -> string or unicode\n\nReturn a' - ' copy of the string S with leading and' - ' trailing\nwhitespace removed.\nIf chars is given' - ' and not None, remove characters in chars' - ' instead.\nIf chars is unicode, S will be converted' - ' to unicode before stripping') -str_rstrip = SMM('rstrip', 2, defaults=(None,), - doc='S.rstrip([chars]) -> string or unicode\n\nReturn a' - ' copy of the string S with trailing whitespace' - ' removed.\nIf chars is given and not None, remove' - ' characters in chars instead.\nIf chars is unicode,' - ' S will be converted to unicode before stripping') -str_lstrip = SMM('lstrip', 2, defaults=(None,), - doc='S.lstrip([chars]) -> string or unicode\n\nReturn a' - ' copy of the string S with leading whitespace' - ' removed.\nIf chars is given and not None, remove' - ' characters in chars instead.\nIf chars is unicode,' - ' S will be converted to unicode before stripping') -str_center = SMM('center', 3, defaults=(' ',), - doc='S.center(width[, fillchar]) -> string\n\nReturn S' - ' centered in a string of length width. Padding' - ' is\ndone using the specified fill character' - ' (default is a space)') -str_count = SMM('count', 4, defaults=(0, maxint), - doc='S.count(sub[, start[, end]]) -> int\n\nReturn the' - ' number of occurrences of substring sub in' - ' string\nS[start:end]. Optional arguments start and' - ' end are\ninterpreted as in slice notation.') -str_endswith = SMM('endswith', 4, defaults=(0, maxint), - doc='S.endswith(suffix[, start[, end]]) -> bool\n\nReturn' - ' True if S ends with the specified suffix, False' - ' otherwise.\nWith optional start, test S beginning' - ' at that position.\nWith optional end, stop' - ' comparing S at that position.') -str_expandtabs = SMM('expandtabs', 2, defaults=(8,), - doc='S.expandtabs([tabsize]) -> string\n\nReturn a copy' - ' of S where all tab characters are expanded using' - ' spaces.\nIf tabsize is not given, a tab size of 8' - ' characters is assumed.') -str_splitlines = SMM('splitlines', 2, defaults=(0,), - doc='S.splitlines([keepends]) -> list of' - ' strings\n\nReturn a list of the lines in S,' - ' breaking at line boundaries.\nLine breaks are not' - ' included in the resulting list unless keepends\nis' - ' given and true.') -str_startswith = SMM('startswith', 4, defaults=(0, maxint), - doc='S.startswith(prefix[, start[, end]]) ->' - ' bool\n\nReturn True if S starts with the specified' - ' prefix, False otherwise.\nWith optional start, test' - ' S beginning at that position.\nWith optional end,' - ' stop comparing S at that position.') -str_translate = SMM('translate', 3, defaults=('',), #unicode mimic not supported now - doc='S.translate(table [,deletechars]) -> string\n\n' - 'Return a copy of the string S, where all characters' - ' occurring\nin the optional argument deletechars are' - ' removed, and the\nremaining characters have been' - ' mapped through the given\ntranslation table, which' - ' must be a string of length 256.') -str_decode = SMM('decode', 3, defaults=(None, None), - argnames=['encoding', 'errors'], - doc='S.decode([encoding[,errors]]) -> object\n\nDecodes S' - ' using the codec registered for encoding. encoding' - ' defaults\nto the default encoding. errors may be' - ' given to set a different error\nhandling scheme.' - " Default is 'strict' meaning that encoding errors" - ' raise\na UnicodeDecodeError. Other possible values' - " are 'ignore' and 'replace'\nas well as any other" - ' name registerd with codecs.register_error that' - ' is\nable to handle UnicodeDecodeErrors.') -str_encode = SMM('encode', 3, defaults=(None, None), - argnames=['encoding', 'errors'], - doc='S.encode([encoding[,errors]]) -> object\n\nEncodes S' - ' using the codec registered for encoding. encoding' - ' defaults\nto the default encoding. errors may be' - ' given to set a different error\nhandling scheme.' - " Default is 'strict' meaning that encoding errors" - ' raise\na UnicodeEncodeError. Other possible values' - " are 'ignore', 'replace' and\n'xmlcharrefreplace' as" - ' well as any other name registered' - ' with\ncodecs.register_error that is able to handle' - ' UnicodeEncodeErrors.') - -str_formatter_parser = SMM('_formatter_parser', 1) -str_formatter_field_name_split = SMM('_formatter_field_name_split', 1) - -def str_formatter_parser__ANY(space, w_str): - from pypy.objspace.std.newformat import str_template_formatter - tformat = str_template_formatter(space, space.str_w(w_str)) - return tformat.formatter_parser() - -def str_formatter_field_name_split__ANY(space, w_str): - from pypy.objspace.std.newformat import str_template_formatter - tformat = str_template_formatter(space, space.str_w(w_str)) - return tformat.formatter_field_name_split() - -register_all(vars(), globals()) - -# ____________________________________________________________ - - at unwrap_spec(w_object = WrappedDefault("")) -def descr__new__(space, w_stringtype, w_object): - # NB. the default value of w_object is really a *wrapped* empty string: - # there is gateway magic at work - from pypy.objspace.std.stringobject import W_StringObject - w_obj = space.str(w_object) - if space.is_w(w_stringtype, space.w_str): - return w_obj # XXX might be reworked when space.str() typechecks - value = space.str_w(w_obj) - w_obj = space.allocate_instance(W_StringObject, w_stringtype) - W_StringObject.__init__(w_obj, value) - return w_obj - -# ____________________________________________________________ - -str_typedef = StdTypeDef("str", basestring_typedef, - __new__ = interp2app(descr__new__), - __doc__ = '''str(object) -> string - -Return a nice string representation of the object. -If the argument is a string, the return value is the same object.''' - ) - -str_typedef.registermethods(globals()) - -# ____________________________________________________________ - -# Helpers for several string implementations - - at specialize.argtype(0) -def stringendswith(u_self, suffix, start, end): - begin = end - len(suffix) - if begin < start: - return False - for i in range(len(suffix)): - if u_self[begin+i] != suffix[i]: - return False - return True - - at specialize.argtype(0) -def stringstartswith(u_self, prefix, start, end): - stop = start + len(prefix) - if stop > end: - return False - for i in range(len(prefix)): - if u_self[start+i] != prefix[i]: - return False - return True diff --git a/pypy/objspace/std/test/test_builtinshortcut.py b/pypy/objspace/std/test/test_builtinshortcut.py --- a/pypy/objspace/std/test/test_builtinshortcut.py +++ b/pypy/objspace/std/test/test_builtinshortcut.py @@ -1,6 +1,6 @@ from pypy.objspace.std.test import test_userobject from pypy.objspace.std.test import test_setobject -from pypy.objspace.std.test import test_stringobject +from pypy.objspace.std.test import test_bytesobject WITH_BUILTINSHORTCUT = {'objspace.std.builtinshortcut': True} @@ -97,5 +97,5 @@ """) cls.w_FakeInt = w_fakeint -class AppTestString(test_stringobject.AppTestStringObject): +class AppTestString(test_bytesobject.AppTestBytesObject): spaceconfig = WITH_BUILTINSHORTCUT diff --git a/pypy/objspace/std/test/test_stringobject.py b/pypy/objspace/std/test/test_bytesobject.py rename from pypy/objspace/std/test/test_stringobject.py rename to pypy/objspace/std/test/test_bytesobject.py --- a/pypy/objspace/std/test/test_stringobject.py +++ b/pypy/objspace/std/test/test_bytesobject.py @@ -1,4 +1,4 @@ -class TestW_StringObject: +class TestW_BytesObject: def teardown_method(self, method): pass @@ -84,7 +84,7 @@ w_str = self.space.wrap('abcd') assert self.space.listview_str(w_str) == list("abcd") -class AppTestStringObject: +class AppTestBytesObject: def test_format_wrongchar(self): raises(ValueError, 'a%Zb'.__mod__, ((23,),)) @@ -770,12 +770,12 @@ iterable = "hello" raises(TypeError, len, iter(iterable)) -class AppTestPrebuilt(AppTestStringObject): +class AppTestPrebuilt(AppTestBytesObject): spaceconfig = {"objspace.std.withprebuiltchar": True} -class AppTestShare(AppTestStringObject): +class AppTestShare(AppTestBytesObject): spaceconfig = {"objspace.std.sharesmallstr": True} -class AppTestPrebuiltShare(AppTestStringObject): +class AppTestPrebuiltShare(AppTestBytesObject): spaceconfig = {"objspace.std.withprebuiltchar": True, "objspace.std.sharesmallstr": True} diff --git a/pypy/objspace/std/test/test_complexobject.py b/pypy/objspace/std/test/test_complexobject.py --- a/pypy/objspace/std/test/test_complexobject.py +++ b/pypy/objspace/std/test/test_complexobject.py @@ -3,7 +3,6 @@ pow__Complex_Complex_ANY from pypy.objspace.std import complextype as cobjtype from pypy.objspace.std.multimethod import FailedToImplement -from pypy.objspace.std.stringobject import W_StringObject from pypy.objspace.std import StdObjSpace EPS = 1e-9 diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py --- a/pypy/objspace/std/test/test_stdobjspace.py +++ b/pypy/objspace/std/test/test_stdobjspace.py @@ -37,15 +37,15 @@ assert space.sliceindices(w_obj, w(3)) == (1,2,3) def test_fastpath_isinstance(self): - from pypy.objspace.std.stringobject import W_StringObject + from pypy.objspace.std.bytesobject import W_BytesObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.iterobject import W_AbstractSeqIterObject from pypy.objspace.std.iterobject import W_SeqIterObject space = self.space - assert space._get_interplevel_cls(space.w_str) is W_StringObject + assert space._get_interplevel_cls(space.w_str) is W_BytesObject assert space._get_interplevel_cls(space.w_int) is W_IntObject - class X(W_StringObject): + class X(W_BytesObject): def __init__(self): pass @@ -58,11 +58,11 @@ assert cls is W_AbstractSeqIterObject def test_withstrbuf_fastpath_isinstance(self): - from pypy.objspace.std.stringobject import W_AbstractStringObject + from pypy.objspace.std.bytesobject import W_AbstractBytesObject space = gettestobjspace(withstrbuf=True) cls = space._get_interplevel_cls(space.w_str) - assert cls is W_AbstractStringObject + assert cls is W_AbstractBytesObject def test_wrap_various_unsigned_types(self): import sys diff --git a/pypy/objspace/std/test/test_strbufobject.py b/pypy/objspace/std/test/test_strbufobject.py --- a/pypy/objspace/std/test/test_strbufobject.py +++ b/pypy/objspace/std/test/test_strbufobject.py @@ -1,8 +1,8 @@ import py -from pypy.objspace.std.test import test_stringobject +from pypy.objspace.std.test import test_bytesobject -class AppTestStringObject(test_stringobject.AppTestStringObject): +class AppTestStringObject(test_bytesobject.AppTestBytesObject): spaceconfig = {"objspace.std.withstrbuf": True} def test_basic(self): diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -3,14 +3,13 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.module.unicodedata import unicodedb from pypy.objspace.std import newformat, slicetype +from pypy.objspace.std.bytesobject import (W_StringObject, + make_rsplit_with_delim, stringendswith, stringstartswith) from pypy.objspace.std.formatting import mod_format from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std.stringobject import ( - W_StringObject, make_rsplit_with_delim) -from pypy.objspace.std.stringtype import stringendswith, stringstartswith from pypy.objspace.std.register_all import register_all from rpython.rlib import jit from rpython.rlib.rarithmetic import ovfcheck @@ -943,9 +942,9 @@ # methods? class str_methods: - from pypy.objspace.std import stringtype + from pypy.objspace.std import bytesobject W_UnicodeObject = W_UnicodeObject - from pypy.objspace.std.stringobject import W_StringObject + from pypy.objspace.std.bytesobject import W_BytesObject as W_StringObject def str_strip__String_Unicode(space, w_self, w_chars): from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), @@ -990,4 +989,4 @@ from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'rsplit', w_delim, w_maxsplit) - register_all(vars(), stringtype) + register_all(vars(), bytesobject) diff --git a/pypy/objspace/std/unicodetype.py b/pypy/objspace/std/unicodetype.py --- a/pypy/objspace/std/unicodetype.py +++ b/pypy/objspace/std/unicodetype.py @@ -163,24 +163,24 @@ tformat = unicode_template_formatter(space, space.unicode_w(w_unicode)) return tformat.formatter_field_name_split() -# stuff imported from stringtype for interoperability +# stuff imported from bytesobject for interoperability -from pypy.objspace.std.stringtype import str_endswith as unicode_endswith -from pypy.objspace.std.stringtype import str_startswith as unicode_startswith -from pypy.objspace.std.stringtype import str_find as unicode_find -from pypy.objspace.std.stringtype import str_index as unicode_index -from pypy.objspace.std.stringtype import str_replace as unicode_replace -from pypy.objspace.std.stringtype import str_rfind as unicode_rfind -from pypy.objspace.std.stringtype import str_rindex as unicode_rindex -from pypy.objspace.std.stringtype import str_split as unicode_split -from pypy.objspace.std.stringtype import str_rsplit as unicode_rsplit -from pypy.objspace.std.stringtype import str_partition as unicode_partition -from pypy.objspace.std.stringtype import str_rpartition as unicode_rpartition -from pypy.objspace.std.stringtype import str_splitlines as unicode_splitlines -from pypy.objspace.std.stringtype import str_strip as unicode_strip -from pypy.objspace.std.stringtype import str_rstrip as unicode_rstrip -from pypy.objspace.std.stringtype import str_lstrip as unicode_lstrip -from pypy.objspace.std.stringtype import str_decode as unicode_decode +from pypy.objspace.std.bytesobject import str_endswith as unicode_endswith +from pypy.objspace.std.bytesobject import str_startswith as unicode_startswith +from pypy.objspace.std.bytesobject import str_find as unicode_find +from pypy.objspace.std.bytesobject import str_index as unicode_index +from pypy.objspace.std.bytesobject import str_replace as unicode_replace +from pypy.objspace.std.bytesobject import str_rfind as unicode_rfind +from pypy.objspace.std.bytesobject import str_rindex as unicode_rindex +from pypy.objspace.std.bytesobject import str_split as unicode_split +from pypy.objspace.std.bytesobject import str_rsplit as unicode_rsplit +from pypy.objspace.std.bytesobject import str_partition as unicode_partition +from pypy.objspace.std.bytesobject import str_rpartition as unicode_rpartition +from pypy.objspace.std.bytesobject import str_splitlines as unicode_splitlines +from pypy.objspace.std.bytesobject import str_strip as unicode_strip +from pypy.objspace.std.bytesobject import str_rstrip as unicode_rstrip +from pypy.objspace.std.bytesobject import str_lstrip as unicode_lstrip +from pypy.objspace.std.bytesobject import str_decode as unicode_decode # ____________________________________________________________ From noreply at buildbot.pypy.org Tue May 28 14:55:30 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:30 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: Merge bytearraytype.py into bytearrayobject.py. Message-ID: <20130528125530.DF5461C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64608:cdea8495ecff Date: 2013-05-24 22:47 +0200 http://bitbucket.org/pypy/pypy/changeset/cdea8495ecff/ Log: Merge bytearraytype.py into bytearrayobject.py. diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -1,11 +1,20 @@ """The builtin bytearray implementation""" +from pypy.interpreter.baseobjspace import ObjSpace, W_Root from pypy.interpreter.buffer import RWBuffer from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import interp2app from pypy.interpreter.signature import Signature +from pypy.objspace.std.bytesobject import ( + W_StringObject, str_decode, + str_count, str_index, str_rindex, str_find, str_rfind, str_replace, + str_startswith, str_endswith, str_islower, str_isupper, str_isalpha, + str_isalnum, str_isdigit, str_isspace, str_istitle, + str_upper, str_lower, str_title, str_swapcase, str_capitalize, + str_expandtabs, str_ljust, str_rjust, str_center, str_zfill, + str_join, str_split, str_rsplit, str_partition, str_rpartition, + str_splitlines, str_translate) from pypy.objspace.std import bytesobject -from pypy.objspace.std.bytearraytype import ( - getbytevalue, makebytearraydata_w, new_bytearray) from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.model import W_Object, registerimplementation @@ -13,15 +22,14 @@ from pypy.objspace.std.noneobject import W_NoneObject from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std.bytesobject import W_StringObject +from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index +from rpython.rlib.objectmodel import newlist_hint, resizelist_hint from rpython.rlib.rstring import StringBuilder class W_BytearrayObject(W_Object): - from pypy.objspace.std.bytearraytype import bytearray_typedef as typedef - def __init__(w_self, data): w_self.data = data @@ -29,6 +37,166 @@ """ representation for debugging purposes """ return "%s(%s)" % (w_self.__class__.__name__, ''.join(w_self.data)) + +bytearray_append = SMM('append', 2) +bytearray_extend = SMM('extend', 2) +bytearray_insert = SMM('insert', 3, + doc="B.insert(index, int) -> None\n\n" + "Insert a single item into the bytearray before " + "the given index.") + +bytearray_pop = SMM('pop', 2, defaults=(-1,), + doc="B.pop([index]) -> int\n\nRemove and return a " + "single item from B. If no index\nargument is given, " + "will pop the last value.") + +bytearray_remove = SMM('remove', 2, + doc="B.remove(int) -> None\n\n" + "Remove the first occurance of a value in B.") + +bytearray_reverse = SMM('reverse', 1, + doc="B.reverse() -> None\n\n" + "Reverse the order of the values in B in place.") + +bytearray_strip = SMM('strip', 2, defaults=(None,), + doc="B.strip([bytes]) -> bytearray\n\nStrip leading " + "and trailing bytes contained in the argument.\nIf " + "the argument is omitted, strip ASCII whitespace.") + +bytearray_lstrip = SMM('lstrip', 2, defaults=(None,), + doc="B.lstrip([bytes]) -> bytearray\n\nStrip leading " + "bytes contained in the argument.\nIf the argument is " + "omitted, strip leading ASCII whitespace.") + +bytearray_rstrip = SMM('rstrip', 2, defaults=(None,), + doc="'B.rstrip([bytes]) -> bytearray\n\nStrip trailing " + "bytes contained in the argument.\nIf the argument is " + "omitted, strip trailing ASCII whitespace.") + +def getbytevalue(space, w_value): + if space.isinstance_w(w_value, space.w_str): + string = space.str_w(w_value) + if len(string) != 1: + raise OperationError(space.w_ValueError, space.wrap( + "string must be of size 1")) + return string[0] + + value = space.getindex_w(w_value, None) + if not 0 <= value < 256: + # this includes the OverflowError in case the long is too large + raise OperationError(space.w_ValueError, space.wrap( + "byte must be in range(0, 256)")) + return chr(value) + +def new_bytearray(space, w_bytearraytype, data): + w_obj = space.allocate_instance(W_BytearrayObject, w_bytearraytype) + W_BytearrayObject.__init__(w_obj, data) + return w_obj + + +def descr__new__(space, w_bytearraytype, __args__): + return new_bytearray(space,w_bytearraytype, []) + + +def makebytearraydata_w(space, w_source): + # String-like argument + try: + string = space.bufferstr_new_w(w_source) + except OperationError, e: + if not e.match(space, space.w_TypeError): + raise + else: + return [c for c in string] + + # sequence of bytes + w_iter = space.iter(w_source) + length_hint = space.length_hint(w_source, 0) + data = newlist_hint(length_hint) + extended = 0 + while True: + try: + w_item = space.next(w_iter) + except OperationError, e: + if not e.match(space, space.w_StopIteration): + raise + break + value = getbytevalue(space, w_item) + data.append(value) + extended += 1 + if extended < length_hint: + resizelist_hint(data, extended) + return data + +def descr_bytearray__reduce__(space, w_self): + from pypy.objspace.std.bytearrayobject import W_BytearrayObject + assert isinstance(w_self, W_BytearrayObject) + w_dict = w_self.getdict(space) + if w_dict is None: + w_dict = space.w_None + return space.newtuple([ + space.type(w_self), space.newtuple([ + space.wrap(''.join(w_self.data).decode('latin-1')), + space.wrap('latin-1')]), + w_dict]) + +def _hex_digit_to_int(d): + val = ord(d) + if 47 < val < 58: + return val - 48 + if 96 < val < 103: + return val - 87 + return -1 + +def descr_fromhex(space, w_type, w_hexstring): + "bytearray.fromhex(string) -> bytearray\n" + "\n" + "Create a bytearray object from a string of hexadecimal numbers.\n" + "Spaces between two numbers are accepted.\n" + "Example: bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef')." + hexstring = space.str_w(w_hexstring) + hexstring = hexstring.lower() + data = [] + length = len(hexstring) + i = -2 + while True: + i += 2 + while i < length and hexstring[i] == ' ': + i += 1 + if i >= length: + break + if i+1 == length: + raise OperationError(space.w_ValueError, space.wrap( + "non-hexadecimal number found in fromhex() arg at position %d" % i)) + + top = _hex_digit_to_int(hexstring[i]) + if top == -1: + raise OperationError(space.w_ValueError, space.wrap( + "non-hexadecimal number found in fromhex() arg at position %d" % i)) + bot = _hex_digit_to_int(hexstring[i+1]) + if bot == -1: + raise OperationError(space.w_ValueError, space.wrap( + "non-hexadecimal number found in fromhex() arg at position %d" % (i+1,))) + data.append(chr(top*16 + bot)) + + # in CPython bytearray.fromhex is a staticmethod, so + # we ignore w_type and always return a bytearray + return new_bytearray(space, space.w_bytearray, data) + +# ____________________________________________________________ + +bytearray_typedef = W_BytearrayObject.typedef = StdTypeDef( + "bytearray", + __doc__ = '''bytearray() -> an empty bytearray +bytearray(sequence) -> bytearray initialized from sequence\'s items + +If the argument is a bytearray, the return value is the same object.''', + __new__ = interp2app(descr__new__), + __hash__ = None, + __reduce__ = interp2app(descr_bytearray__reduce__), + fromhex = interp2app(descr_fromhex, as_classmethod=True) + ) +bytearray_typedef.registermethods(globals()) + registerimplementation(W_BytearrayObject) init_signature = Signature(['source', 'encoding', 'errors'], None, None) @@ -552,7 +720,6 @@ # Mutability methods def bytearray_append__Bytearray_ANY(space, w_bytearray, w_item): - from pypy.objspace.std.bytearraytype import getbytevalue w_bytearray.data.append(getbytevalue(space, w_item)) def bytearray_extend__Bytearray_Bytearray(space, w_bytearray, w_other): @@ -570,7 +737,6 @@ return w_bytearray1 def setitem__Bytearray_ANY_ANY(space, w_bytearray, w_index, w_item): - from pypy.objspace.std.bytearraytype import getbytevalue idx = space.getindex_w(w_index, space.w_IndexError, "bytearray index") try: w_bytearray.data[idx] = getbytevalue(space, w_item) @@ -715,5 +881,4 @@ b = BytearrayBuffer(self.data) return space.wrap(b) -from pypy.objspace.std import bytearraytype -register_all(vars(), bytearraytype) +register_all(vars(), globals()) diff --git a/pypy/objspace/std/bytearraytype.py b/pypy/objspace/std/bytearraytype.py deleted file mode 100644 --- a/pypy/objspace/std/bytearraytype.py +++ /dev/null @@ -1,176 +0,0 @@ -from pypy.interpreter.baseobjspace import ObjSpace, W_Root -from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import interp2app -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM - -from pypy.objspace.std.bytesobject import ( - str_decode, - str_count, str_index, str_rindex, str_find, str_rfind, str_replace, - str_startswith, str_endswith, str_islower, str_isupper, str_isalpha, - str_isalnum, str_isdigit, str_isspace, str_istitle, - str_upper, str_lower, str_title, str_swapcase, str_capitalize, - str_expandtabs, str_ljust, str_rjust, str_center, str_zfill, - str_join, str_split, str_rsplit, str_partition, str_rpartition, - str_splitlines, str_translate) - -from rpython.rlib.objectmodel import newlist_hint, resizelist_hint - -bytearray_append = SMM('append', 2) -bytearray_extend = SMM('extend', 2) -bytearray_insert = SMM('insert', 3, - doc="B.insert(index, int) -> None\n\n" - "Insert a single item into the bytearray before " - "the given index.") - -bytearray_pop = SMM('pop', 2, defaults=(-1,), - doc="B.pop([index]) -> int\n\nRemove and return a " - "single item from B. If no index\nargument is given, " - "will pop the last value.") - -bytearray_remove = SMM('remove', 2, - doc="B.remove(int) -> None\n\n" - "Remove the first occurance of a value in B.") - -bytearray_reverse = SMM('reverse', 1, - doc="B.reverse() -> None\n\n" - "Reverse the order of the values in B in place.") - -bytearray_strip = SMM('strip', 2, defaults=(None,), - doc="B.strip([bytes]) -> bytearray\n\nStrip leading " - "and trailing bytes contained in the argument.\nIf " - "the argument is omitted, strip ASCII whitespace.") - -bytearray_lstrip = SMM('lstrip', 2, defaults=(None,), - doc="B.lstrip([bytes]) -> bytearray\n\nStrip leading " - "bytes contained in the argument.\nIf the argument is " - "omitted, strip leading ASCII whitespace.") - -bytearray_rstrip = SMM('rstrip', 2, defaults=(None,), - doc="'B.rstrip([bytes]) -> bytearray\n\nStrip trailing " - "bytes contained in the argument.\nIf the argument is " - "omitted, strip trailing ASCII whitespace.") - -def getbytevalue(space, w_value): - if space.isinstance_w(w_value, space.w_str): - string = space.str_w(w_value) - if len(string) != 1: - raise OperationError(space.w_ValueError, space.wrap( - "string must be of size 1")) - return string[0] - - value = space.getindex_w(w_value, None) - if not 0 <= value < 256: - # this includes the OverflowError in case the long is too large - raise OperationError(space.w_ValueError, space.wrap( - "byte must be in range(0, 256)")) - return chr(value) - -def new_bytearray(space, w_bytearraytype, data): - from pypy.objspace.std.bytearrayobject import W_BytearrayObject - w_obj = space.allocate_instance(W_BytearrayObject, w_bytearraytype) - W_BytearrayObject.__init__(w_obj, data) - return w_obj - - -def descr__new__(space, w_bytearraytype, __args__): - return new_bytearray(space,w_bytearraytype, []) - - -def makebytearraydata_w(space, w_source): - # String-like argument - try: - string = space.bufferstr_new_w(w_source) - except OperationError, e: - if not e.match(space, space.w_TypeError): - raise - else: - return [c for c in string] - - # sequence of bytes - w_iter = space.iter(w_source) - length_hint = space.length_hint(w_source, 0) - data = newlist_hint(length_hint) - extended = 0 - while True: - try: - w_item = space.next(w_iter) - except OperationError, e: - if not e.match(space, space.w_StopIteration): - raise - break - value = getbytevalue(space, w_item) - data.append(value) - extended += 1 - if extended < length_hint: - resizelist_hint(data, extended) - return data - -def descr_bytearray__reduce__(space, w_self): - from pypy.objspace.std.bytearrayobject import W_BytearrayObject - assert isinstance(w_self, W_BytearrayObject) - w_dict = w_self.getdict(space) - if w_dict is None: - w_dict = space.w_None - return space.newtuple([ - space.type(w_self), space.newtuple([ - space.wrap(''.join(w_self.data).decode('latin-1')), - space.wrap('latin-1')]), - w_dict]) - -def _hex_digit_to_int(d): - val = ord(d) - if 47 < val < 58: - return val - 48 - if 96 < val < 103: - return val - 87 - return -1 - -def descr_fromhex(space, w_type, w_hexstring): - "bytearray.fromhex(string) -> bytearray\n" - "\n" - "Create a bytearray object from a string of hexadecimal numbers.\n" - "Spaces between two numbers are accepted.\n" - "Example: bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef')." - hexstring = space.str_w(w_hexstring) - hexstring = hexstring.lower() - data = [] - length = len(hexstring) - i = -2 - while True: - i += 2 - while i < length and hexstring[i] == ' ': - i += 1 - if i >= length: - break - if i+1 == length: - raise OperationError(space.w_ValueError, space.wrap( - "non-hexadecimal number found in fromhex() arg at position %d" % i)) - - top = _hex_digit_to_int(hexstring[i]) - if top == -1: - raise OperationError(space.w_ValueError, space.wrap( - "non-hexadecimal number found in fromhex() arg at position %d" % i)) - bot = _hex_digit_to_int(hexstring[i+1]) - if bot == -1: - raise OperationError(space.w_ValueError, space.wrap( - "non-hexadecimal number found in fromhex() arg at position %d" % (i+1,))) - data.append(chr(top*16 + bot)) - - # in CPython bytearray.fromhex is a staticmethod, so - # we ignore w_type and always return a bytearray - return new_bytearray(space, space.w_bytearray, data) - -# ____________________________________________________________ - -bytearray_typedef = StdTypeDef("bytearray", - __doc__ = '''bytearray() -> an empty bytearray -bytearray(sequence) -> bytearray initialized from sequence\'s items - -If the argument is a bytearray, the return value is the same object.''', - __new__ = interp2app(descr__new__), - __hash__ = None, - __reduce__ = interp2app(descr_bytearray__reduce__), - fromhex = interp2app(descr_fromhex, as_classmethod=True) - ) -bytearray_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -38,7 +38,7 @@ from pypy.objspace.std.complextype import complex_typedef from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.bytesobject import str_typedef - from pypy.objspace.std.bytearraytype import bytearray_typedef + from pypy.objspace.std.bytearrayobject import bytearray_typedef from pypy.objspace.std.typeobject import type_typedef from pypy.objspace.std.slicetype import slice_typedef from pypy.objspace.std.longtype import long_typedef From noreply at buildbot.pypy.org Tue May 28 14:55:32 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:32 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: Add stubs for shared string methods. Message-ID: <20130528125532.061E01C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64609:c80d5be3241d Date: 2013-05-24 23:45 +0200 http://bitbucket.org/pypy/pypy/changeset/c80d5be3241d/ Log: Add stubs for shared string methods. diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -23,13 +23,14 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stdtypedef import StdTypeDef, SMM +from pypy.objspace.std.stringmethods import StringMethods from pypy.objspace.std.unicodeobject import W_UnicodeObject from pypy.objspace.std.util import get_positive_index from rpython.rlib.objectmodel import newlist_hint, resizelist_hint from rpython.rlib.rstring import StringBuilder -class W_BytearrayObject(W_Object): +class W_BytearrayObject(W_Object, StringMethods): def __init__(w_self, data): w_self.data = data @@ -37,6 +38,12 @@ """ representation for debugging purposes """ return "%s(%s)" % (w_self.__class__.__name__, ''.join(w_self.data)) + def new(self, value): + return W_BytearrayObject(value) + + def get_value(self): + return self.data + bytearray_append = SMM('append', 2) bytearray_extend = SMM('extend', 2) @@ -128,7 +135,6 @@ return data def descr_bytearray__reduce__(space, w_self): - from pypy.objspace.std.bytearrayobject import W_BytearrayObject assert isinstance(w_self, W_BytearrayObject) w_dict = w_self.getdict(space) if w_dict is None: @@ -193,8 +199,65 @@ __new__ = interp2app(descr__new__), __hash__ = None, __reduce__ = interp2app(descr_bytearray__reduce__), - fromhex = interp2app(descr_fromhex, as_classmethod=True) - ) + fromhex = interp2app(descr_fromhex, as_classmethod=True), + +# __repr__ = interp2app(W_BytearrayObject.descr_repr), +# __str__ = interp2app(W_BytearrayObject.descr_str), + +# __eq__ = interp2app(W_BytearrayObject.descr_eq), +# __ne__ = interp2app(W_BytearrayObject.descr_ne), +# __lt__ = interp2app(W_BytearrayObject.descr_lt), +# __le__ = interp2app(W_BytearrayObject.descr_le), +# __gt__ = interp2app(W_BytearrayObject.descr_gt), +# __ge__ = interp2app(W_BytearrayObject.descr_ge), + +# __len__ = interp2app(W_BytearrayObject.descr_len), +# __iter__ = interp2app(W_BytearrayObject.descr_iter), +# __contains__ = interp2app(W_BytearrayObject.descr_contains), + +# __add__ = interp2app(W_BytearrayObject.descr_add), + __mul__ = interp2app(W_BytearrayObject.descr_mul), + __rmul__ = interp2app(W_BytearrayObject.descr_mul), + +# __getitem__ = interp2app(W_BytearrayObject.descr_getitem), + +# capitalize = interp2app(W_BytearrayObject.descr_capitalize), +# center = interp2app(W_BytearrayObject.descr_center), +# count = interp2app(W_BytearrayObject.descr_count), +# decode = interp2app(W_BytearrayObject.descr_decode), +# expandtabs = interp2app(W_BytearrayObject.descr_expandtabs), +# find = interp2app(W_BytearrayObject.descr_find), +# rfind = interp2app(W_BytearrayObject.descr_rfind), +# index = interp2app(W_BytearrayObject.descr_index), +# rindex = interp2app(W_BytearrayObject.descr_rindex), +# isalnum = interp2app(W_BytearrayObject.descr_isalnum), +# isalpha = interp2app(W_BytearrayObject.descr_isalpha), +# isdigit = interp2app(W_BytearrayObject.descr_isdigit), +# islower = interp2app(W_BytearrayObject.descr_islower), +# isspace = interp2app(W_BytearrayObject.descr_isspace), +# istitle = interp2app(W_BytearrayObject.descr_istitle), +# isupper = interp2app(W_BytearrayObject.descr_isupper), +# join = interp2app(W_BytearrayObject.descr_join), +# ljust = interp2app(W_BytearrayObject.descr_ljust), +# rjust = interp2app(W_BytearrayObject.descr_rjust), +# lower = interp2app(W_BytearrayObject.descr_lower), +# partition = interp2app(W_BytearrayObject.descr_partition), +# rpartition = interp2app(W_BytearrayObject.descr_rpartition), +# replace = interp2app(W_BytearrayObject.descr_replace), +# split = interp2app(W_BytearrayObject.descr_split), +# rsplit = interp2app(W_BytearrayObject.descr_rsplit), +# splitlines = interp2app(W_BytearrayObject.descr_splitlines), +# startswith = interp2app(W_BytearrayObject.descr_startswith), +# endswith = interp2app(W_BytearrayObject.descr_endswith), +# strip = interp2app(W_BytearrayObject.descr_strip), +# lstrip = interp2app(W_BytearrayObject.descr_lstrip), +# rstrip = interp2app(W_BytearrayObject.descr_rstrip), +# swapcase = interp2app(W_BytearrayObject.descr_swapcase), +# title = interp2app(W_BytearrayObject.descr_title), +# translate = interp2app(W_BytearrayObject.descr_translate), +# upper = interp2app(W_BytearrayObject.descr_upper), +# zfill = interp2app(W_BytearrayObject.descr_zfill), +) bytearray_typedef.registermethods(globals()) registerimplementation(W_BytearrayObject) @@ -317,22 +380,6 @@ data1 = [c for c in space.str_w(w_str)] return W_BytearrayObject(data1 + data2) -def mul_bytearray_times(space, w_bytearray, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - data = w_bytearray.data - return W_BytearrayObject(data * times) - -def mul__Bytearray_ANY(space, w_bytearray, w_times): - return mul_bytearray_times(space, w_bytearray, w_times) - -def mul__ANY_Bytearray(space, w_times, w_bytearray): - return mul_bytearray_times(space, w_bytearray, w_times) - def inplace_mul__Bytearray_ANY(space, w_bytearray, w_times): try: times = space.getindex_w(w_times, space.w_OverflowError) diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/stringmethods.py @@ -0,0 +1,153 @@ +class StringMethods(object): + _mixin_ = True + + def descr_eq(self, space): + pass + + def descr_ne(self, space): + pass + + def descr_lt(self, space): + pass + + def descr_le(self, space): + pass + + def descr_gt(self, space): + pass + + def descr_ge(self, space): + pass + + def descr_len(self, space): + pass + + def descr_iter(self, space): + pass + + def descr_contains(self, space): + pass + + def descr_add(self, space): + pass + + def descr_mul(self, space, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + return NotImplemented + raise + data = self.get_value() + return self.new(data * times) + + def descr_getitem(self, space): + pass + + def descr_capitalize(self, space): + pass + + def descr_center(self, space): + pass + + def descr_count(self, space): + pass + + def descr_decode(self, space): + pass + + def descr_expandtabs(self, space): + pass + + def descr_find(self, space): + pass + + def descr_rfind(self, space): + pass + + def descr_index(self, space): + pass + + def descr_rindex(self, space): + pass + + def descr_isalnum(self, space): + pass + + def descr_isalpha(self, space): + pass + + def descr_isdigit(self, space): + pass + + def descr_islower(self, space): + pass + + def descr_isspace(self, space): + pass + + def descr_istitle(self, space): + pass + + def descr_isupper(self, space): + pass + + def descr_join(self, space): + pass + + def descr_ljust(self, space): + pass + + def descr_rjust(self, space): + pass + + def descr_lower(self, space): + pass + + def descr_partition(self, space): + pass + + def descr_rpartition(self, space): + pass + + def descr_replace(self, space): + pass + + def descr_split(self, space): + pass + + def descr_rsplit(self, space): + pass + + def descr_splitlines(self, space): + pass + + def descr_startswith(self, space): + pass + + def descr_endswith(self, space): + pass + + def descr_strip(self, space): + pass + + def descr_lstrip(self, space): + pass + + def descr_rstrip(self, space): + pass + + def descr_swapcase(self, space): + pass + + def descr_title(self, space): + pass + + def descr_translate(self, space): + pass + + def descr_upper(self, space): + pass + + def descr_zfill(self, space): + pass From noreply at buildbot.pypy.org Tue May 28 14:55:32 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:32 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: Rename internal methods. Message-ID: <20130528125532.E95341C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64610:1ec0c56555fc Date: 2013-05-25 00:23 +0200 http://bitbucket.org/pypy/pypy/changeset/1ec0c56555fc/ Log: Rename internal methods. diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -38,10 +38,10 @@ """ representation for debugging purposes """ return "%s(%s)" % (w_self.__class__.__name__, ''.join(w_self.data)) - def new(self, value): + def _new(self, value): return W_BytearrayObject(value) - def get_value(self): + def _self_value(self): return self.data diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -1,6 +1,12 @@ class StringMethods(object): _mixin_ = True + def _new(self, value): + raise NotImplementedError + + def _self_value(self): + raise NotImplementedError + def descr_eq(self, space): pass @@ -38,8 +44,7 @@ if e.match(space, space.w_TypeError): return NotImplemented raise - data = self.get_value() - return self.new(data * times) + return self._new(self._self_value() * times) def descr_getitem(self, space): pass From noreply at buildbot.pypy.org Tue May 28 14:55:34 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:34 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: Make W_BytesObject inherit StringMethods and let it use the shared __mul__/__rmul__ implementation. Message-ID: <20130528125534.1F9BF1C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64611:82a10bd78400 Date: 2013-05-25 01:18 +0200 http://bitbucket.org/pypy/pypy/changeset/82a10bd78400/ Log: Make W_BytesObject inherit StringMethods and let it use the shared __mul__/__rmul__ implementation. diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -41,9 +41,14 @@ def _new(self, value): return W_BytearrayObject(value) - def _self_value(self): + def _len(self): + return len(self.data) + + def _val(self): return self.data +W_BytearrayObject.EMPTY = W_BytearrayObject([]) + bytearray_append = SMM('append', 2) bytearray_extend = SMM('extend', 2) diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/bytesobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -14,6 +14,7 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stdtypedef import StdTypeDef, SMM +from pypy.objspace.std.stringmethods import StringMethods from rpython.rlib import jit from rpython.rlib.jit import we_are_jitted from rpython.rlib.objectmodel import (compute_hash, compute_unique_id, @@ -52,7 +53,7 @@ return space.unicode_w(decode_object(space, w_self, encoding, errors)) -class W_BytesObject(W_AbstractBytesObject): +class W_BytesObject(W_AbstractBytesObject, StringMethods): _immutable_fields_ = ['_value'] def __init__(w_self, str): @@ -71,6 +72,16 @@ def listview_str(w_self): return _create_list_from_string(w_self._value) + def _new(self, value): + return W_BytesObject(value) + + def _len(self): + return len(self._value) + + def _val(self): + return self._value + + W_StringObject = W_BytesObject def _create_list_from_string(value): @@ -361,8 +372,65 @@ __doc__ = '''str(object) -> string Return a nice string representation of the object. -If the argument is a string, the return value is the same object.''' - ) +If the argument is a string, the return value is the same object.''', + +# __repr__ = interp2app(W_BytesObject.descr_repr), +# __str__ = interp2app(W_BytesObject.descr_str), + +# __eq__ = interp2app(W_BytesObject.descr_eq), +# __ne__ = interp2app(W_BytesObject.descr_ne), +# __lt__ = interp2app(W_BytesObject.descr_lt), +# __le__ = interp2app(W_BytesObject.descr_le), +# __gt__ = interp2app(W_BytesObject.descr_gt), +# __ge__ = interp2app(W_BytesObject.descr_ge), + +# __len__ = interp2app(W_BytesObject.descr_len), +# __iter__ = interp2app(W_BytesObject.descr_iter), +# __contains__ = interp2app(W_BytesObject.descr_contains), + +# __add__ = interp2app(W_BytesObject.descr_add), + __mul__ = interp2app(W_BytesObject.descr_mul), + __rmul__ = interp2app(W_BytesObject.descr_mul), + +# __getitem__ = interp2app(W_BytesObject.descr_getitem), + +# capitalize = interp2app(W_BytesObject.descr_capitalize), +# center = interp2app(W_BytesObject.descr_center), +# count = interp2app(W_BytesObject.descr_count), +# decode = interp2app(W_BytesObject.descr_decode), +# expandtabs = interp2app(W_BytesObject.descr_expandtabs), +# find = interp2app(W_BytesObject.descr_find), +# rfind = interp2app(W_BytesObject.descr_rfind), +# index = interp2app(W_BytesObject.descr_index), +# rindex = interp2app(W_BytesObject.descr_rindex), +# isalnum = interp2app(W_BytesObject.descr_isalnum), +# isalpha = interp2app(W_BytesObject.descr_isalpha), +# isdigit = interp2app(W_BytesObject.descr_isdigit), +# islower = interp2app(W_BytesObject.descr_islower), +# isspace = interp2app(W_BytesObject.descr_isspace), +# istitle = interp2app(W_BytesObject.descr_istitle), +# isupper = interp2app(W_BytesObject.descr_isupper), +# join = interp2app(W_BytesObject.descr_join), +# ljust = interp2app(W_BytesObject.descr_ljust), +# rjust = interp2app(W_BytesObject.descr_rjust), +# lower = interp2app(W_BytesObject.descr_lower), +# partition = interp2app(W_BytesObject.descr_partition), +# rpartition = interp2app(W_BytesObject.descr_rpartition), +# replace = interp2app(W_BytesObject.descr_replace), +# split = interp2app(W_BytesObject.descr_split), +# rsplit = interp2app(W_BytesObject.descr_rsplit), +# splitlines = interp2app(W_BytesObject.descr_splitlines), +# startswith = interp2app(W_BytesObject.descr_startswith), +# endswith = interp2app(W_BytesObject.descr_endswith), +# strip = interp2app(W_BytesObject.descr_strip), +# lstrip = interp2app(W_BytesObject.descr_lstrip), +# rstrip = interp2app(W_BytesObject.descr_rstrip), +# swapcase = interp2app(W_BytesObject.descr_swapcase), +# title = interp2app(W_BytesObject.descr_title), +# translate = interp2app(W_BytesObject.descr_translate), +# upper = interp2app(W_BytesObject.descr_upper), +# zfill = interp2app(W_BytesObject.descr_zfill), +) str_typedef.registermethods(globals()) @@ -1208,28 +1276,6 @@ else: return sliced(space, s, start, stop, w_str) -def mul_string_times(space, w_str, w_times): - try: - mul = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if mul <= 0: - return W_BytesObject.EMPTY - input = w_str._value - if len(input) == 1: - s = input[0] * mul - else: - s = input * mul - return W_BytesObject(s) - -def mul__String_ANY(space, w_str, w_times): - return mul_string_times(space, w_str, w_times) - -def mul__ANY_String(space, w_times, w_str): - return mul_string_times(space, w_str, w_times) - def add__String_String(space, w_left, w_right): right = w_right._value left = w_left._value diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -4,7 +4,10 @@ def _new(self, value): raise NotImplementedError - def _self_value(self): + def _len(self): + raise NotImplementedError + + def _val(self): raise NotImplementedError def descr_eq(self, space): @@ -44,7 +47,11 @@ if e.match(space, space.w_TypeError): return NotImplemented raise - return self._new(self._self_value() * times) + if times <= 0: + return self.EMPTY + if self._len() == 1: + return self._new(self._val()[0] * times) + return self._new(self._val() * times) def descr_getitem(self, space): pass From noreply at buildbot.pypy.org Tue May 28 14:55:36 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:36 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: Kill unicodetype.py. Message-ID: <20130528125536.3ED381C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64612:ecebc3f985bb Date: 2013-05-25 01:38 +0200 http://bitbucket.org/pypy/pypy/changeset/ecebc3f985bb/ Log: Kill unicodetype.py. diff --git a/pypy/interpreter/unicodehelper.py b/pypy/interpreter/unicodehelper.py --- a/pypy/interpreter/unicodehelper.py +++ b/pypy/interpreter/unicodehelper.py @@ -30,7 +30,7 @@ # ____________________________________________________________ def encode(space, w_data, encoding=None, errors='strict'): - from pypy.objspace.std.unicodetype import encode_object + from pypy.objspace.std.unicodeobject import encode_object return encode_object(space, w_data, encoding, errors) # These functions take and return unwrapped rpython strings and unicodes diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py --- a/pypy/module/cpyext/unicodeobject.py +++ b/pypy/module/cpyext/unicodeobject.py @@ -12,7 +12,7 @@ from pypy.module.cpyext.stringobject import PyString_Check from pypy.module.sys.interp_encoding import setdefaultencoding from pypy.module._codecs.interp_codecs import CodecState -from pypy.objspace.std import unicodeobject, unicodetype, bytesobject +from pypy.objspace.std import unicodeobject, bytesobject from rpython.rlib import runicode from rpython.tool.sourcetools import func_renamer import sys @@ -262,7 +262,7 @@ def PyUnicode_GetDefaultEncoding(space): """Returns the currently active default encoding.""" if default_encoding[0] == '\x00': - encoding = unicodetype.getdefaultencoding(space) + encoding = unicodeobject.getdefaultencoding(space) i = 0 while i < len(encoding) and i < DEFAULT_ENCODING_SIZE: default_encoding[i] = encoding[i] @@ -293,7 +293,7 @@ encoding = rffi.charp2str(llencoding) if llerrors: errors = rffi.charp2str(llerrors) - return unicodetype.encode_object(space, w_unicode, encoding, errors) + return unicodeobject.encode_object(space, w_unicode, encoding, errors) @cpython_api([PyObject, CONST_STRING, CONST_STRING], PyObject) def PyUnicode_AsEncodedString(space, w_unicode, llencoding, llerrors): @@ -316,7 +316,7 @@ if not PyUnicode_Check(space, w_unicode): PyErr_BadArgument(space) - return unicodetype.encode_object(space, w_unicode, 'unicode-escape', 'strict') + return unicodeobject.encode_object(space, w_unicode, 'unicode-escape', 'strict') @cpython_api([CONST_WSTRING, Py_ssize_t], PyObject) def PyUnicode_FromUnicode(space, wchar_p, length): @@ -463,7 +463,7 @@ exception was raised by the codec.""" if not PyUnicode_Check(space, w_unicode): PyErr_BadArgument(space) - return unicodetype.encode_object(space, w_unicode, encoding, "strict") + return unicodeobject.encode_object(space, w_unicode, encoding, "strict") @cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject) @func_renamer('PyUnicode_Decode%s' % suffix) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -4,7 +4,7 @@ from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.objspace.std.bytesobject import str_typedef from pypy.objspace.std.floattype import float_typedef -from pypy.objspace.std.unicodetype import unicode_typedef, unicode_from_object +from pypy.objspace.std.unicodeobject import unicode_typedef, unicode_from_object from pypy.objspace.std.inttype import int_typedef from pypy.objspace.std.complextype import complex_typedef from rpython.rlib.rarithmetic import LONG_BIT diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -284,7 +284,7 @@ # Unicode argument if not space.is_w(w_encoding, space.w_None): - from pypy.objspace.std.unicodetype import ( + from pypy.objspace.std.unicodeobject import ( _get_encoding_and_errors, encode_object ) encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/bytesobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -42,7 +42,7 @@ def unicode_w(w_self, space): # Use the default encoding. - from pypy.objspace.std.unicodetype import (unicode_from_string, + from pypy.objspace.std.unicodeobject import (unicode_from_string, decode_object, _get_encoding_and_errors) w_defaultencoding = space.call_function(space.sys.get( 'getdefaultencoding')) @@ -1393,7 +1393,7 @@ return W_BytesObject(buf.build()) def str_decode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None): - from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \ + from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \ unicode_from_string, decode_object encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) if encoding is None and errors is None: @@ -1401,7 +1401,7 @@ return decode_object(space, w_string, encoding, errors) def str_encode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None): - from pypy.objspace.std.unicodetype import _get_encoding_and_errors, \ + from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \ encode_object encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) return encode_object(space, w_string, encoding, errors) diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py --- a/pypy/objspace/std/formatting.py +++ b/pypy/objspace/std/formatting.py @@ -352,7 +352,7 @@ length = len(r) if do_unicode and isinstance(r, str): # convert string to unicode explicitely here - from pypy.objspace.std.unicodetype import plain_str2unicode + from pypy.objspace.std.unicodeobject import plain_str2unicode r = plain_str2unicode(self.space, r) prec = self.prec if prec == -1 and self.width == 0: @@ -441,7 +441,7 @@ if not got_unicode: w_value = space.call_function(space.w_unicode, w_value) else: - from pypy.objspace.std.unicodetype import unicode_from_object + from pypy.objspace.std.unicodeobject import unicode_from_object w_value = unicode_from_object(space, w_value) s = space.unicode_w(w_value) self.std_wp(s) @@ -509,7 +509,7 @@ result = formatter.format() except NeedUnicodeFormattingError: # fall through to the unicode case - from pypy.objspace.std.unicodetype import plain_str2unicode + from pypy.objspace.std.unicodeobject import plain_str2unicode fmt = plain_str2unicode(space, fmt) else: return space.wrap(result) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -42,7 +42,7 @@ from pypy.objspace.std.typeobject import type_typedef from pypy.objspace.std.slicetype import slice_typedef from pypy.objspace.std.longtype import long_typedef - from pypy.objspace.std.unicodetype import unicode_typedef + from pypy.objspace.std.unicodeobject import unicode_typedef from pypy.objspace.std.nonetype import none_typedef self.pythontypes = [value for key, value in result.__dict__.items() if not key.startswith('_')] # don't look diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -34,7 +34,7 @@ # types from pypy.objspace.std.inttype import wrapint -from pypy.objspace.std.unicodetype import wrapunicode +from pypy.objspace.std.unicodeobject import wrapunicode class StdObjSpace(ObjSpace, DescrOperation): """The standard object space, implementing a general-purpose object diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -1,22 +1,28 @@ """The builtin unicode implementation""" +from sys import maxint +from pypy.interpreter import unicodehelper from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.module.unicodedata import unicodedb from pypy.objspace.std import newformat, slicetype +from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.bytesobject import (W_StringObject, make_rsplit_with_delim, stringendswith, stringstartswith) from pypy.objspace.std.formatting import mod_format from pypy.objspace.std.model import W_Object, registerimplementation from pypy.objspace.std.multimethod import FailedToImplement from pypy.objspace.std.noneobject import W_NoneObject +from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice -from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from rpython.rlib import jit +from rpython.rlib.objectmodel import (compute_hash, compute_unique_id, + specialize) from rpython.rlib.rarithmetic import ovfcheck -from rpython.rlib.objectmodel import ( - compute_hash, compute_unique_id, specialize) from rpython.rlib.rstring import UnicodeBuilder -from rpython.rlib.runicode import make_unicode_escape_function +from rpython.rlib.runicode import (str_decode_utf_8, str_decode_ascii, + unicode_encode_utf_8, unicode_encode_ascii, make_unicode_escape_function) from rpython.tool.sourcetools import func_with_new_name @@ -39,7 +45,6 @@ class W_UnicodeObject(W_AbstractUnicodeObject): - from pypy.objspace.std.unicodetype import unicode_typedef as typedef _immutable_fields_ = ['_value'] def __init__(w_self, unistr): @@ -68,6 +73,347 @@ def listview_unicode(w_self): return _create_list_from_unicode(w_self._value) + +def wrapunicode(space, uni): + return W_UnicodeObject(uni) + +def plain_str2unicode(space, s): + try: + return unicode(s) + except UnicodeDecodeError: + for i in range(len(s)): + if ord(s[i]) > 127: + raise OperationError( + space.w_UnicodeDecodeError, + space.newtuple([ + space.wrap('ascii'), + space.wrap(s), + space.wrap(i), + space.wrap(i+1), + space.wrap("ordinal not in range(128)")])) + assert False, "unreachable" + + +unicode_capitalize = SMM('capitalize', 1, + doc='S.capitalize() -> unicode\n\nReturn a' + ' capitalized version of S, i.e. make the first' + ' character\nhave upper case.') +unicode_center = SMM('center', 3, defaults=(' ',), + doc='S.center(width[, fillchar]) -> unicode\n\nReturn' + ' S centered in a Unicode string of length width.' + ' Padding is\ndone using the specified fill' + ' character (default is a space)') +unicode_count = SMM('count', 4, defaults=(0, maxint), + doc='S.count(sub[, start[, end]]) -> int\n\nReturn' + ' the number of occurrences of substring sub in' + ' Unicode string\nS[start:end]. Optional' + ' arguments start and end are\ninterpreted as in' + ' slice notation.') +unicode_encode = SMM('encode', 3, defaults=(None, None), + argnames=['encoding', 'errors'], + doc='S.encode([encoding[,errors]]) -> string or' + ' unicode\n\nEncodes S using the codec registered' + ' for encoding. encoding defaults\nto the default' + ' encoding. errors may be given to set a' + ' different error\nhandling scheme. Default is' + " 'strict' meaning that encoding errors raise\na" + ' UnicodeEncodeError. Other possible values are' + " 'ignore', 'replace' and\n'xmlcharrefreplace' as" + ' well as any other name registered' + ' with\ncodecs.register_error that can handle' + ' UnicodeEncodeErrors.') +unicode_expandtabs = SMM('expandtabs', 2, defaults=(8,), + doc='S.expandtabs([tabsize]) -> unicode\n\nReturn a' + ' copy of S where all tab characters are expanded' + ' using spaces.\nIf tabsize is not given, a tab' + ' size of 8 characters is assumed.') +unicode_format = SMM('format', 1, general__args__=True, + doc='S.format() -> new style formating') +unicode_isalnum = SMM('isalnum', 1, + doc='S.isalnum() -> bool\n\nReturn True if all' + ' characters in S are alphanumeric\nand there is' + ' at least one character in S, False otherwise.') +unicode_isalpha = SMM('isalpha', 1, + doc='S.isalpha() -> bool\n\nReturn True if all' + ' characters in S are alphabetic\nand there is at' + ' least one character in S, False otherwise.') +unicode_isdecimal = SMM('isdecimal', 1, + doc='S.isdecimal() -> bool\n\nReturn True if there' + ' are only decimal characters in S,\nFalse' + ' otherwise.') +unicode_isdigit = SMM('isdigit', 1, + doc='S.isdigit() -> bool\n\nReturn True if all' + ' characters in S are digits\nand there is at' + ' least one character in S, False otherwise.') +unicode_islower = SMM('islower', 1, + doc='S.islower() -> bool\n\nReturn True if all cased' + ' characters in S are lowercase and there is\nat' + ' least one cased character in S, False' + ' otherwise.') +unicode_isnumeric = SMM('isnumeric', 1, + doc='S.isnumeric() -> bool\n\nReturn True if there' + ' are only numeric characters in S,\nFalse' + ' otherwise.') +unicode_isspace = SMM('isspace', 1, + doc='S.isspace() -> bool\n\nReturn True if all' + ' characters in S are whitespace\nand there is at' + ' least one character in S, False otherwise.') +unicode_istitle = SMM('istitle', 1, + doc='S.istitle() -> bool\n\nReturn True if S is a' + ' titlecased string and there is at least' + ' one\ncharacter in S, i.e. upper- and titlecase' + ' characters may only\nfollow uncased characters' + ' and lowercase characters only cased' + ' ones.\nReturn False otherwise.') +unicode_isupper = SMM('isupper', 1, + doc='S.isupper() -> bool\n\nReturn True if all cased' + ' characters in S are uppercase and there is\nat' + ' least one cased character in S, False' + ' otherwise.') +unicode_join = SMM('join', 2, + doc='S.join(sequence) -> unicode\n\nReturn a string' + ' which is the concatenation of the strings in' + ' the\nsequence. The separator between elements' + ' is S.') +unicode_ljust = SMM('ljust', 3, defaults=(' ',), + doc='S.ljust(width[, fillchar]) -> int\n\nReturn S' + ' left justified in a Unicode string of length' + ' width. Padding is\ndone using the specified' + ' fill character (default is a space).') +unicode_lower = SMM('lower', 1, + doc='S.lower() -> unicode\n\nReturn a copy of the' + ' string S converted to lowercase.') +unicode_rjust = SMM('rjust', 3, defaults=(' ',), + doc='S.rjust(width[, fillchar]) -> unicode\n\nReturn' + ' S right justified in a Unicode string of length' + ' width. Padding is\ndone using the specified' + ' fill character (default is a space).') +unicode_swapcase = SMM('swapcase', 1, + doc='S.swapcase() -> unicode\n\nReturn a copy of S' + ' with uppercase characters converted to' + ' lowercase\nand vice versa.') +unicode_title = SMM('title', 1, + doc='S.title() -> unicode\n\nReturn a titlecased' + ' version of S, i.e. words start with title' + ' case\ncharacters, all remaining cased' + ' characters have lower case.') +unicode_translate = SMM('translate', 2, + doc='S.translate(table) -> unicode\n\nReturn a copy' + ' of the string S, where all characters have been' + ' mapped\nthrough the given translation table,' + ' which must be a mapping of\nUnicode ordinals to' + ' Unicode ordinals, Unicode strings or' + ' None.\nUnmapped characters are left untouched.' + ' Characters mapped to None\nare deleted.') +unicode_upper = SMM('upper', 1, + doc='S.upper() -> unicode\n\nReturn a copy of S' + ' converted to uppercase.') +unicode_zfill = SMM('zfill', 2, + doc='S.zfill(width) -> unicode\n\nPad a numeric' + ' string x with zeros on the left, to fill a' + ' field\nof the specified width. The string x is' + ' never truncated.') + +unicode_formatter_parser = SMM('_formatter_parser', 1) +unicode_formatter_field_name_split = SMM('_formatter_field_name_split', 1) + +def unicode_formatter_parser__ANY(space, w_unicode): + from pypy.objspace.std.newformat import unicode_template_formatter + tformat = unicode_template_formatter(space, space.unicode_w(w_unicode)) + return tformat.formatter_parser() + +def unicode_formatter_field_name_split__ANY(space, w_unicode): + from pypy.objspace.std.newformat import unicode_template_formatter + tformat = unicode_template_formatter(space, space.unicode_w(w_unicode)) + return tformat.formatter_field_name_split() + +# stuff imported from bytesobject for interoperability + +from pypy.objspace.std.bytesobject import str_endswith as unicode_endswith +from pypy.objspace.std.bytesobject import str_startswith as unicode_startswith +from pypy.objspace.std.bytesobject import str_find as unicode_find +from pypy.objspace.std.bytesobject import str_index as unicode_index +from pypy.objspace.std.bytesobject import str_replace as unicode_replace +from pypy.objspace.std.bytesobject import str_rfind as unicode_rfind +from pypy.objspace.std.bytesobject import str_rindex as unicode_rindex +from pypy.objspace.std.bytesobject import str_split as unicode_split +from pypy.objspace.std.bytesobject import str_rsplit as unicode_rsplit +from pypy.objspace.std.bytesobject import str_partition as unicode_partition +from pypy.objspace.std.bytesobject import str_rpartition as unicode_rpartition +from pypy.objspace.std.bytesobject import str_splitlines as unicode_splitlines +from pypy.objspace.std.bytesobject import str_strip as unicode_strip +from pypy.objspace.std.bytesobject import str_rstrip as unicode_rstrip +from pypy.objspace.std.bytesobject import str_lstrip as unicode_lstrip +from pypy.objspace.std.bytesobject import str_decode as unicode_decode + +# ____________________________________________________________ + +def getdefaultencoding(space): + return space.sys.defaultencoding + +def _get_encoding_and_errors(space, w_encoding, w_errors): + if space.is_none(w_encoding): + encoding = None + else: + encoding = space.str_w(w_encoding) + if space.is_none(w_errors): + errors = None + else: + errors = space.str_w(w_errors) + return encoding, errors + +def encode_object(space, w_object, encoding, errors): + if encoding is None: + # Get the encoder functions as a wrapped object. + # This lookup is cached. + w_encoder = space.sys.get_w_default_encoder() + else: + if errors is None or errors == 'strict': + if encoding == 'ascii': + u = space.unicode_w(w_object) + eh = unicodehelper.encode_error_handler(space) + return space.wrap(unicode_encode_ascii( + u, len(u), None, errorhandler=eh)) + if encoding == 'utf-8': + u = space.unicode_w(w_object) + eh = unicodehelper.encode_error_handler(space) + return space.wrap(unicode_encode_utf_8( + u, len(u), None, errorhandler=eh, + allow_surrogates=True)) + from pypy.module._codecs.interp_codecs import lookup_codec + w_encoder = space.getitem(lookup_codec(space, encoding), space.wrap(0)) + if errors is None: + w_errors = space.wrap('strict') + else: + w_errors = space.wrap(errors) + w_restuple = space.call_function(w_encoder, w_object, w_errors) + w_retval = space.getitem(w_restuple, space.wrap(0)) + if not space.isinstance_w(w_retval, space.w_str): + raise operationerrfmt(space.w_TypeError, + "encoder did not return an string object (type '%s')", + space.type(w_retval).getname(space)) + return w_retval + +def decode_object(space, w_obj, encoding, errors): + if encoding is None: + encoding = getdefaultencoding(space) + if errors is None or errors == 'strict': + if encoding == 'ascii': + # XXX error handling + s = space.bufferstr_w(w_obj) + eh = unicodehelper.decode_error_handler(space) + return space.wrap(str_decode_ascii( + s, len(s), None, final=True, errorhandler=eh)[0]) + if encoding == 'utf-8': + s = space.bufferstr_w(w_obj) + eh = unicodehelper.decode_error_handler(space) + return space.wrap(str_decode_utf_8( + s, len(s), None, final=True, errorhandler=eh, + allow_surrogates=True)[0]) + w_codecs = space.getbuiltinmodule("_codecs") + w_decode = space.getattr(w_codecs, space.wrap("decode")) + if errors is None: + w_retval = space.call_function(w_decode, w_obj, space.wrap(encoding)) + else: + w_retval = space.call_function(w_decode, w_obj, space.wrap(encoding), + space.wrap(errors)) + return w_retval + + +def unicode_from_encoded_object(space, w_obj, encoding, errors): + w_retval = decode_object(space, w_obj, encoding, errors) + if not space.isinstance_w(w_retval, space.w_unicode): + raise operationerrfmt(space.w_TypeError, + "decoder did not return an unicode object (type '%s')", + space.type(w_retval).getname(space)) + return w_retval + +def unicode_from_object(space, w_obj): + if space.is_w(space.type(w_obj), space.w_unicode): + return w_obj + elif space.is_w(space.type(w_obj), space.w_str): + w_res = w_obj + else: + w_unicode_method = space.lookup(w_obj, "__unicode__") + # obscure workaround: for the next two lines see + # test_unicode_conversion_with__str__ + if w_unicode_method is None: + if space.isinstance_w(w_obj, space.w_unicode): + return space.wrap(space.unicode_w(w_obj)) + w_unicode_method = space.lookup(w_obj, "__str__") + if w_unicode_method is not None: + w_res = space.get_and_call_function(w_unicode_method, w_obj) + else: + w_res = space.str(w_obj) + if space.isinstance_w(w_res, space.w_unicode): + return w_res + return unicode_from_encoded_object(space, w_res, None, "strict") + +def unicode_from_string(space, w_str): + # this is a performance and bootstrapping hack + encoding = getdefaultencoding(space) + if encoding != 'ascii': + return unicode_from_encoded_object(space, w_str, encoding, "strict") + s = space.str_w(w_str) + try: + return W_UnicodeObject(s.decode("ascii")) + except UnicodeDecodeError: + # raising UnicodeDecodeError is messy, "please crash for me" + return unicode_from_encoded_object(space, w_str, "ascii", "strict") + +def unicode_decode__unitypedef_ANY_ANY(space, w_unicode, w_encoding=None, + w_errors=None): + return space.call_method(space.str(w_unicode), 'decode', + w_encoding, w_errors) + + + at unwrap_spec(w_string = WrappedDefault("")) +def descr_new_(space, w_unicodetype, w_string, w_encoding=None, w_errors=None): + # NB. the default value of w_obj is really a *wrapped* empty string: + # there is gateway magic at work + w_obj = w_string + + encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) + # convoluted logic for the case when unicode subclass has a __unicode__ + # method, we need to call this method + if (space.is_w(space.type(w_obj), space.w_unicode) or + (space.isinstance_w(w_obj, space.w_unicode) and + space.findattr(w_obj, space.wrap('__unicode__')) is None)): + if encoding is not None or errors is not None: + raise OperationError(space.w_TypeError, + space.wrap('decoding Unicode is not supported')) + w_value = w_obj + else: + if encoding is None and errors is None: + w_value = unicode_from_object(space, w_obj) + else: + w_value = unicode_from_encoded_object(space, w_obj, + encoding, errors) + if space.is_w(w_unicodetype, space.w_unicode): + return w_value + + assert isinstance(w_value, W_UnicodeObject) + w_newobj = space.allocate_instance(W_UnicodeObject, w_unicodetype) + W_UnicodeObject.__init__(w_newobj, w_value._value) + return w_newobj + +# ____________________________________________________________ + +unicode_typedef = W_UnicodeObject.typedef = StdTypeDef( + "unicode", basestring_typedef, + __new__ = interp2app(descr_new_), + __doc__ = '''unicode(string [, encoding[, errors]]) -> object + +Create a new Unicode object from the given encoded string. +encoding defaults to the current default string encoding. +errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'.''' + ) + +unicode_typedef.registermethods(globals()) + +unitypedef = unicode_typedef + + def _create_list_from_unicode(value): # need this helper function to allow the jit to look inside and inline # listview_unicode @@ -108,7 +454,6 @@ # string-to-unicode delegation def delegate_String2Unicode(space, w_str): - from pypy.objspace.std.unicodetype import unicode_from_string w_uni = unicode_from_string(space, w_str) assert isinstance(w_uni, W_UnicodeObject) # help the annotator! return w_uni @@ -131,19 +476,16 @@ return result def str__Unicode(space, w_uni): - from pypy.objspace.std.unicodetype import encode_object return encode_object(space, w_uni, None, None) def eq__Unicode_Unicode(space, w_left, w_right): return space.newbool(w_left._value == w_right._value) def eq__Unicode_String(space, w_uni, w_str): - from pypy.objspace.std.unicodetype import unicode_from_string return _unicode_string_comparison(space, w_uni, w_str, False, unicode_from_string) def ne__Unicode_String(space, w_uni, w_str): - from pypy.objspace.std.unicodetype import unicode_from_string return _unicode_string_comparison(space, w_uni, w_str, True, unicode_from_string) @@ -169,7 +511,6 @@ # this function is needed to make 'abc'.__add__(u'def') return # u'abcdef' instead of NotImplemented. This is what occurs on # top of CPython. - from pypy.objspace.std.unicodetype import unicode_from_string # XXX fragile implementation detail: for "string + unicode subclass", # if the unicode subclass overrides __radd__(), then it will be # called (see test_str_unicode_concat_overrides). This occurs as a @@ -182,13 +523,11 @@ # this function is needed to make 'abc'.__radd__(u'def') return # u'defabc', although it's completely unclear if that's necessary # given that CPython doesn't even have a method str.__radd__(). - from pypy.objspace.std.unicodetype import unicode_from_string return space.add(w_left, unicode_from_string(space, w_right)) # Note about "unicode + string subclass": look for # "cpython bug compatibility" in descroperation.py def contains__String_Unicode(space, w_container, w_item): - from pypy.objspace.std.unicodetype import unicode_from_string return space.contains(unicode_from_string(space, w_container), w_item ) @@ -394,7 +733,6 @@ def unicode_strip__Unicode_Unicode(space, w_self, w_chars): return _strip(space, w_self, w_chars, 1, 1) def unicode_strip__Unicode_String(space, w_self, w_chars): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(w_self, 'strip', unicode_from_string(space, w_chars)) @@ -403,7 +741,6 @@ def unicode_lstrip__Unicode_Unicode(space, w_self, w_chars): return _strip(space, w_self, w_chars, 1, 0) def unicode_lstrip__Unicode_String(space, w_self, w_chars): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(w_self, 'lstrip', unicode_from_string(space, w_chars)) @@ -413,7 +750,6 @@ def unicode_rstrip__Unicode_Unicode(space, w_self, w_chars): return _strip(space, w_self, w_chars, 0, 1) def unicode_rstrip__Unicode_String(space, w_self, w_chars): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(w_self, 'rstrip', unicode_from_string(space, w_chars)) @@ -808,8 +1144,6 @@ w_encoding=None, w_errors=None): - from pypy.objspace.std.unicodetype import _get_encoding_and_errors - from pypy.objspace.std.unicodetype import encode_object encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) w_retval = encode_object(space, w_unistr, encoding, errors) return w_retval @@ -924,15 +1258,13 @@ def format__Unicode_ANY(space, w_unicode, w_format_spec): if not space.isinstance_w(w_format_spec, space.w_unicode): w_format_spec = space.call_function(space.w_unicode, w_format_spec) - from pypy.objspace.std.unicodetype import unicode_from_object w_unicode = unicode_from_object(space, w_unicode) spec = space.unicode_w(w_format_spec) formatter = newformat.unicode_formatter(space, spec) return formatter.format_string(space.unicode_w(w_unicode)) -from pypy.objspace.std import unicodetype -register_all(vars(), unicodetype) +register_all(vars(), globals()) # str.strip(unicode) needs to convert self to unicode and call unicode.strip we # use the following magic to register strip_string_unicode as a String @@ -946,47 +1278,36 @@ W_UnicodeObject = W_UnicodeObject from pypy.objspace.std.bytesobject import W_BytesObject as W_StringObject def str_strip__String_Unicode(space, w_self, w_chars): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'strip', w_chars) def str_lstrip__String_Unicode(space, w_self, w_chars): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'lstrip', w_chars) def str_rstrip__String_Unicode(space, w_self, w_chars): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'rstrip', w_chars) def str_count__String_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'count', w_substr, w_start, w_end) def str_find__String_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'find', w_substr, w_start, w_end) def str_rfind__String_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'rfind', w_substr, w_start, w_end) def str_index__String_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'index', w_substr, w_start, w_end) def str_rindex__String_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'rindex', w_substr, w_start, w_end) def str_replace__String_Unicode_Unicode_ANY(space, w_self, w_old, w_new, w_maxsplit): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'replace', w_old, w_new, w_maxsplit) def str_split__String_Unicode_ANY(space, w_self, w_delim, w_maxsplit): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'split', w_delim, w_maxsplit) def str_rsplit__String_Unicode_ANY(space, w_self, w_delim, w_maxsplit): - from pypy.objspace.std.unicodetype import unicode_from_string return space.call_method(unicode_from_string(space, w_self), 'rsplit', w_delim, w_maxsplit) register_all(vars(), bytesobject) diff --git a/pypy/objspace/std/unicodetype.py b/pypy/objspace/std/unicodetype.py deleted file mode 100644 --- a/pypy/objspace/std/unicodetype.py +++ /dev/null @@ -1,352 +0,0 @@ -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault -from pypy.interpreter import unicodehelper -from pypy.objspace.std.stdtypedef import StdTypeDef, SMM -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.basestringtype import basestring_typedef -from rpython.rlib.runicode import str_decode_utf_8, str_decode_ascii,\ - unicode_encode_utf_8, unicode_encode_ascii - -from sys import maxint - -def wrapunicode(space, uni): - from pypy.objspace.std.unicodeobject import W_UnicodeObject - return W_UnicodeObject(uni) - -def plain_str2unicode(space, s): - try: - return unicode(s) - except UnicodeDecodeError: - for i in range(len(s)): - if ord(s[i]) > 127: - raise OperationError( - space.w_UnicodeDecodeError, - space.newtuple([ - space.wrap('ascii'), - space.wrap(s), - space.wrap(i), - space.wrap(i+1), - space.wrap("ordinal not in range(128)")])) - assert False, "unreachable" - - -unicode_capitalize = SMM('capitalize', 1, - doc='S.capitalize() -> unicode\n\nReturn a' - ' capitalized version of S, i.e. make the first' - ' character\nhave upper case.') -unicode_center = SMM('center', 3, defaults=(' ',), - doc='S.center(width[, fillchar]) -> unicode\n\nReturn' - ' S centered in a Unicode string of length width.' - ' Padding is\ndone using the specified fill' - ' character (default is a space)') -unicode_count = SMM('count', 4, defaults=(0, maxint), - doc='S.count(sub[, start[, end]]) -> int\n\nReturn' - ' the number of occurrences of substring sub in' - ' Unicode string\nS[start:end]. Optional' - ' arguments start and end are\ninterpreted as in' - ' slice notation.') -unicode_encode = SMM('encode', 3, defaults=(None, None), - argnames=['encoding', 'errors'], - doc='S.encode([encoding[,errors]]) -> string or' - ' unicode\n\nEncodes S using the codec registered' - ' for encoding. encoding defaults\nto the default' - ' encoding. errors may be given to set a' - ' different error\nhandling scheme. Default is' - " 'strict' meaning that encoding errors raise\na" - ' UnicodeEncodeError. Other possible values are' - " 'ignore', 'replace' and\n'xmlcharrefreplace' as" - ' well as any other name registered' - ' with\ncodecs.register_error that can handle' - ' UnicodeEncodeErrors.') -unicode_expandtabs = SMM('expandtabs', 2, defaults=(8,), - doc='S.expandtabs([tabsize]) -> unicode\n\nReturn a' - ' copy of S where all tab characters are expanded' - ' using spaces.\nIf tabsize is not given, a tab' - ' size of 8 characters is assumed.') -unicode_format = SMM('format', 1, general__args__=True, - doc='S.format() -> new style formating') -unicode_isalnum = SMM('isalnum', 1, - doc='S.isalnum() -> bool\n\nReturn True if all' - ' characters in S are alphanumeric\nand there is' - ' at least one character in S, False otherwise.') -unicode_isalpha = SMM('isalpha', 1, - doc='S.isalpha() -> bool\n\nReturn True if all' - ' characters in S are alphabetic\nand there is at' - ' least one character in S, False otherwise.') -unicode_isdecimal = SMM('isdecimal', 1, - doc='S.isdecimal() -> bool\n\nReturn True if there' - ' are only decimal characters in S,\nFalse' - ' otherwise.') -unicode_isdigit = SMM('isdigit', 1, - doc='S.isdigit() -> bool\n\nReturn True if all' - ' characters in S are digits\nand there is at' - ' least one character in S, False otherwise.') -unicode_islower = SMM('islower', 1, - doc='S.islower() -> bool\n\nReturn True if all cased' - ' characters in S are lowercase and there is\nat' - ' least one cased character in S, False' - ' otherwise.') -unicode_isnumeric = SMM('isnumeric', 1, - doc='S.isnumeric() -> bool\n\nReturn True if there' - ' are only numeric characters in S,\nFalse' - ' otherwise.') -unicode_isspace = SMM('isspace', 1, - doc='S.isspace() -> bool\n\nReturn True if all' - ' characters in S are whitespace\nand there is at' - ' least one character in S, False otherwise.') -unicode_istitle = SMM('istitle', 1, - doc='S.istitle() -> bool\n\nReturn True if S is a' - ' titlecased string and there is at least' - ' one\ncharacter in S, i.e. upper- and titlecase' - ' characters may only\nfollow uncased characters' - ' and lowercase characters only cased' - ' ones.\nReturn False otherwise.') -unicode_isupper = SMM('isupper', 1, - doc='S.isupper() -> bool\n\nReturn True if all cased' - ' characters in S are uppercase and there is\nat' - ' least one cased character in S, False' - ' otherwise.') -unicode_join = SMM('join', 2, - doc='S.join(sequence) -> unicode\n\nReturn a string' - ' which is the concatenation of the strings in' - ' the\nsequence. The separator between elements' - ' is S.') -unicode_ljust = SMM('ljust', 3, defaults=(' ',), - doc='S.ljust(width[, fillchar]) -> int\n\nReturn S' - ' left justified in a Unicode string of length' - ' width. Padding is\ndone using the specified' - ' fill character (default is a space).') -unicode_lower = SMM('lower', 1, - doc='S.lower() -> unicode\n\nReturn a copy of the' - ' string S converted to lowercase.') -unicode_rjust = SMM('rjust', 3, defaults=(' ',), - doc='S.rjust(width[, fillchar]) -> unicode\n\nReturn' - ' S right justified in a Unicode string of length' - ' width. Padding is\ndone using the specified' - ' fill character (default is a space).') -unicode_swapcase = SMM('swapcase', 1, - doc='S.swapcase() -> unicode\n\nReturn a copy of S' - ' with uppercase characters converted to' - ' lowercase\nand vice versa.') -unicode_title = SMM('title', 1, - doc='S.title() -> unicode\n\nReturn a titlecased' - ' version of S, i.e. words start with title' - ' case\ncharacters, all remaining cased' - ' characters have lower case.') -unicode_translate = SMM('translate', 2, - doc='S.translate(table) -> unicode\n\nReturn a copy' - ' of the string S, where all characters have been' - ' mapped\nthrough the given translation table,' - ' which must be a mapping of\nUnicode ordinals to' - ' Unicode ordinals, Unicode strings or' - ' None.\nUnmapped characters are left untouched.' - ' Characters mapped to None\nare deleted.') -unicode_upper = SMM('upper', 1, - doc='S.upper() -> unicode\n\nReturn a copy of S' - ' converted to uppercase.') -unicode_zfill = SMM('zfill', 2, - doc='S.zfill(width) -> unicode\n\nPad a numeric' - ' string x with zeros on the left, to fill a' - ' field\nof the specified width. The string x is' - ' never truncated.') - -unicode_formatter_parser = SMM('_formatter_parser', 1) -unicode_formatter_field_name_split = SMM('_formatter_field_name_split', 1) - -def unicode_formatter_parser__ANY(space, w_unicode): - from pypy.objspace.std.newformat import unicode_template_formatter - tformat = unicode_template_formatter(space, space.unicode_w(w_unicode)) - return tformat.formatter_parser() - -def unicode_formatter_field_name_split__ANY(space, w_unicode): - from pypy.objspace.std.newformat import unicode_template_formatter - tformat = unicode_template_formatter(space, space.unicode_w(w_unicode)) - return tformat.formatter_field_name_split() - -# stuff imported from bytesobject for interoperability - -from pypy.objspace.std.bytesobject import str_endswith as unicode_endswith -from pypy.objspace.std.bytesobject import str_startswith as unicode_startswith -from pypy.objspace.std.bytesobject import str_find as unicode_find -from pypy.objspace.std.bytesobject import str_index as unicode_index -from pypy.objspace.std.bytesobject import str_replace as unicode_replace -from pypy.objspace.std.bytesobject import str_rfind as unicode_rfind -from pypy.objspace.std.bytesobject import str_rindex as unicode_rindex -from pypy.objspace.std.bytesobject import str_split as unicode_split -from pypy.objspace.std.bytesobject import str_rsplit as unicode_rsplit -from pypy.objspace.std.bytesobject import str_partition as unicode_partition -from pypy.objspace.std.bytesobject import str_rpartition as unicode_rpartition -from pypy.objspace.std.bytesobject import str_splitlines as unicode_splitlines -from pypy.objspace.std.bytesobject import str_strip as unicode_strip -from pypy.objspace.std.bytesobject import str_rstrip as unicode_rstrip -from pypy.objspace.std.bytesobject import str_lstrip as unicode_lstrip -from pypy.objspace.std.bytesobject import str_decode as unicode_decode - -# ____________________________________________________________ - -def getdefaultencoding(space): - return space.sys.defaultencoding - -def _get_encoding_and_errors(space, w_encoding, w_errors): - if space.is_none(w_encoding): - encoding = None - else: - encoding = space.str_w(w_encoding) - if space.is_none(w_errors): - errors = None - else: - errors = space.str_w(w_errors) - return encoding, errors - -def encode_object(space, w_object, encoding, errors): - if encoding is None: - # Get the encoder functions as a wrapped object. - # This lookup is cached. - w_encoder = space.sys.get_w_default_encoder() - else: - if errors is None or errors == 'strict': - if encoding == 'ascii': - u = space.unicode_w(w_object) - eh = unicodehelper.encode_error_handler(space) - return space.wrap(unicode_encode_ascii( - u, len(u), None, errorhandler=eh)) - if encoding == 'utf-8': - u = space.unicode_w(w_object) - eh = unicodehelper.encode_error_handler(space) - return space.wrap(unicode_encode_utf_8( - u, len(u), None, errorhandler=eh, - allow_surrogates=True)) - from pypy.module._codecs.interp_codecs import lookup_codec - w_encoder = space.getitem(lookup_codec(space, encoding), space.wrap(0)) - if errors is None: - w_errors = space.wrap('strict') - else: - w_errors = space.wrap(errors) - w_restuple = space.call_function(w_encoder, w_object, w_errors) - w_retval = space.getitem(w_restuple, space.wrap(0)) - if not space.isinstance_w(w_retval, space.w_str): - raise operationerrfmt(space.w_TypeError, - "encoder did not return an string object (type '%s')", - space.type(w_retval).getname(space)) - return w_retval - -def decode_object(space, w_obj, encoding, errors): - if encoding is None: - encoding = getdefaultencoding(space) - if errors is None or errors == 'strict': - if encoding == 'ascii': - # XXX error handling - s = space.bufferstr_w(w_obj) - eh = unicodehelper.decode_error_handler(space) - return space.wrap(str_decode_ascii( - s, len(s), None, final=True, errorhandler=eh)[0]) - if encoding == 'utf-8': - s = space.bufferstr_w(w_obj) - eh = unicodehelper.decode_error_handler(space) - return space.wrap(str_decode_utf_8( - s, len(s), None, final=True, errorhandler=eh, - allow_surrogates=True)[0]) - w_codecs = space.getbuiltinmodule("_codecs") - w_decode = space.getattr(w_codecs, space.wrap("decode")) - if errors is None: - w_retval = space.call_function(w_decode, w_obj, space.wrap(encoding)) - else: - w_retval = space.call_function(w_decode, w_obj, space.wrap(encoding), - space.wrap(errors)) - return w_retval - - -def unicode_from_encoded_object(space, w_obj, encoding, errors): - w_retval = decode_object(space, w_obj, encoding, errors) - if not space.isinstance_w(w_retval, space.w_unicode): - raise operationerrfmt(space.w_TypeError, - "decoder did not return an unicode object (type '%s')", - space.type(w_retval).getname(space)) - return w_retval - -def unicode_from_object(space, w_obj): - if space.is_w(space.type(w_obj), space.w_unicode): - return w_obj - elif space.is_w(space.type(w_obj), space.w_str): - w_res = w_obj - else: - w_unicode_method = space.lookup(w_obj, "__unicode__") - # obscure workaround: for the next two lines see - # test_unicode_conversion_with__str__ - if w_unicode_method is None: - if space.isinstance_w(w_obj, space.w_unicode): - return space.wrap(space.unicode_w(w_obj)) - w_unicode_method = space.lookup(w_obj, "__str__") - if w_unicode_method is not None: - w_res = space.get_and_call_function(w_unicode_method, w_obj) - else: - w_res = space.str(w_obj) - if space.isinstance_w(w_res, space.w_unicode): - return w_res - return unicode_from_encoded_object(space, w_res, None, "strict") - -def unicode_from_string(space, w_str): - # this is a performance and bootstrapping hack - encoding = getdefaultencoding(space) - from pypy.objspace.std.unicodeobject import W_UnicodeObject - if encoding != 'ascii': - return unicode_from_encoded_object(space, w_str, encoding, "strict") - s = space.str_w(w_str) - try: - return W_UnicodeObject(s.decode("ascii")) - except UnicodeDecodeError: - # raising UnicodeDecodeError is messy, "please crash for me" - return unicode_from_encoded_object(space, w_str, "ascii", "strict") - -def unicode_decode__unitypedef_ANY_ANY(space, w_unicode, w_encoding=None, - w_errors=None): - return space.call_method(space.str(w_unicode), 'decode', - w_encoding, w_errors) - - - at unwrap_spec(w_string = WrappedDefault("")) -def descr_new_(space, w_unicodetype, w_string, w_encoding=None, w_errors=None): - # NB. the default value of w_obj is really a *wrapped* empty string: - # there is gateway magic at work - from pypy.objspace.std.unicodeobject import W_UnicodeObject - w_obj = w_string - - encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) - # convoluted logic for the case when unicode subclass has a __unicode__ - # method, we need to call this method - if (space.is_w(space.type(w_obj), space.w_unicode) or - (space.isinstance_w(w_obj, space.w_unicode) and - space.findattr(w_obj, space.wrap('__unicode__')) is None)): - if encoding is not None or errors is not None: - raise OperationError(space.w_TypeError, - space.wrap('decoding Unicode is not supported')) - w_value = w_obj - else: - if encoding is None and errors is None: - w_value = unicode_from_object(space, w_obj) - else: - w_value = unicode_from_encoded_object(space, w_obj, - encoding, errors) - if space.is_w(w_unicodetype, space.w_unicode): - return w_value - - assert isinstance(w_value, W_UnicodeObject) - w_newobj = space.allocate_instance(W_UnicodeObject, w_unicodetype) - W_UnicodeObject.__init__(w_newobj, w_value._value) - return w_newobj - -# ____________________________________________________________ - -unicode_typedef = StdTypeDef("unicode", basestring_typedef, - __new__ = interp2app(descr_new_), - __doc__ = '''unicode(string [, encoding[, errors]]) -> object - -Create a new Unicode object from the given encoded string. -encoding defaults to the current default string encoding. -errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'.''' - ) - -unicode_typedef.registermethods(globals()) - -unitypedef = unicode_typedef -register_all(vars(), globals()) From noreply at buildbot.pypy.org Tue May 28 14:55:38 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:38 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: Make W_UnicodeObject use shared __mul__/__rmul__ implementation. Message-ID: <20130528125538.13AA81C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64613:bb62ce8ae4ae Date: 2013-05-25 01:46 +0200 http://bitbucket.org/pypy/pypy/changeset/bb62ce8ae4ae/ Log: Make W_UnicodeObject use shared __mul__/__rmul__ implementation. diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -16,6 +16,7 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stdtypedef import StdTypeDef, SMM +from pypy.objspace.std.stringmethods import StringMethods from rpython.rlib import jit from rpython.rlib.objectmodel import (compute_hash, compute_unique_id, specialize) @@ -44,7 +45,7 @@ return space.wrap(compute_unique_id(space.unicode_w(self))) -class W_UnicodeObject(W_AbstractUnicodeObject): +class W_UnicodeObject(W_AbstractUnicodeObject, StringMethods): _immutable_fields_ = ['_value'] def __init__(w_self, unistr): @@ -73,6 +74,15 @@ def listview_unicode(w_self): return _create_list_from_unicode(w_self._value) + def _new(self, value): + return W_UnicodeObject(value) + + def _len(self): + return len(self._value) + + def _val(self): + return self._value + def wrapunicode(space, uni): return W_UnicodeObject(uni) @@ -406,8 +416,65 @@ Create a new Unicode object from the given encoded string. encoding defaults to the current default string encoding. -errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'.''' - ) +errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'.''', + +# __repr__ = interp2app(W_UnicodeObject.descr_repr), +# __str__ = interp2app(W_UnicodeObject.descr_str), + +# __eq__ = interp2app(W_UnicodeObject.descr_eq), +# __ne__ = interp2app(W_UnicodeObject.descr_ne), +# __lt__ = interp2app(W_UnicodeObject.descr_lt), +# __le__ = interp2app(W_UnicodeObject.descr_le), +# __gt__ = interp2app(W_UnicodeObject.descr_gt), +# __ge__ = interp2app(W_UnicodeObject.descr_ge), + +# __len__ = interp2app(W_UnicodeObject.descr_len), +# __iter__ = interp2app(W_UnicodeObject.descr_iter), +# __contains__ = interp2app(W_UnicodeObject.descr_contains), + +# __add__ = interp2app(W_UnicodeObject.descr_add), + __mul__ = interp2app(W_UnicodeObject.descr_mul), + __rmul__ = interp2app(W_UnicodeObject.descr_mul), + +# __getitem__ = interp2app(W_UnicodeObject.descr_getitem), + +# capitalize = interp2app(W_UnicodeObject.descr_capitalize), +# center = interp2app(W_UnicodeObject.descr_center), +# count = interp2app(W_UnicodeObject.descr_count), +# decode = interp2app(W_UnicodeObject.descr_decode), +# expandtabs = interp2app(W_UnicodeObject.descr_expandtabs), +# find = interp2app(W_UnicodeObject.descr_find), +# rfind = interp2app(W_UnicodeObject.descr_rfind), +# index = interp2app(W_UnicodeObject.descr_index), +# rindex = interp2app(W_UnicodeObject.descr_rindex), +# isalnum = interp2app(W_UnicodeObject.descr_isalnum), +# isalpha = interp2app(W_UnicodeObject.descr_isalpha), +# isdigit = interp2app(W_UnicodeObject.descr_isdigit), +# islower = interp2app(W_UnicodeObject.descr_islower), +# isspace = interp2app(W_UnicodeObject.descr_isspace), +# istitle = interp2app(W_UnicodeObject.descr_istitle), +# isupper = interp2app(W_UnicodeObject.descr_isupper), +# join = interp2app(W_UnicodeObject.descr_join), +# ljust = interp2app(W_UnicodeObject.descr_ljust), +# rjust = interp2app(W_UnicodeObject.descr_rjust), +# lower = interp2app(W_UnicodeObject.descr_lower), +# partition = interp2app(W_UnicodeObject.descr_partition), +# rpartition = interp2app(W_UnicodeObject.descr_rpartition), +# replace = interp2app(W_UnicodeObject.descr_replace), +# split = interp2app(W_UnicodeObject.descr_split), +# rsplit = interp2app(W_UnicodeObject.descr_rsplit), +# splitlines = interp2app(W_UnicodeObject.descr_splitlines), +# startswith = interp2app(W_UnicodeObject.descr_startswith), +# endswith = interp2app(W_UnicodeObject.descr_endswith), +# strip = interp2app(W_UnicodeObject.descr_strip), +# lstrip = interp2app(W_UnicodeObject.descr_lstrip), +# rstrip = interp2app(W_UnicodeObject.descr_rstrip), +# swapcase = interp2app(W_UnicodeObject.descr_swapcase), +# title = interp2app(W_UnicodeObject.descr_title), +# translate = interp2app(W_UnicodeObject.descr_translate), +# upper = interp2app(W_UnicodeObject.descr_upper), +# zfill = interp2app(W_UnicodeObject.descr_zfill), +) unicode_typedef.registermethods(globals()) @@ -612,25 +679,6 @@ start, stop = normalize_simple_slice(space, len(uni), w_start, w_stop) return W_UnicodeObject(uni[start:stop]) -def mul__Unicode_ANY(space, w_uni, w_times): - try: - times = space.getindex_w(w_times, space.w_OverflowError) - except OperationError, e: - if e.match(space, space.w_TypeError): - raise FailedToImplement - raise - if times <= 0: - return W_UnicodeObject.EMPTY - input = w_uni._value - if len(input) == 1: - result = input[0] * times - else: - result = input * times - return W_UnicodeObject(result) - -def mul__ANY_Unicode(space, w_times, w_uni): - return mul__Unicode_ANY(space, w_uni, w_times) - def _isspace(uchar): return unicodedb.isspace(ord(uchar)) From noreply at buildbot.pypy.org Tue May 28 14:55:39 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:39 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: fixes Message-ID: <20130528125539.074761C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64614:0c3ec61773b7 Date: 2013-05-25 02:10 +0200 http://bitbucket.org/pypy/pypy/changeset/0c3ec61773b7/ Log: fixes diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -1,3 +1,6 @@ +from pypy.interpreter.error import OperationError + + class StringMethods(object): _mixin_ = True @@ -45,7 +48,7 @@ times = space.getindex_w(w_times, space.w_OverflowError) except OperationError, e: if e.match(space, space.w_TypeError): - return NotImplemented + return space.w_NotImplemented raise if times <= 0: return self.EMPTY From noreply at buildbot.pypy.org Tue May 28 14:55:40 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:40 +0200 (CEST) Subject: [pypy-commit] pypy remove-string-smm: This branch is superseded by refactor-str-types. Message-ID: <20130528125540.071941C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: remove-string-smm Changeset: r64615:ef9c84a9a1aa Date: 2013-05-25 14:58 +0200 http://bitbucket.org/pypy/pypy/changeset/ef9c84a9a1aa/ Log: This branch is superseded by refactor-str-types. From noreply at buildbot.pypy.org Tue May 28 14:55:41 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:41 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: IN-PROGRESS: Share more code between str and unicode. str/unicode tests pass but it's not translatable. Message-ID: <20130528125541.19F851C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64616:8eb92c3424de Date: 2013-05-28 14:52 +0200 http://bitbucket.org/pypy/pypy/changeset/8eb92c3424de/ Log: IN-PROGRESS: Share more code between str and unicode. str/unicode tests pass but it's not translatable. diff too long, truncating to 2000 out of 3748 lines diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -239,6 +239,11 @@ msg = "__int__ returned non-int (type '%s')" raise operationerrfmt(space.w_TypeError, msg, typename) + def ord(self, space): + typename = space.type(self).getname(space) + msg = "ord() expected string of length 1, but %s found" + raise operationerrfmt(space.w_TypeError, msg, typename) + def __spacebind__(self, space): return self @@ -1366,6 +1371,9 @@ # This is here mostly just for gateway.int_unwrapping_space_method(). return bool(self.int_w(w_obj)) + def ord(self, w_obj): + return w_obj.ord(self) + # This is all interface for gateway.py. def gateway_int_w(self, w_obj): if self.isinstance_w(w_obj, self.w_float): diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -5,15 +5,6 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app from pypy.interpreter.signature import Signature -from pypy.objspace.std.bytesobject import ( - W_StringObject, str_decode, - str_count, str_index, str_rindex, str_find, str_rfind, str_replace, - str_startswith, str_endswith, str_islower, str_isupper, str_isalpha, - str_isalnum, str_isdigit, str_isspace, str_istitle, - str_upper, str_lower, str_title, str_swapcase, str_capitalize, - str_expandtabs, str_ljust, str_rjust, str_center, str_zfill, - str_join, str_split, str_rsplit, str_partition, str_rpartition, - str_splitlines, str_translate) from pypy.objspace.std import bytesobject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.inttype import wrapint @@ -47,6 +38,9 @@ def _val(self): return self.data + def _op_val(self, w_other): + return w_other.data + W_BytearrayObject.EMPTY = W_BytearrayObject([]) @@ -405,10 +399,6 @@ return space.w_False return space.w_True -def String2Bytearray(space, w_str): - data = [c for c in space.str_w(w_str)] - return W_BytearrayObject(data) - def eq__Bytearray_String(space, w_bytearray, w_other): return space.eq(str__Bytearray(space, w_bytearray), w_other) @@ -454,13 +444,6 @@ # No more items to compare -- compare sizes return space.newbool(len(data1) > len(data2)) -def str_translate__Bytearray_ANY_ANY(space, w_bytearray1, w_table, w_deletechars): - # XXX slow, copies *twice* needs proper implementation - w_str_copy = str__Bytearray(space, w_bytearray1) - w_res = bytesobject.str_translate__String_ANY_ANY(space, w_str_copy, - w_table, w_deletechars) - return String2Bytearray(space, w_res) - # Mostly copied from repr__String, but without the "smart quote" # functionality. def repr__Bytearray(space, w_bytearray): @@ -657,117 +640,6 @@ def bytearray_rstrip__Bytearray_ANY(space, w_bytearray, w_chars): return _strip(space, w_bytearray, space.bufferstr_new_w(w_chars), 0, 1) -# These methods could just delegate to the string implementation, -# but they have to return a bytearray. -def str_replace__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_str1, w_str2, w_max): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_replace__String_ANY_ANY_ANY(space, w_str, w_str1, - w_str2, w_max) - return String2Bytearray(space, w_res) - -def str_upper__Bytearray(space, w_bytearray): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_upper__String(space, w_str) - return String2Bytearray(space, w_res) - -def str_lower__Bytearray(space, w_bytearray): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_lower__String(space, w_str) - return String2Bytearray(space, w_res) - -def str_title__Bytearray(space, w_bytearray): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_title__String(space, w_str) - return String2Bytearray(space, w_res) - -def str_swapcase__Bytearray(space, w_bytearray): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_swapcase__String(space, w_str) - return String2Bytearray(space, w_res) - -def str_capitalize__Bytearray(space, w_bytearray): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_capitalize__String(space, w_str) - return String2Bytearray(space, w_res) - -def str_ljust__Bytearray_ANY_ANY(space, w_bytearray, w_width, w_fillchar): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_ljust__String_ANY_ANY(space, w_str, w_width, - w_fillchar) - return String2Bytearray(space, w_res) - -def str_rjust__Bytearray_ANY_ANY(space, w_bytearray, w_width, w_fillchar): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_rjust__String_ANY_ANY(space, w_str, w_width, - w_fillchar) - return String2Bytearray(space, w_res) - -def str_center__Bytearray_ANY_ANY(space, w_bytearray, w_width, w_fillchar): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_center__String_ANY_ANY(space, w_str, w_width, - w_fillchar) - return String2Bytearray(space, w_res) - -def str_zfill__Bytearray_ANY(space, w_bytearray, w_width): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_zfill__String_ANY(space, w_str, w_width) - return String2Bytearray(space, w_res) - -def str_expandtabs__Bytearray_ANY(space, w_bytearray, w_tabsize): - w_str = str__Bytearray(space, w_bytearray) - w_res = bytesobject.str_expandtabs__String_ANY(space, w_str, w_tabsize) - return String2Bytearray(space, w_res) - -def str_splitlines__Bytearray_ANY(space, w_bytearray, w_keepends): - w_str = str__Bytearray(space, w_bytearray) - w_result = bytesobject.str_splitlines__String_ANY(space, w_str, w_keepends) - return space.newlist([ - new_bytearray(space, space.w_bytearray, makebytearraydata_w(space, w_entry)) - for w_entry in space.unpackiterable(w_result) - ]) - -def str_split__Bytearray_ANY_ANY(space, w_bytearray, w_by, w_maxsplit=-1): - w_str = str__Bytearray(space, w_bytearray) - if not space.is_w(w_by, space.w_None): - w_by = space.wrap(space.bufferstr_new_w(w_by)) - w_list = space.call_method(w_str, "split", w_by, w_maxsplit) - length = space.int_w(space.len(w_list)) - for i in range(length): - w_i = space.wrap(i) - space.setitem(w_list, w_i, String2Bytearray(space, space.getitem(w_list, w_i))) - return w_list - -def str_rsplit__Bytearray_ANY_ANY(space, w_bytearray, w_by, w_maxsplit=-1): - w_str = str__Bytearray(space, w_bytearray) - if not space.is_w(w_by, space.w_None): - w_by = space.wrap(space.bufferstr_new_w(w_by)) - w_list = space.call_method(w_str, "rsplit", w_by, w_maxsplit) - length = space.int_w(space.len(w_list)) - for i in range(length): - w_i = space.wrap(i) - space.setitem(w_list, w_i, String2Bytearray(space, space.getitem(w_list, w_i))) - return w_list - -def str_partition__Bytearray_ANY(space, w_bytearray, w_sub): - w_str = str__Bytearray(space, w_bytearray) - w_sub = space.wrap(space.bufferstr_new_w(w_sub)) - w_tuple = bytesobject.str_partition__String_String(space, w_str, w_sub) - w_a, w_b, w_c = space.fixedview(w_tuple, 3) - return space.newtuple([ - String2Bytearray(space, w_a), - String2Bytearray(space, w_b), - String2Bytearray(space, w_c)]) - -def str_rpartition__Bytearray_ANY(space, w_bytearray, w_sub): - w_str = str__Bytearray(space, w_bytearray) - w_sub = space.wrap(space.bufferstr_new_w(w_sub)) - w_tuple = bytesobject.str_rpartition__String_String(space, w_str, w_sub) - w_a, w_b, w_c = space.fixedview(w_tuple, 3) - return space.newtuple([ - String2Bytearray(space, w_a), - String2Bytearray(space, w_b), - String2Bytearray(space, w_c)]) - # __________________________________________________________ # Mutability methods @@ -933,4 +805,4 @@ b = BytearrayBuffer(self.data) return space.wrap(b) -register_all(vars(), globals()) +#register_all(vars(), globals()) diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py --- a/pypy/objspace/std/bytesobject.py +++ b/pypy/objspace/std/bytesobject.py @@ -15,6 +15,8 @@ from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.stringmethods import StringMethods +from pypy.objspace.std.unicodeobject import (unicode_from_string, + decode_object, _get_encoding_and_errors) from rpython.rlib import jit from rpython.rlib.jit import we_are_jitted from rpython.rlib.objectmodel import (compute_hash, compute_unique_id, @@ -40,37 +42,41 @@ return None return space.wrap(compute_unique_id(space.str_w(self))) - def unicode_w(w_self, space): + def unicode_w(self, space): # Use the default encoding. - from pypy.objspace.std.unicodeobject import (unicode_from_string, - decode_object, _get_encoding_and_errors) w_defaultencoding = space.call_function(space.sys.get( 'getdefaultencoding')) encoding, errors = _get_encoding_and_errors(space, w_defaultencoding, space.w_None) if encoding is None and errors is None: - return space.unicode_w(unicode_from_string(space, w_self)) - return space.unicode_w(decode_object(space, w_self, encoding, errors)) + return space.unicode_w(unicode_from_string(space, self)) + return space.unicode_w(decode_object(space, self, encoding, errors)) class W_BytesObject(W_AbstractBytesObject, StringMethods): _immutable_fields_ = ['_value'] - def __init__(w_self, str): - w_self._value = str + def __init__(self, str): + self._value = str - def __repr__(w_self): + def __repr__(self): """ representation for debugging purposes """ - return "%s(%r)" % (w_self.__class__.__name__, w_self._value) + return "%s(%r)" % (self.__class__.__name__, self._value) - def unwrap(w_self, space): - return w_self._value + def unwrap(self, space): + return self._value - def str_w(w_self, space): - return w_self._value + def str_w(self, space): + return self._value - def listview_str(w_self): - return _create_list_from_string(w_self._value) + def listview_str(self): + return _create_list_from_string(self._value) + + def ord(self, space): + if len(self._value) != 1: + msg = "ord() expected a character, but string of length %d found" + raise operationerrfmt(space.w_TypeError, msg, len(self._value)) + return space.wrap(ord(self._value[0])) def _new(self, value): return W_BytesObject(value) @@ -81,8 +87,99 @@ def _val(self): return self._value + def _op_val(self, space, w_other): + return space.bufferstr_w(w_other) + #return w_other._value -W_StringObject = W_BytesObject + def _chr(self, char): + return str(char) + + _builder = StringBuilder + + @staticmethod + @unwrap_spec(w_object = WrappedDefault("")) + def descr_new(space, w_stringtype, w_object): + # NB. the default value of w_object is really a *wrapped* empty string: + # there is gateway magic at work + w_obj = space.str(w_object) + if space.is_w(w_stringtype, space.w_str): + return w_obj # XXX might be reworked when space.str() typechecks + value = space.str_w(w_obj) + w_obj = space.allocate_instance(W_BytesObject, w_stringtype) + W_BytesObject.__init__(w_obj, value) + return w_obj + + def descr_repr(self, space): + s = self._value + quote = "'" + if quote in s and '"' not in s: + quote = '"' + return space.wrap(string_escape_encode(s, quote)) + + def descr_str(self, space): + if type(self) is W_BytesObject: + return self + return wrapstr(space, self._value) + + def descr_hash(self, space): + x = compute_hash(self._value) + return space.wrap(x) + + def descr_format(self, space, __args__): + return newformat.format_method(space, self, __args__, is_unicode=False) + + def descr__format__(self, space, w_format_spec): + if not space.isinstance_w(w_format_spec, space.w_str): + w_format_spec = space.str(w_format_spec) + spec = space.str_w(w_format_spec) + formatter = newformat.str_formatter(space, spec) + return formatter.format_string(self._value) + + def descr_mod(self, space, w_values): + return mod_format(space, self, w_values, do_unicode=False) + + def descr_buffer(self, space): + return space.wrap(StringBuffer(self._value)) + + # auto-conversion fun + + def descr_add(self, space, w_other): + if space.isinstance_w(w_other, space.w_unicode): + self_as_unicode = decode_object(space, self, None, None) + #return self_as_unicode.descr_add(space, w_other) + return space.add(self_as_unicode, w_other) + return StringMethods.descr_add(self, space, w_other) + + def _startswith(self, space, value, w_prefix, start, end): + if space.isinstance_w(w_prefix, space.w_unicode): + self_as_unicode = decode_object(space, self, None, None) + return self_as_unicode._startswith(space, value, w_prefix, start, end) + return StringMethods._startswith(self, space, value, w_prefix, start, end) + + def _endswith(self, space, value, w_suffix, start, end): + if space.isinstance_w(w_suffix, space.w_unicode): + self_as_unicode = decode_object(space, self, None, None) + return self_as_unicode._endswith(space, value, w_suffix, start, end) + return StringMethods._endswith(self, space, value, w_suffix, start, end) + + def _join_return_one(self, space, w_obj): + return (space.is_w(space.type(w_obj), space.w_str) or + space.is_w(space.type(w_obj), space.w_unicode)) + + def _join_check_item(self, space, w_obj): + if space.isinstance_w(w_obj, space.w_str): + return 0 + if space.isinstance_w(w_obj, space.w_unicode): + return 2 + return 1 + + def _join_autoconvert(self, space, list_w): + # we need to rebuild w_list here, because the original + # w_list might be an iterable which we already consumed + w_list = space.newlist(list_w) + w_u = space.call_function(space.w_unicode, self) + return space.call_method(w_u, "join", w_list) + def _create_list_from_string(value): # need this helper function to allow the jit to look inside and inline @@ -118,1198 +215,85 @@ else: return W_BytesObject(c) -def sliced(space, s, start, stop, orig_obj): - assert start >= 0 - assert stop >= 0 - if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), space.w_str): - return orig_obj - return wrapstr(space, s[start:stop]) - -def joined2(space, str1, str2): - if space.config.objspace.std.withstrbuf: - from pypy.objspace.std.strbufobject import joined2 - return joined2(str1, str2) - else: - return wrapstr(space, str1 + str2) - -str_join = SMM('join', 2, - doc='S.join(sequence) -> string\n\nReturn a string which is' - ' the concatenation of the strings in the\nsequence. ' - ' The separator between elements is S.') -str_split = SMM('split', 3, defaults=(None,-1), - doc='S.split([sep [,maxsplit]]) -> list of strings\n\nReturn' - ' a list of the words in the string S, using sep as' - ' the\ndelimiter string. If maxsplit is given, at most' - ' maxsplit\nsplits are done. If sep is not specified or' - ' is None, any\nwhitespace string is a separator.') -str_rsplit = SMM('rsplit', 3, defaults=(None,-1), - doc='S.rsplit([sep [,maxsplit]]) -> list of' - ' strings\n\nReturn a list of the words in the string S,' - ' using sep as the\ndelimiter string, starting at the' - ' end of the string and working\nto the front. If' - ' maxsplit is given, at most maxsplit splits are\ndone.' - ' If sep is not specified or is None, any whitespace' - ' string\nis a separator.') -str_format = SMM('format', 1, general__args__=True) -str_isdigit = SMM('isdigit', 1, - doc='S.isdigit() -> bool\n\nReturn True if all characters' - ' in S are digits\nand there is at least one' - ' character in S, False otherwise.') -str_isalpha = SMM('isalpha', 1, - doc='S.isalpha() -> bool\n\nReturn True if all characters' - ' in S are alphabetic\nand there is at least one' - ' character in S, False otherwise.') -str_isspace = SMM('isspace', 1, - doc='S.isspace() -> bool\n\nReturn True if all characters' - ' in S are whitespace\nand there is at least one' - ' character in S, False otherwise.') -str_isupper = SMM('isupper', 1, - doc='S.isupper() -> bool\n\nReturn True if all cased' - ' characters in S are uppercase and there is\nat' - ' least one cased character in S, False otherwise.') -str_islower = SMM('islower', 1, - doc='S.islower() -> bool\n\nReturn True if all cased' - ' characters in S are lowercase and there is\nat' - ' least one cased character in S, False otherwise.') -str_istitle = SMM('istitle', 1, - doc='S.istitle() -> bool\n\nReturn True if S is a' - ' titlecased string and there is at least' - ' one\ncharacter in S, i.e. uppercase characters may' - ' only follow uncased\ncharacters and lowercase' - ' characters only cased ones. Return' - ' False\notherwise.') -str_isalnum = SMM('isalnum', 1, - doc='S.isalnum() -> bool\n\nReturn True if all characters' - ' in S are alphanumeric\nand there is at least one' - ' character in S, False otherwise.') -str_ljust = SMM('ljust', 3, defaults=(' ',), - doc='S.ljust(width[, fillchar]) -> string\n\nReturn S' - ' left justified in a string of length width. Padding' - ' is\ndone using the specified fill character' - ' (default is a space).') -str_rjust = SMM('rjust', 3, defaults=(' ',), - doc='S.rjust(width[, fillchar]) -> string\n\nReturn S' - ' right justified in a string of length width.' - ' Padding is\ndone using the specified fill character' - ' (default is a space)') -str_upper = SMM('upper', 1, - doc='S.upper() -> string\n\nReturn a copy of the string S' - ' converted to uppercase.') -str_lower = SMM('lower', 1, - doc='S.lower() -> string\n\nReturn a copy of the string S' - ' converted to lowercase.') -str_swapcase = SMM('swapcase', 1, - doc='S.swapcase() -> string\n\nReturn a copy of the' - ' string S with uppercase characters\nconverted to' - ' lowercase and vice versa.') -str_capitalize = SMM('capitalize', 1, - doc='S.capitalize() -> string\n\nReturn a copy of the' - ' string S with only its first' - ' character\ncapitalized.') -str_title = SMM('title', 1, - doc='S.title() -> string\n\nReturn a titlecased version' - ' of S, i.e. words start with uppercase\ncharacters,' - ' all remaining cased characters have lowercase.') -str_find = SMM('find', 4, defaults=(0, maxint), - doc='S.find(sub [,start [,end]]) -> int\n\nReturn the' - ' lowest index in S where substring sub is' - ' found,\nsuch that sub is contained within' - ' s[start,end]. Optional\narguments start and end' - ' are interpreted as in slice notation.\n\nReturn -1' - ' on failure.') -str_rfind = SMM('rfind', 4, defaults=(0, maxint), - doc='S.rfind(sub [,start [,end]]) -> int\n\nReturn the' - ' highest index in S where substring sub is' - ' found,\nsuch that sub is contained within' - ' s[start,end]. Optional\narguments start and end' - ' are interpreted as in slice notation.\n\nReturn -1' - ' on failure.') -str_partition = SMM('partition', 2, - doc='S.partition(sep) -> (head, sep, tail)\n\nSearches' - ' for the separator sep in S, and returns the part before' - ' it,\nthe separator itself, and the part after it. If' - ' the separator is not\nfound, returns S and two empty' - ' strings.') -str_rpartition = SMM('rpartition', 2, - doc='S.rpartition(sep) -> (tail, sep, head)\n\nSearches' - ' for the separator sep in S, starting at the end of S,' - ' and returns\nthe part before it, the separator itself,' - ' and the part after it. If the\nseparator is not found,' - ' returns two empty strings and S.') -str_index = SMM('index', 4, defaults=(0, maxint), - doc='S.index(sub [,start [,end]]) -> int\n\nLike S.find()' - ' but raise ValueError when the substring is not' - ' found.') -str_rindex = SMM('rindex', 4, defaults=(0, maxint), - doc='S.rindex(sub [,start [,end]]) -> int\n\nLike' - ' S.rfind() but raise ValueError when the substring' - ' is not found.') -str_replace = SMM('replace', 4, defaults=(-1,), - doc='S.replace (old, new[, count]) -> string\n\nReturn a' - ' copy of string S with all occurrences of' - ' substring\nold replaced by new. If the optional' - ' argument count is\ngiven, only the first count' - ' occurrences are replaced.') -str_zfill = SMM('zfill', 2, - doc='S.zfill(width) -> string\n\nPad a numeric string S' - ' with zeros on the left, to fill a field\nof the' - ' specified width. The string S is never truncated.') -str_strip = SMM('strip', 2, defaults=(None,), - doc='S.strip([chars]) -> string or unicode\n\nReturn a' - ' copy of the string S with leading and' - ' trailing\nwhitespace removed.\nIf chars is given' - ' and not None, remove characters in chars' - ' instead.\nIf chars is unicode, S will be converted' - ' to unicode before stripping') -str_rstrip = SMM('rstrip', 2, defaults=(None,), - doc='S.rstrip([chars]) -> string or unicode\n\nReturn a' - ' copy of the string S with trailing whitespace' - ' removed.\nIf chars is given and not None, remove' - ' characters in chars instead.\nIf chars is unicode,' - ' S will be converted to unicode before stripping') -str_lstrip = SMM('lstrip', 2, defaults=(None,), - doc='S.lstrip([chars]) -> string or unicode\n\nReturn a' - ' copy of the string S with leading whitespace' - ' removed.\nIf chars is given and not None, remove' - ' characters in chars instead.\nIf chars is unicode,' - ' S will be converted to unicode before stripping') -str_center = SMM('center', 3, defaults=(' ',), - doc='S.center(width[, fillchar]) -> string\n\nReturn S' - ' centered in a string of length width. Padding' - ' is\ndone using the specified fill character' - ' (default is a space)') -str_count = SMM('count', 4, defaults=(0, maxint), - doc='S.count(sub[, start[, end]]) -> int\n\nReturn the' - ' number of occurrences of substring sub in' - ' string\nS[start:end]. Optional arguments start and' - ' end are\ninterpreted as in slice notation.') -str_endswith = SMM('endswith', 4, defaults=(0, maxint), - doc='S.endswith(suffix[, start[, end]]) -> bool\n\nReturn' - ' True if S ends with the specified suffix, False' - ' otherwise.\nWith optional start, test S beginning' - ' at that position.\nWith optional end, stop' - ' comparing S at that position.') -str_expandtabs = SMM('expandtabs', 2, defaults=(8,), - doc='S.expandtabs([tabsize]) -> string\n\nReturn a copy' - ' of S where all tab characters are expanded using' - ' spaces.\nIf tabsize is not given, a tab size of 8' - ' characters is assumed.') -str_splitlines = SMM('splitlines', 2, defaults=(0,), - doc='S.splitlines([keepends]) -> list of' - ' strings\n\nReturn a list of the lines in S,' - ' breaking at line boundaries.\nLine breaks are not' - ' included in the resulting list unless keepends\nis' - ' given and true.') -str_startswith = SMM('startswith', 4, defaults=(0, maxint), - doc='S.startswith(prefix[, start[, end]]) ->' - ' bool\n\nReturn True if S starts with the specified' - ' prefix, False otherwise.\nWith optional start, test' - ' S beginning at that position.\nWith optional end,' - ' stop comparing S at that position.') -str_translate = SMM('translate', 3, defaults=('',), #unicode mimic not supported now - doc='S.translate(table [,deletechars]) -> string\n\n' - 'Return a copy of the string S, where all characters' - ' occurring\nin the optional argument deletechars are' - ' removed, and the\nremaining characters have been' - ' mapped through the given\ntranslation table, which' - ' must be a string of length 256.') -str_decode = SMM('decode', 3, defaults=(None, None), - argnames=['encoding', 'errors'], - doc='S.decode([encoding[,errors]]) -> object\n\nDecodes S' - ' using the codec registered for encoding. encoding' - ' defaults\nto the default encoding. errors may be' - ' given to set a different error\nhandling scheme.' - " Default is 'strict' meaning that encoding errors" - ' raise\na UnicodeDecodeError. Other possible values' - " are 'ignore' and 'replace'\nas well as any other" - ' name registerd with codecs.register_error that' - ' is\nable to handle UnicodeDecodeErrors.') -str_encode = SMM('encode', 3, defaults=(None, None), - argnames=['encoding', 'errors'], - doc='S.encode([encoding[,errors]]) -> object\n\nEncodes S' - ' using the codec registered for encoding. encoding' - ' defaults\nto the default encoding. errors may be' - ' given to set a different error\nhandling scheme.' - " Default is 'strict' meaning that encoding errors" - ' raise\na UnicodeEncodeError. Other possible values' - " are 'ignore', 'replace' and\n'xmlcharrefreplace' as" - ' well as any other name registered' - ' with\ncodecs.register_error that is able to handle' - ' UnicodeEncodeErrors.') - -str_formatter_parser = SMM('_formatter_parser', 1) -str_formatter_field_name_split = SMM('_formatter_field_name_split', 1) - -def str_formatter_parser__ANY(space, w_str): - from pypy.objspace.std.newformat import str_template_formatter - tformat = str_template_formatter(space, space.str_w(w_str)) - return tformat.formatter_parser() - -def str_formatter_field_name_split__ANY(space, w_str): - from pypy.objspace.std.newformat import str_template_formatter - tformat = str_template_formatter(space, space.str_w(w_str)) - return tformat.formatter_field_name_split() - -# ____________________________________________________________ - - at unwrap_spec(w_object = WrappedDefault("")) -def descr__new__(space, w_stringtype, w_object): - # NB. the default value of w_object is really a *wrapped* empty string: - # there is gateway magic at work - w_obj = space.str(w_object) - if space.is_w(w_stringtype, space.w_str): - return w_obj # XXX might be reworked when space.str() typechecks - value = space.str_w(w_obj) - w_obj = space.allocate_instance(W_BytesObject, w_stringtype) - W_BytesObject.__init__(w_obj, value) - return w_obj - -# ____________________________________________________________ - str_typedef = W_BytesObject.typedef = StdTypeDef( "str", basestring_typedef, - __new__ = interp2app(descr__new__), + __new__ = interp2app(W_BytesObject.descr_new), __doc__ = '''str(object) -> string Return a nice string representation of the object. If the argument is a string, the return value is the same object.''', -# __repr__ = interp2app(W_BytesObject.descr_repr), -# __str__ = interp2app(W_BytesObject.descr_str), + __repr__ = interp2app(W_BytesObject.descr_repr), + __str__ = interp2app(W_BytesObject.descr_str), + __hash__ = interp2app(W_BytesObject.descr_hash), -# __eq__ = interp2app(W_BytesObject.descr_eq), -# __ne__ = interp2app(W_BytesObject.descr_ne), -# __lt__ = interp2app(W_BytesObject.descr_lt), -# __le__ = interp2app(W_BytesObject.descr_le), -# __gt__ = interp2app(W_BytesObject.descr_gt), -# __ge__ = interp2app(W_BytesObject.descr_ge), + __eq__ = interp2app(W_BytesObject.descr_eq), + __ne__ = interp2app(W_BytesObject.descr_ne), + __lt__ = interp2app(W_BytesObject.descr_lt), + __le__ = interp2app(W_BytesObject.descr_le), + __gt__ = interp2app(W_BytesObject.descr_gt), + __ge__ = interp2app(W_BytesObject.descr_ge), -# __len__ = interp2app(W_BytesObject.descr_len), -# __iter__ = interp2app(W_BytesObject.descr_iter), -# __contains__ = interp2app(W_BytesObject.descr_contains), + __len__ = interp2app(W_BytesObject.descr_len), + #__iter__ = interp2app(W_BytesObject.descr_iter), + __contains__ = interp2app(W_BytesObject.descr_contains), -# __add__ = interp2app(W_BytesObject.descr_add), + __add__ = interp2app(W_BytesObject.descr_add), __mul__ = interp2app(W_BytesObject.descr_mul), __rmul__ = interp2app(W_BytesObject.descr_mul), -# __getitem__ = interp2app(W_BytesObject.descr_getitem), + __getitem__ = interp2app(W_BytesObject.descr_getitem), + __getslice__ = interp2app(W_BytesObject.descr_getslice), -# capitalize = interp2app(W_BytesObject.descr_capitalize), -# center = interp2app(W_BytesObject.descr_center), -# count = interp2app(W_BytesObject.descr_count), -# decode = interp2app(W_BytesObject.descr_decode), -# expandtabs = interp2app(W_BytesObject.descr_expandtabs), -# find = interp2app(W_BytesObject.descr_find), -# rfind = interp2app(W_BytesObject.descr_rfind), -# index = interp2app(W_BytesObject.descr_index), -# rindex = interp2app(W_BytesObject.descr_rindex), -# isalnum = interp2app(W_BytesObject.descr_isalnum), -# isalpha = interp2app(W_BytesObject.descr_isalpha), -# isdigit = interp2app(W_BytesObject.descr_isdigit), -# islower = interp2app(W_BytesObject.descr_islower), -# isspace = interp2app(W_BytesObject.descr_isspace), -# istitle = interp2app(W_BytesObject.descr_istitle), -# isupper = interp2app(W_BytesObject.descr_isupper), -# join = interp2app(W_BytesObject.descr_join), -# ljust = interp2app(W_BytesObject.descr_ljust), -# rjust = interp2app(W_BytesObject.descr_rjust), -# lower = interp2app(W_BytesObject.descr_lower), -# partition = interp2app(W_BytesObject.descr_partition), -# rpartition = interp2app(W_BytesObject.descr_rpartition), -# replace = interp2app(W_BytesObject.descr_replace), -# split = interp2app(W_BytesObject.descr_split), -# rsplit = interp2app(W_BytesObject.descr_rsplit), -# splitlines = interp2app(W_BytesObject.descr_splitlines), -# startswith = interp2app(W_BytesObject.descr_startswith), -# endswith = interp2app(W_BytesObject.descr_endswith), -# strip = interp2app(W_BytesObject.descr_strip), -# lstrip = interp2app(W_BytesObject.descr_lstrip), -# rstrip = interp2app(W_BytesObject.descr_rstrip), -# swapcase = interp2app(W_BytesObject.descr_swapcase), -# title = interp2app(W_BytesObject.descr_title), -# translate = interp2app(W_BytesObject.descr_translate), -# upper = interp2app(W_BytesObject.descr_upper), -# zfill = interp2app(W_BytesObject.descr_zfill), + capitalize = interp2app(W_BytesObject.descr_capitalize), + center = interp2app(W_BytesObject.descr_center), + count = interp2app(W_BytesObject.descr_count), + decode = interp2app(W_BytesObject.descr_decode), + encode = interp2app(W_BytesObject.descr_encode), + expandtabs = interp2app(W_BytesObject.descr_expandtabs), + find = interp2app(W_BytesObject.descr_find), + rfind = interp2app(W_BytesObject.descr_rfind), + index = interp2app(W_BytesObject.descr_index), + rindex = interp2app(W_BytesObject.descr_rindex), + isalnum = interp2app(W_BytesObject.descr_isalnum), + isalpha = interp2app(W_BytesObject.descr_isalpha), + isdigit = interp2app(W_BytesObject.descr_isdigit), + islower = interp2app(W_BytesObject.descr_islower), + isspace = interp2app(W_BytesObject.descr_isspace), + istitle = interp2app(W_BytesObject.descr_istitle), + isupper = interp2app(W_BytesObject.descr_isupper), + join = interp2app(W_BytesObject.descr_join), + ljust = interp2app(W_BytesObject.descr_ljust), + rjust = interp2app(W_BytesObject.descr_rjust), + lower = interp2app(W_BytesObject.descr_lower), + partition = interp2app(W_BytesObject.descr_partition), + rpartition = interp2app(W_BytesObject.descr_rpartition), + replace = interp2app(W_BytesObject.descr_replace), + split = interp2app(W_BytesObject.descr_split), + rsplit = interp2app(W_BytesObject.descr_rsplit), + splitlines = interp2app(W_BytesObject.descr_splitlines), + startswith = interp2app(W_BytesObject.descr_startswith), + endswith = interp2app(W_BytesObject.descr_endswith), + strip = interp2app(W_BytesObject.descr_strip), + lstrip = interp2app(W_BytesObject.descr_lstrip), + rstrip = interp2app(W_BytesObject.descr_rstrip), + swapcase = interp2app(W_BytesObject.descr_swapcase), + title = interp2app(W_BytesObject.descr_title), + translate = interp2app(W_BytesObject.descr_translate), + upper = interp2app(W_BytesObject.descr_upper), + zfill = interp2app(W_BytesObject.descr_zfill), + + format = interp2app(W_BytesObject.descr_format), + __format__ = interp2app(W_BytesObject.descr__format__), + __mod__ = interp2app(W_BytesObject.descr_mod), + __buffer__ = interp2app(W_BytesObject.descr_buffer), + __getnewargs__ = interp2app(W_BytesObject.descr_getnewargs), ) str_typedef.registermethods(globals()) # ____________________________________________________________ -# Helpers for several string implementations - - at specialize.argtype(0) -def stringendswith(u_self, suffix, start, end): - begin = end - len(suffix) - if begin < start: - return False - for i in range(len(suffix)): - if u_self[begin+i] != suffix[i]: - return False - return True - - at specialize.argtype(0) -def stringstartswith(u_self, prefix, start, end): - stop = start + len(prefix) - if stop > end: - return False - for i in range(len(prefix)): - if u_self[start+i] != prefix[i]: - return False - return True - - - at specialize.arg(2) -def _is_generic(space, w_self, fun): - v = w_self._value - if len(v) == 0: - return space.w_False - if len(v) == 1: - c = v[0] - return space.newbool(fun(c)) - else: - return _is_generic_loop(space, v, fun) - - at specialize.arg(2) -def _is_generic_loop(space, v, fun): - for idx in range(len(v)): - if not fun(v[idx]): - return space.w_False - return space.w_True - -def _upper(ch): - if ch.islower(): - o = ord(ch) - 32 - return chr(o) - else: - return ch - -def _lower(ch): - if ch.isupper(): - o = ord(ch) + 32 - return chr(o) - else: - return ch - -_isspace = lambda c: c.isspace() -_isdigit = lambda c: c.isdigit() -_isalpha = lambda c: c.isalpha() -_isalnum = lambda c: c.isalnum() - -def str_isspace__String(space, w_self): - return _is_generic(space, w_self, _isspace) - -def str_isdigit__String(space, w_self): - return _is_generic(space, w_self, _isdigit) - -def str_isalpha__String(space, w_self): - return _is_generic(space, w_self, _isalpha) - -def str_isalnum__String(space, w_self): - return _is_generic(space, w_self, _isalnum) - -def str_isupper__String(space, w_self): - """Return True if all cased characters in S are uppercase and there is -at least one cased character in S, False otherwise.""" - v = w_self._value - if len(v) == 1: - c = v[0] - return space.newbool(c.isupper()) - cased = False - for idx in range(len(v)): - if v[idx].islower(): - return space.w_False - elif not cased and v[idx].isupper(): - cased = True - return space.newbool(cased) - -def str_islower__String(space, w_self): - """Return True if all cased characters in S are lowercase and there is -at least one cased character in S, False otherwise.""" - v = w_self._value - if len(v) == 1: - c = v[0] - return space.newbool(c.islower()) - cased = False - for idx in range(len(v)): - if v[idx].isupper(): - return space.w_False - elif not cased and v[idx].islower(): - cased = True - return space.newbool(cased) - -def str_istitle__String(space, w_self): - """Return True if S is a titlecased string and there is at least one -character in S, i.e. uppercase characters may only follow uncased -characters and lowercase characters only cased ones. Return False -otherwise.""" - input = w_self._value - cased = False - previous_is_cased = False - - for pos in range(0, len(input)): - ch = input[pos] - if ch.isupper(): - if previous_is_cased: - return space.w_False - previous_is_cased = True - cased = True - elif ch.islower(): - if not previous_is_cased: - return space.w_False - cased = True - else: - previous_is_cased = False - - return space.newbool(cased) - -def str_upper__String(space, w_self): - self = w_self._value - return space.wrap(self.upper()) - -def str_lower__String(space, w_self): - self = w_self._value - return space.wrap(self.lower()) - -def str_swapcase__String(space, w_self): - self = w_self._value - builder = StringBuilder(len(self)) - for i in range(len(self)): - ch = self[i] - if ch.isupper(): - o = ord(ch) + 32 - builder.append(chr(o)) - elif ch.islower(): - o = ord(ch) - 32 - builder.append(chr(o)) - else: - builder.append(ch) - - return space.wrap(builder.build()) - - -def str_capitalize__String(space, w_self): - input = w_self._value - builder = StringBuilder(len(input)) - if len(input) > 0: - ch = input[0] - if ch.islower(): - o = ord(ch) - 32 - builder.append(chr(o)) - else: - builder.append(ch) - - for i in range(1, len(input)): - ch = input[i] - if ch.isupper(): - o = ord(ch) + 32 - builder.append(chr(o)) - else: - builder.append(ch) - - return space.wrap(builder.build()) - -def str_title__String(space, w_self): - input = w_self._value - builder = StringBuilder(len(input)) - prev_letter = ' ' - - for pos in range(len(input)): - ch = input[pos] - if not prev_letter.isalpha(): - ch = _upper(ch) - builder.append(ch) - else: - ch = _lower(ch) - builder.append(ch) - - prev_letter = ch - - return space.wrap(builder.build()) - -def str_split__String_None_ANY(space, w_self, w_none, w_maxsplit=-1): - maxsplit = space.int_w(w_maxsplit) - res = [] - value = w_self._value - length = len(value) - i = 0 - while True: - # find the beginning of the next word - while i < length: - if not value[i].isspace(): - break # found - i += 1 - else: - break # end of string, finished - - # find the end of the word - if maxsplit == 0: - j = length # take all the rest of the string - else: - j = i + 1 - while j < length and not value[j].isspace(): - j += 1 - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - - # the word is value[i:j] - res.append(value[i:j]) - - # continue to look from the character following the space after the word - i = j + 1 - - return space.newlist_str(res) - -def str_split__String_String_ANY(space, w_self, w_by, w_maxsplit=-1): - maxsplit = space.int_w(w_maxsplit) - value = w_self._value - by = w_by._value - bylen = len(by) - if bylen == 0: - raise OperationError(space.w_ValueError, space.wrap("empty separator")) - - if bylen == 1 and maxsplit < 0: - res = [] - start = 0 - # fast path: uses str.rfind(character) and str.count(character) - by = by[0] # annotator hack: string -> char - count = value.count(by) - res = [None] * (count + 1) - end = len(value) - while count >= 0: - assert end >= 0 - prev = value.rfind(by, 0, end) - start = prev + 1 - assert start >= 0 - res[count] = value[start:end] - count -= 1 - end = prev - else: - res = split(value, by, maxsplit) - - return space.newlist_str(res) - -def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1): - maxsplit = space.int_w(w_maxsplit) - res_w = [] - value = w_self._value - i = len(value)-1 - while True: - # starting from the end, find the end of the next word - while i >= 0: - if not value[i].isspace(): - break # found - i -= 1 - else: - break # end of string, finished - - # find the start of the word - # (more precisely, 'j' will be the space character before the word) - if maxsplit == 0: - j = -1 # take all the rest of the string - else: - j = i - 1 - while j >= 0 and not value[j].isspace(): - j -= 1 - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - - # the word is value[j+1:i+1] - j1 = j + 1 - assert j1 >= 0 - res_w.append(sliced(space, value, j1, i+1, w_self)) - - # continue to look from the character before the space before the word - i = j - 1 - - res_w.reverse() - return space.newlist(res_w) - -def make_rsplit_with_delim(funcname, sliced): - from rpython.tool.sourcetools import func_with_new_name - - def fn(space, w_self, w_by, w_maxsplit=-1): - maxsplit = space.int_w(w_maxsplit) - res_w = [] - value = w_self._value - end = len(value) - by = w_by._value - bylen = len(by) - if bylen == 0: - raise OperationError(space.w_ValueError, space.wrap("empty separator")) - - while maxsplit != 0: - next = value.rfind(by, 0, end) - if next < 0: - break - res_w.append(sliced(space, value, next+bylen, end, w_self)) - end = next - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - - res_w.append(sliced(space, value, 0, end, w_self)) - res_w.reverse() - return space.newlist(res_w) - - return func_with_new_name(fn, funcname) - -str_rsplit__String_String_ANY = make_rsplit_with_delim('str_rsplit__String_String_ANY', - sliced) - -def str_join__String_ANY(space, w_self, w_list): - l = space.listview_str(w_list) - if l is not None: - if len(l) == 1: - return space.wrap(l[0]) - return space.wrap(w_self._value.join(l)) - list_w = space.listview(w_list) - size = len(list_w) - - if size == 0: - return W_BytesObject.EMPTY - - if size == 1: - w_s = list_w[0] - # only one item, return it if it's not a subclass of str - if (space.is_w(space.type(w_s), space.w_str) or - space.is_w(space.type(w_s), space.w_unicode)): - return w_s - - return _str_join_many_items(space, w_self, list_w, size) - - at jit.look_inside_iff(lambda space, w_self, list_w, size: - jit.loop_unrolling_heuristic(list_w, size)) -def _str_join_many_items(space, w_self, list_w, size): - self = w_self._value - reslen = len(self) * (size - 1) - for i in range(size): - w_s = list_w[i] - if not space.isinstance_w(w_s, space.w_str): - if space.isinstance_w(w_s, space.w_unicode): - # we need to rebuild w_list here, because the original - # w_list might be an iterable which we already consumed - w_list = space.newlist(list_w) - w_u = space.call_function(space.w_unicode, w_self) - return space.call_method(w_u, "join", w_list) - raise operationerrfmt( - space.w_TypeError, - "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space)) - reslen += len(space.str_w(w_s)) - - sb = StringBuilder(reslen) - for i in range(size): - if self and i != 0: - sb.append(self) - sb.append(space.str_w(list_w[i])) - return space.wrap(sb.build()) - -def str_rjust__String_ANY_ANY(space, w_self, w_arg, w_fillchar): - u_arg = space.int_w(w_arg) - u_self = w_self._value - fillchar = space.str_w(w_fillchar) - if len(fillchar) != 1: - raise OperationError(space.w_TypeError, - space.wrap("rjust() argument 2 must be a single character")) - - d = u_arg - len(u_self) - if d > 0: - fillchar = fillchar[0] # annotator hint: it's a single character - u_self = d * fillchar + u_self - - return space.wrap(u_self) - - -def str_ljust__String_ANY_ANY(space, w_self, w_arg, w_fillchar): - u_self = w_self._value - u_arg = space.int_w(w_arg) - fillchar = space.str_w(w_fillchar) - if len(fillchar) != 1: - raise OperationError(space.w_TypeError, - space.wrap("ljust() argument 2 must be a single character")) - - d = u_arg - len(u_self) - if d > 0: - fillchar = fillchar[0] # annotator hint: it's a single character - u_self += d * fillchar - - return space.wrap(u_self) - - at specialize.arg(4) -def _convert_idx_params(space, w_self, w_start, w_end, upper_bound=False): - self = w_self._value - lenself = len(self) - - start, end = slicetype.unwrap_start_stop( - space, lenself, w_start, w_end, upper_bound=upper_bound) - return (self, start, end) - -def contains__String_String(space, w_self, w_sub): - self = w_self._value - sub = w_sub._value - return space.newbool(self.find(sub) >= 0) - -def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) - res = self.find(w_sub._value, start, end) - return space.wrap(res) - -def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) - res = self.rfind(w_sub._value, start, end) - return space.wrap(res) - -def str_partition__String_String(space, w_self, w_sub): - self = w_self._value - sub = w_sub._value - if not sub: - raise OperationError(space.w_ValueError, - space.wrap("empty separator")) - pos = self.find(sub) - if pos == -1: - return space.newtuple([w_self, space.wrap(''), space.wrap('')]) - else: - return space.newtuple([sliced(space, self, 0, pos, w_self), - w_sub, - sliced(space, self, pos+len(sub), len(self), - w_self)]) - -def str_rpartition__String_String(space, w_self, w_sub): - self = w_self._value - sub = w_sub._value - if not sub: - raise OperationError(space.w_ValueError, - space.wrap("empty separator")) - pos = self.rfind(sub) - if pos == -1: - return space.newtuple([space.wrap(''), space.wrap(''), w_self]) - else: - return space.newtuple([sliced(space, self, 0, pos, w_self), - w_sub, - sliced(space, self, pos+len(sub), len(self), w_self)]) - - -def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) - res = self.find(w_sub._value, start, end) - if res < 0: - raise OperationError(space.w_ValueError, - space.wrap("substring not found in string.index")) - - return space.wrap(res) - - -def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) - res = self.rfind(w_sub._value, start, end) - if res < 0: - raise OperationError(space.w_ValueError, - space.wrap("substring not found in string.rindex")) - - return space.wrap(res) - -def _string_replace(space, input, sub, by, maxsplit): - if maxsplit == 0: - return space.wrap(input) - - if not sub: - upper = len(input) - if maxsplit > 0 and maxsplit < upper + 2: - upper = maxsplit - 1 - assert upper >= 0 - - try: - result_size = ovfcheck(upper * len(by)) - result_size = ovfcheck(result_size + upper) - result_size = ovfcheck(result_size + len(by)) - remaining_size = len(input) - upper - result_size = ovfcheck(result_size + remaining_size) - except OverflowError: - raise OperationError(space.w_OverflowError, - space.wrap("replace string is too long") - ) - builder = StringBuilder(result_size) - for i in range(upper): - builder.append(by) - builder.append(input[i]) - builder.append(by) - builder.append_slice(input, upper, len(input)) - else: - # First compute the exact result size - count = input.count(sub) - if count > maxsplit and maxsplit > 0: - count = maxsplit - diff_len = len(by) - len(sub) - try: - result_size = ovfcheck(diff_len * count) - result_size = ovfcheck(result_size + len(input)) - except OverflowError: - raise OperationError(space.w_OverflowError, - space.wrap("replace string is too long") - ) - - builder = StringBuilder(result_size) - start = 0 - sublen = len(sub) - - while maxsplit != 0: - next = input.find(sub, start) - if next < 0: - break - builder.append_slice(input, start, next) - builder.append(by) - start = next + sublen - maxsplit -= 1 # NB. if it's already < 0, it stays < 0 - - builder.append_slice(input, start, len(input)) - - return space.wrap(builder.build()) - - -def str_replace__String_ANY_ANY_ANY(space, w_self, w_sub, w_by, w_maxsplit): - return _string_replace(space, w_self._value, space.buffer_w(w_sub).as_str(), - space.buffer_w(w_by).as_str(), - space.int_w(w_maxsplit)) - -def str_replace__String_String_String_ANY(space, w_self, w_sub, w_by, w_maxsplit=-1): - input = w_self._value - sub = w_sub._value - by = w_by._value - maxsplit = space.int_w(w_maxsplit) - return _string_replace(space, input, sub, by, maxsplit) - -def _strip(space, w_self, w_chars, left, right): - "internal function called by str_xstrip methods" - u_self = w_self._value - u_chars = w_chars._value - - lpos = 0 - rpos = len(u_self) - - if left: - #print "while %d < %d and -%s- in -%s-:"%(lpos, rpos, u_self[lpos],w_chars) - while lpos < rpos and u_self[lpos] in u_chars: - lpos += 1 - - if right: - while rpos > lpos and u_self[rpos - 1] in u_chars: - rpos -= 1 - - assert rpos >= lpos # annotator hint, don't remove - return sliced(space, u_self, lpos, rpos, w_self) - -def _strip_none(space, w_self, left, right): - "internal function called by str_xstrip methods" - u_self = w_self._value - - lpos = 0 - rpos = len(u_self) - - if left: - #print "while %d < %d and -%s- in -%s-:"%(lpos, rpos, u_self[lpos],w_chars) - while lpos < rpos and u_self[lpos].isspace(): - lpos += 1 - - if right: - while rpos > lpos and u_self[rpos - 1].isspace(): - rpos -= 1 - - assert rpos >= lpos # annotator hint, don't remove - return sliced(space, u_self, lpos, rpos, w_self) - -def str_strip__String_String(space, w_self, w_chars): - return _strip(space, w_self, w_chars, left=1, right=1) - -def str_strip__String_None(space, w_self, w_chars): - return _strip_none(space, w_self, left=1, right=1) - -def str_rstrip__String_String(space, w_self, w_chars): - return _strip(space, w_self, w_chars, left=0, right=1) - -def str_rstrip__String_None(space, w_self, w_chars): - return _strip_none(space, w_self, left=0, right=1) - - -def str_lstrip__String_String(space, w_self, w_chars): - return _strip(space, w_self, w_chars, left=1, right=0) - -def str_lstrip__String_None(space, w_self, w_chars): - return _strip_none(space, w_self, left=1, right=0) - - - -def str_center__String_ANY_ANY(space, w_self, w_arg, w_fillchar): - u_self = w_self._value - u_arg = space.int_w(w_arg) - fillchar = space.str_w(w_fillchar) - if len(fillchar) != 1: - raise OperationError(space.w_TypeError, - space.wrap("center() argument 2 must be a single character")) - - d = u_arg - len(u_self) - if d>0: - offset = d//2 + (d & u_arg & 1) - fillchar = fillchar[0] # annotator hint: it's a single character - u_centered = offset * fillchar + u_self + (d - offset) * fillchar - else: - u_centered = u_self - - return wrapstr(space, u_centered) - -def str_count__String_String_ANY_ANY(space, w_self, w_arg, w_start, w_end): - u_self, u_start, u_end = _convert_idx_params(space, w_self, w_start, w_end) - return wrapint(space, u_self.count(w_arg._value, u_start, u_end)) - -def str_endswith__String_String_ANY_ANY(space, w_self, w_suffix, w_start, w_end): - (u_self, start, end) = _convert_idx_params(space, w_self, w_start, - w_end, True) - return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) - -def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): - if not space.isinstance_w(w_suffixes, space.w_tuple): - raise FailedToImplement - (u_self, start, end) = _convert_idx_params(space, w_self, w_start, - w_end, True) - for w_suffix in space.fixedview(w_suffixes): - if space.isinstance_w(w_suffix, space.w_unicode): - w_u = space.call_function(space.w_unicode, w_self) - return space.call_method(w_u, "endswith", w_suffixes, w_start, - w_end) - suffix = space.str_w(w_suffix) - if stringendswith(u_self, suffix, start, end): - return space.w_True - return space.w_False - -def str_startswith__String_String_ANY_ANY(space, w_self, w_prefix, w_start, w_end): - (u_self, start, end) = _convert_idx_params(space, w_self, w_start, - w_end, True) - return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) - -def str_startswith__String_ANY_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): - if not space.isinstance_w(w_prefixes, space.w_tuple): - raise FailedToImplement - (u_self, start, end) = _convert_idx_params(space, w_self, - w_start, w_end, True) - for w_prefix in space.fixedview(w_prefixes): - if space.isinstance_w(w_prefix, space.w_unicode): - w_u = space.call_function(space.w_unicode, w_self) - return space.call_method(w_u, "startswith", w_prefixes, w_start, - w_end) - prefix = space.str_w(w_prefix) - if stringstartswith(u_self, prefix, start, end): - return space.w_True - return space.w_False - -def _tabindent(u_token, u_tabsize): - "calculates distance behind the token to the next tabstop" - - distance = u_tabsize - if u_token: - distance = 0 - offset = len(u_token) - - while 1: - #no sophisticated linebreak support now, '\r' just for passing adapted CPython test - if u_token[offset-1] == "\n" or u_token[offset-1] == "\r": - break - distance += 1 - offset -= 1 - if offset == 0: - break - - #the same like distance = len(u_token) - (offset + 1) - #print '' % (offset, distance, u_tabsize, u_token) - distance = (u_tabsize-distance) % u_tabsize - if distance == 0: - distance = u_tabsize - - return distance - - -def str_expandtabs__String_ANY(space, w_self, w_tabsize): - u_self = w_self._value - u_tabsize = space.int_w(w_tabsize) - - u_expanded = "" - if u_self: - split = u_self.split("\t") - try: - ovfcheck(len(split) * u_tabsize) - except OverflowError: - raise OperationError(space.w_OverflowError, - space.wrap("new string is too long") - ) - u_expanded = oldtoken = split.pop(0) - - for token in split: - #print "%d#%d -%s-" % (_tabindent(oldtoken,u_tabsize), u_tabsize, token) - u_expanded += " " * _tabindent(oldtoken, u_tabsize) + token - oldtoken = token - - return wrapstr(space, u_expanded) - - -def str_splitlines__String_ANY(space, w_self, w_keepends): - u_keepends = space.int_w(w_keepends) # truth value, but type checked - data = w_self._value - selflen = len(data) - strs_w = [] - i = j = 0 - while i < selflen: - # Find a line and append it - while i < selflen and data[i] != '\n' and data[i] != '\r': - i += 1 - # Skip the line break reading CRLF as one line break - eol = i - i += 1 - if i < selflen and data[i-1] == '\r' and data[i] == '\n': - i += 1 - if u_keepends: - eol = i - strs_w.append(sliced(space, data, j, eol, w_self)) - j = i - - if j < selflen: - strs_w.append(sliced(space, data, j, len(data), w_self)) - return space.newlist(strs_w) - -def str_zfill__String_ANY(space, w_self, w_width): - input = w_self._value - width = space.int_w(w_width) - - num_zeros = width - len(input) - if num_zeros <= 0: - # cannot return w_self, in case it is a subclass of str - return space.wrap(input) - - builder = StringBuilder(width) - if len(input) > 0 and (input[0] == '+' or input[0] == '-'): - builder.append(input[0]) - start = 1 - else: - start = 0 - - builder.append_multiple_char('0', num_zeros) - builder.append_slice(input, start, len(input)) - return space.wrap(builder.build()) - - -def hash__String(space, w_str): - s = w_str._value - x = compute_hash(s) - return wrapint(space, x) - -def lt__String_String(space, w_str1, w_str2): - s1 = w_str1._value - s2 = w_str2._value - if s1 < s2: - return space.w_True - else: - return space.w_False - -def le__String_String(space, w_str1, w_str2): - s1 = w_str1._value - s2 = w_str2._value - if s1 <= s2: - return space.w_True - else: - return space.w_False - -def eq__String_String(space, w_str1, w_str2): - s1 = w_str1._value - s2 = w_str2._value - if s1 == s2: - return space.w_True - else: - return space.w_False - -def ne__String_String(space, w_str1, w_str2): - s1 = w_str1._value - s2 = w_str2._value - if s1 != s2: - return space.w_True - else: - return space.w_False - -def gt__String_String(space, w_str1, w_str2): - s1 = w_str1._value - s2 = w_str2._value - if s1 > s2: - return space.w_True - else: - return space.w_False - -def ge__String_String(space, w_str1, w_str2): - s1 = w_str1._value - s2 = w_str2._value - if s1 >= s2: - return space.w_True - else: - return space.w_False - -def getitem__String_ANY(space, w_str, w_index): - ival = space.getindex_w(w_index, space.w_IndexError, "string index") - str = w_str._value - slen = len(str) - if ival < 0: - ival += slen - if ival < 0 or ival >= slen: - raise OperationError(space.w_IndexError, - space.wrap("string index out of range")) - return wrapchar(space, str[ival]) - -def getitem__String_Slice(space, w_str, w_slice): - s = w_str._value - length = len(s) - start, stop, step, sl = w_slice.indices4(space, length) - if sl == 0: - return W_BytesObject.EMPTY - elif step == 1: - assert start >= 0 and stop >= 0 - return sliced(space, s, start, stop, w_str) - else: - str = "".join([s[start + i*step] for i in range(sl)]) - return wrapstr(space, str) - -def getslice__String_ANY_ANY(space, w_str, w_start, w_stop): - s = w_str._value - start, stop = normalize_simple_slice(space, len(s), w_start, w_stop) - if start == stop: - return W_BytesObject.EMPTY - else: - return sliced(space, s, start, stop, w_str) - -def add__String_String(space, w_left, w_right): - right = w_right._value - left = w_left._value - return joined2(space, left, right) - -def len__String(space, w_str): - return space.wrap(len(w_str._value)) - -def str__String(space, w_str): - if type(w_str) is W_BytesObject: - return w_str - return wrapstr(space, w_str._value) - -def ord__String(space, w_str): - u_str = w_str._value - if len(u_str) != 1: - raise operationerrfmt( - space.w_TypeError, - "ord() expected a character, but string " - "of length %d found", len(u_str)) - return space.wrap(ord(u_str[0])) - -def getnewargs__String(space, w_str): - return space.newtuple([wrapstr(space, w_str._value)]) - -def repr__String(space, w_str): - s = w_str._value - - quote = "'" - if quote in s and '"' not in s: - quote = '"' - - return space.wrap(string_escape_encode(s, quote)) - def string_escape_encode(s, quote): buf = StringBuilder(len(s) + 2) @@ -1357,73 +341,16 @@ return buf.build() -DEFAULT_NOOP_TABLE = ''.join([chr(i) for i in range(256)]) -def str_translate__String_ANY_ANY(space, w_string, w_table, w_deletechars=''): - """charfilter - unicode handling is not implemented - - Return a copy of the string where all characters occurring - in the optional argument deletechars are removed, and the - remaining characters have been mapped through the given translation table, - which must be a string of length 256""" - - if space.is_w(w_table, space.w_None): - table = DEFAULT_NOOP_TABLE - else: - table = space.bufferstr_w(w_table) - if len(table) != 256: - raise OperationError( - space.w_ValueError, - space.wrap("translation table must be 256 characters long")) - - string = w_string._value - deletechars = space.str_w(w_deletechars) - if len(deletechars) == 0: - buf = StringBuilder(len(string)) - for char in string: - buf.append(table[ord(char)]) - else: - buf = StringBuilder() - deletion_table = [False] * 256 - for c in deletechars: - deletion_table[ord(c)] = True - for char in string: - if not deletion_table[ord(char)]: - buf.append(table[ord(char)]) - return W_BytesObject(buf.build()) - -def str_decode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None): - from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \ - unicode_from_string, decode_object - encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) - if encoding is None and errors is None: - return unicode_from_string(space, w_string) - return decode_object(space, w_string, encoding, errors) - -def str_encode__String_ANY_ANY(space, w_string, w_encoding=None, w_errors=None): - from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \ - encode_object - encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors) - return encode_object(space, w_string, encoding, errors) - -# CPython's logic for deciding if ""%values is -# an error (1 value, 0 %-formatters) or not -# (values is of a mapping type) -def mod__String_ANY(space, w_format, w_values): - return mod_format(space, w_format, w_values, do_unicode=False) - -def str_format__String(space, w_string, __args__): - return newformat.format_method(space, w_string, __args__, False) - -def format__String_ANY(space, w_string, w_format_spec): - if not space.isinstance_w(w_format_spec, space.w_str): - w_format_spec = space.str(w_format_spec) - spec = space.str_w(w_format_spec) - formatter = newformat.str_formatter(space, spec) - return formatter.format_string(w_string._value) - -def buffer__String(space, w_string): - return space.wrap(StringBuffer(w_string._value)) - -# register all methods -register_all(vars(), globals()) +#str_formatter_parser = SMM('_formatter_parser', 1) +#str_formatter_field_name_split = SMM('_formatter_field_name_split', 1) +# +#def str_formatter_parser__ANY(space, w_str): +# from pypy.objspace.std.newformat import str_template_formatter +# tformat = str_template_formatter(space, space.str_w(w_str)) +# return tformat.formatter_parser() +# +#def str_formatter_field_name_split__ANY(space, w_str): +# from pypy.objspace.std.newformat import str_template_formatter +# tformat = str_template_formatter(space, space.str_w(w_str)) +# return tformat.formatter_field_name_split() diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py --- a/pypy/objspace/std/dictmultiobject.py +++ b/pypy/objspace/std/dictmultiobject.py @@ -80,6 +80,7 @@ def __repr__(w_self): """representation for debugging purposes""" + #print('XXXXXXX', w_self.dstorage) return "%s(%s)" % (w_self.__class__.__name__, w_self.strategy) def unwrap(w_dict, space): diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -20,7 +20,7 @@ from rpython.rlib.rstring import StringBuilder from pypy.objspace.std.boolobject import W_BoolObject -from pypy.objspace.std.bytesobject import W_StringObject +from pypy.objspace.std.bytesobject import W_BytesObject from pypy.objspace.std.complexobject import W_ComplexObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.floatobject import W_FloatObject @@ -251,7 +251,7 @@ def PySTRING_CHECK_INTERNED(w_str): return False -def marshal_w__String(space, w_str, m): +def marshal_w__Bytes(space, w_str, m): # using the fastest possible access method here # that does not touch the internal representation, # which might change (array of bytes?) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -171,17 +171,8 @@ complexobject.delegate_Float2Complex), ] - self.typeorder[bytesobject.W_BytesObject] += [ - (unicodeobject.W_UnicodeObject, unicodeobject.delegate_String2Unicode), - ] if config.objspace.std.withstrbuf: from pypy.objspace.std import strbufobject - self.typeorder[strbufobject.W_StringBufferObject] += [ - (bytesobject.W_BytesObject, - strbufobject.delegate_buf2str), - (unicodeobject.W_UnicodeObject, - strbufobject.delegate_buf2unicode) - ] # put W_Root everywhere self.typeorder[W_Root] = [] @@ -371,7 +362,7 @@ ['delattr', 'delete', 'get', 'id', 'inplace_div', 'inplace_floordiv', 'inplace_lshift', 'inplace_mod', 'inplace_pow', 'inplace_rshift', 'inplace_truediv', 'is_', 'set', 'setattr', 'type', 'userdel', - 'isinstance', 'issubtype', 'int']) + 'isinstance', 'issubtype', 'int', 'ord']) # XXX should we just remove those from the method table or we're happy # with just not having multimethods? diff --git a/pypy/objspace/std/strbufobject.py b/pypy/objspace/std/strbufobject.py --- a/pypy/objspace/std/strbufobject.py +++ b/pypy/objspace/std/strbufobject.py @@ -1,7 +1,6 @@ from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_StringObject -from pypy.objspace.std.unicodeobject import delegate_String2Unicode +from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_BytesObject from rpython.rlib.rstring import StringBuilder from pypy.interpreter.buffer import Buffer @@ -19,7 +18,7 @@ s = self.builder.build() if self.length < len(s): s = s[:self.length] - self.w_str = W_StringObject(s) + self.w_str = W_BytesObject(s) return s else: return self.w_str._value @@ -47,18 +46,10 @@ # ____________________________________________________________ -def delegate_buf2str(space, w_strbuf): - w_strbuf.force() - return w_strbuf.w_str - -def delegate_buf2unicode(space, w_strbuf): - w_strbuf.force() - return delegate_String2Unicode(space, w_strbuf.w_str) - def len__StringBuffer(space, w_self): return space.wrap(w_self.length) -def add__StringBuffer_String(space, w_self, w_other): +def add__StringBuffer_Bytes(space, w_self, w_other): if w_self.builder.getlength() != w_self.length: builder = StringBuilder() builder.append(w_self.force()) diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py --- a/pypy/objspace/std/stringmethods.py +++ b/pypy/objspace/std/stringmethods.py @@ -1,4 +1,18 @@ -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.gateway import unwrap_spec, WrappedDefault +from pypy.objspace.std import slicetype +from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from rpython.rlib import jit +from rpython.rlib.objectmodel import specialize +from rpython.rlib.rarithmetic import ovfcheck +from rpython.rlib.rstring import split + + +_isspace = lambda c: c.isspace() +_isdigit = lambda c: c.isdigit() +_isalpha = lambda c: c.isalpha() +_isalnum = lambda c: c.isalnum() class StringMethods(object): @@ -13,35 +27,104 @@ def _val(self): raise NotImplementedError - def descr_eq(self, space): - pass + def _upper(self, ch): + if ch.islower(): + o = ord(ch) - 32 + return chr(o) + else: + return ch - def descr_ne(self, space): - pass + def _lower(self, ch): + if ch.isupper(): + o = ord(ch) + 32 + return chr(o) + else: + return ch - def descr_lt(self, space): - pass + def _sliced(self, space, s, start, stop, orig_obj): + assert start >= 0 + assert stop >= 0 + #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), space.w_str): + # return orig_obj + return self._new(s[start:stop]) - def descr_le(self, space): - pass + @specialize.arg(4) + def _convert_idx_params(self, space, w_start, w_end, upper_bound=False): + value = self._val() + lenself = len(value) + start, end = slicetype.unwrap_start_stop( + space, lenself, w_start, w_end, upper_bound=upper_bound) + return (value, start, end) - def descr_gt(self, space): - pass + def descr_eq(self, space, w_other): + try: + return space.newbool(self._val() == self._op_val(space, w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + if (e.match(space, space.w_UnicodeDecodeError) or + e.match(space, space.w_UnicodeEncodeError)): + msg = ("Unicode equal comparison failed to convert both " + "arguments to Unicode - interpreting them as being " + "unequal") + space.warn(space.wrap(msg), space.w_UnicodeWarning) + return space.w_False + raise - def descr_ge(self, space): - pass + def descr_ne(self, space, w_other): + try: + return space.newbool(self._val() != self._op_val(space, w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + if (e.match(space, space.w_UnicodeDecodeError) or + e.match(space, space.w_UnicodeEncodeError)): + msg = ("Unicode unequal comparison failed to convert both " + "arguments to Unicode - interpreting them as being " + "unequal") + space.warn(space.wrap(msg), space.w_UnicodeWarning) + return space.w_True + raise + + def descr_lt(self, space, w_other): + try: + return space.newbool(self._val() < self._op_val(space, w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + + def descr_le(self, space, w_other): + try: + return space.newbool(self._val() <= self._op_val(space, w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + + def descr_gt(self, space, w_other): + try: + return space.newbool(self._val() > self._op_val(space, w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented + + def descr_ge(self, space, w_other): + try: + return space.newbool(self._val() >= self._op_val(space, w_other)) + except OperationError, e: + if e.match(space, space.w_TypeError): + return space.w_NotImplemented def descr_len(self, space): - pass + return space.wrap(self._len()) - def descr_iter(self, space): - pass + #def descr_iter(self, space): + # pass - def descr_contains(self, space): - pass + def descr_contains(self, space, w_sub): + return space.newbool(self._val().find(self._op_val(space, w_sub)) >= 0) - def descr_add(self, space): - pass + def descr_add(self, space, w_other): + return self._new(self._val() + self._op_val(space, w_other)) def descr_mul(self, space, w_times): try: @@ -56,113 +139,753 @@ return self._new(self._val()[0] * times) return self._new(self._val() * times) - def descr_getitem(self, space): - pass + def descr_getitem(self, space, w_index): + if isinstance(w_index, W_SliceObject): + selfvalue = self._value + length = len(selfvalue) + start, stop, step, sl = w_index.indices4(space, length) + if sl == 0: + return self.EMPTY + elif step == 1: + assert start >= 0 and stop >= 0 + return self._sliced(space, selfvalue, start, stop, self) + else: + str = "".join([selfvalue[start + i*step] for i in range(sl)]) + return self._new(str) + + index = space.getindex_w(w_index, space.w_IndexError, "string index") + selfvalue = self._val() + selflen = len(selfvalue) + if index < 0: + index += selflen + if index < 0 or index >= selflen: + raise OperationError(space.w_IndexError, + space.wrap("string index out of range")) + #return wrapchar(space, selfvalue[index]) + return self._new(selfvalue[index]) + + def descr_getslice(self, space, w_start, w_stop): + selfvalue = self._val() From noreply at buildbot.pypy.org Tue May 28 14:55:43 2013 From: noreply at buildbot.pypy.org (Manuel Jacob) Date: Tue, 28 May 2013 14:55:43 +0200 (CEST) Subject: [pypy-commit] pypy refactor-str-types: hg merge default Message-ID: <20130528125543.C899B1C00BD@cobra.cs.uni-duesseldorf.de> Author: Manuel Jacob Branch: refactor-str-types Changeset: r64617:3032a93d573d Date: 2013-05-28 14:53 +0200 http://bitbucket.org/pypy/pypy/changeset/3032a93d573d/ Log: hg merge default diff too long, truncating to 2000 out of 2697 lines diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py --- a/lib-python/2.7/logging/__init__.py +++ b/lib-python/2.7/logging/__init__.py @@ -134,20 +134,22 @@ DEBUG = 10 NOTSET = 0 -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO : 'INFO', - DEBUG : 'DEBUG', - NOTSET : 'NOTSET', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARNING, - 'WARNING' : WARNING, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'NOTSET' : NOTSET, +_levelToName = { + CRITICAL: 'CRITICAL', + ERROR: 'ERROR', + WARNING: 'WARNING', + INFO: 'INFO', + DEBUG: 'DEBUG', + NOTSET: 'NOTSET', +} +_nameToLevel = { + 'CRITICAL': CRITICAL, + 'ERROR': ERROR, + 'WARN': WARNING, + 'WARNING': WARNING, + 'INFO': INFO, + 'DEBUG': DEBUG, + 'NOTSET': NOTSET, } def getLevelName(level): @@ -164,7 +166,7 @@ Otherwise, the string "Level %s" % level is returned. """ - return _levelNames.get(level, ("Level %s" % level)) + return _levelToName.get(level, ("Level %s" % level)) def addLevelName(level, levelName): """ @@ -174,8 +176,8 @@ """ _acquireLock() try: #unlikely to cause an exception, but you never know... - _levelNames[level] = levelName - _levelNames[levelName] = level + _levelToName[level] = levelName + _nameToLevel[levelName] = level finally: _releaseLock() @@ -183,9 +185,9 @@ if isinstance(level, int): rv = level elif str(level) == level: - if level not in _levelNames: + if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) - rv = _levelNames[level] + rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv @@ -277,7 +279,7 @@ self.lineno = lineno self.funcName = func self.created = ct - self.msecs = (ct - long(ct)) * 1000 + self.msecs = (ct - int(ct)) * 1000 self.relativeCreated = (self.created - _startTime) * 1000 if logThreads and thread: self.thread = thread.get_ident() diff --git a/lib-python/2.7/logging/config.py b/lib-python/2.7/logging/config.py --- a/lib-python/2.7/logging/config.py +++ b/lib-python/2.7/logging/config.py @@ -156,7 +156,7 @@ h = klass(*args) if "level" in opts: level = cp.get(sectname, "level") - h.setLevel(logging._levelNames[level]) + h.setLevel(level) if len(fmt): h.setFormatter(formatters[fmt]) if issubclass(klass, logging.handlers.MemoryHandler): @@ -187,7 +187,7 @@ opts = cp.options(sectname) if "level" in opts: level = cp.get(sectname, "level") - log.setLevel(logging._levelNames[level]) + log.setLevel(level) for h in root.handlers[:]: root.removeHandler(h) hlist = cp.get(sectname, "handlers") @@ -237,7 +237,7 @@ existing.remove(qn) if "level" in opts: level = cp.get(sectname, "level") - logger.setLevel(logging._levelNames[level]) + logger.setLevel(level) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate diff --git a/lib-python/2.7/test/test_logging.py b/lib-python/2.7/test/test_logging.py --- a/lib-python/2.7/test/test_logging.py +++ b/lib-python/2.7/test/test_logging.py @@ -65,7 +65,8 @@ self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] self.saved_loggers = logger_dict.copy() - self.saved_level_names = logging._levelNames.copy() + self.saved_name_to_level = logging._nameToLevel.copy() + self.saved_level_to_name = logging._levelToName.copy() finally: logging._releaseLock() @@ -97,8 +98,10 @@ self.root_logger.setLevel(self.original_logging_level) logging._acquireLock() try: - logging._levelNames.clear() - logging._levelNames.update(self.saved_level_names) + logging._levelToName.clear() + logging._levelToName.update(self.saved_level_to_name) + logging._nameToLevel.clear() + logging._nameToLevel.update(self.saved_name_to_level) logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -166,8 +166,7 @@ if self is StructOrUnion: return if '_fields_' not in self.__dict__: - self._fields_ = [] - _set_shape(self, [], self._is_union) + self._fields_ = [] # As a side-effet, this also sets the ffishape. __setattr__ = struct_setattr diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -124,14 +124,21 @@ @entrypoint('main', [], c_name='pypy_init_threads') def pypy_init_threads(): - if space.config.objspace.usemodules.thread: - os_thread.setup_threads(space) - rffi.aroundstate.before() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + rffi.aroundstate.before() @entrypoint('main', [], c_name='pypy_thread_attach') def pypy_thread_attach(): - if space.config.objspace.usemodules.thread: - rthread.gc_thread_start() + if not space.config.objspace.usemodules.thread: + return + os_thread.setup_threads(space) + os_thread.bootstrapper.acquire(space, None, None) + rthread.gc_thread_start() + os_thread.bootstrapper.nbthreads += 1 + os_thread.bootstrapper.release() + rffi.aroundstate.before() w_globals = space.newdict() space.setitem(w_globals, space.wrap('__builtins__'), diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -16,6 +16,11 @@ else: return space.int_w(w_size) +def unsupported(space, message): + w_exc = space.getattr(space.getbuiltinmodule('_io'), + space.wrap('UnsupportedOperation')) + return OperationError(w_exc, space.wrap(message)) + # May be called with any object def check_readable_w(space, w_obj): if not space.is_true(space.call_method(w_obj, 'readable')): @@ -86,6 +91,9 @@ # attribute as returned by whatever subclass. return self.__IOBase_closed + def _unsupportedoperation(self, space, message): + raise unsupported(space, message) + def _check_closed(self, space, message=None): if message is None: message = "I/O operation on closed file" @@ -111,9 +119,18 @@ space.w_ValueError, space.wrap("I/O operation on closed file")) + def seek_w(self, space, w_offset, w_whence=None): + self._unsupportedoperation(space, "seek") + def tell_w(self, space): return space.call_method(self, "seek", space.wrap(0), space.wrap(1)) + def truncate_w(self, space, w_size=None): + self._unsupportedoperation(space, "truncate") + + def fileno_w(self, space): + self._unsupportedoperation(space, "fileno") + def enter_w(self, space): self._check_closed(space) return space.wrap(self) @@ -248,11 +265,15 @@ next = interp2app(W_IOBase.next_w), close = interp2app(W_IOBase.close_w), flush = interp2app(W_IOBase.flush_w), + seek = interp2app(W_IOBase.seek_w), tell = interp2app(W_IOBase.tell_w), + truncate = interp2app(W_IOBase.truncate_w), + fileno = interp2app(W_IOBase.fileno_w), isatty = interp2app(W_IOBase.isatty_w), readable = interp2app(W_IOBase.readable_w), writable = interp2app(W_IOBase.writable_w), seekable = interp2app(W_IOBase.seekable_w), + _checkReadable = interp2app(check_readable_w), _checkWritable = interp2app(check_writable_w), _checkSeekable = interp2app(check_seekable_w), diff --git a/pypy/module/_io/interp_textio.py b/pypy/module/_io/interp_textio.py --- a/pypy/module/_io/interp_textio.py +++ b/pypy/module/_io/interp_textio.py @@ -196,11 +196,6 @@ def __init__(self, space): W_IOBase.__init__(self, space) - def _unsupportedoperation(self, space, message): - w_exc = space.getattr(space.getbuiltinmodule('_io'), - space.wrap('UnsupportedOperation')) - raise OperationError(w_exc, space.wrap(message)) - def read_w(self, space, w_size=None): self._unsupportedoperation(space, "read") diff --git a/pypy/module/_io/test/test_io.py b/pypy/module/_io/test/test_io.py --- a/pypy/module/_io/test/test_io.py +++ b/pypy/module/_io/test/test_io.py @@ -43,6 +43,13 @@ import _io e = _io.UnsupportedOperation("seek") + def test_default_implementations(self): + import _io + file = _io._IOBase() + raises(_io.UnsupportedOperation, file.seek, 0, 1) + raises(_io.UnsupportedOperation, file.fileno) + raises(_io.UnsupportedOperation, file.truncate) + def test_blockingerror(self): import _io try: diff --git a/pypy/module/_io/test/test_textio.py b/pypy/module/_io/test/test_textio.py --- a/pypy/module/_io/test/test_textio.py +++ b/pypy/module/_io/test/test_textio.py @@ -26,6 +26,14 @@ assert t.readable() assert t.seekable() + def test_default_implementations(self): + import _io + file = _io._TextIOBase() + raises(_io.UnsupportedOperation, file.read) + raises(_io.UnsupportedOperation, file.seek, 0) + raises(_io.UnsupportedOperation, file.readline) + raises(_io.UnsupportedOperation, file.detach) + def test_unreadable(self): import _io class UnReadable(_io.BytesIO): diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -13,6 +13,7 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', '_reconstruct' : 'interp_numarray._reconstruct', + 'scalar' : 'interp_numarray.build_scalar', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -46,11 +46,11 @@ self.name = name class FakeSpace(object): - w_ValueError = "ValueError" - w_TypeError = "TypeError" - w_IndexError = "IndexError" - w_OverflowError = "OverflowError" - w_NotImplementedError = "NotImplementedError" + w_ValueError = W_TypeObject("ValueError") + w_TypeError = W_TypeObject("TypeError") + w_IndexError = W_TypeObject("IndexError") + w_OverflowError = W_TypeObject("OverflowError") + w_NotImplementedError = W_TypeObject("NotImplementedError") w_None = None w_bool = W_TypeObject("bool") diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -11,6 +11,8 @@ from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from rpython.rlib.objectmodel import specialize +from pypy.interpreter.mixedmodule import MixedModule MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else () MIXIN_64 = (int_typedef,) if LONG_BIT == 64 else () @@ -33,7 +35,11 @@ def new(space, w_subtype, w_value): dtype = _get_dtype(space) return dtype.itemtype.coerce_subtype(space, w_subtype, w_value) - return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype) + + def descr_reduce(self, space): + return self.reduce(space) + + return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype), func_with_new_name(descr_reduce, "descr_reduce") class PrimitiveBox(object): @@ -48,6 +54,26 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.value) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, flavor="raw") + value[0] = self.value + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.value))) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret + class ComplexBox(object): _mixin_ = True @@ -64,6 +90,26 @@ def convert_imag_to(self, dtype): return dtype.box(self.imag) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, flavor="raw") + value[0] = self.real + value[1] = self.imag + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.real)) * 2) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret class W_GenericBox(W_Root): _attrs_ = () @@ -187,7 +233,7 @@ return convert_to_array(space, w_values) class W_BoolBox(W_GenericBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("bool") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("bool") class W_NumberBox(W_GenericBox): _attrs_ = () @@ -203,40 +249,40 @@ pass class W_Int8Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int8") class W_UInt8Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint8") class W_Int16Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int16") class W_UInt16Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint16") class W_Int32Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int32") class W_UInt32Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint32") class W_LongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("long") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("long") class W_ULongBox(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("ulong") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("ulong") class W_Int64Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int64") class W_LongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('longlong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('longlong') class W_UInt64Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint64") class W_ULongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('ulonglong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('ulonglong') class W_InexactBox(W_NumberBox): _attrs_ = () @@ -245,15 +291,17 @@ _attrs_ = () class W_Float16Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float16") class W_Float32Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float32") class W_Float64Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): + _attrs_ = ['ofs', 'dtype', 'arr'] + _immutable_fields_ = ['ofs'] def __init__(self, arr, ofs, dtype): self.arr = arr # we have to keep array alive self.ofs = ofs @@ -354,33 +402,33 @@ class W_Complex64Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex64") _COMPONENTS_BOX = W_Float32Box class W_Complex128Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex128") _COMPONENTS_BOX = W_Float64Box if ENABLED_LONG_DOUBLE and long_double_size == 12: class W_Float96Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float96") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float96") W_LongDoubleBox = W_Float96Box class W_Complex192Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex192") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex192") _COMPONENTS_BOX = W_Float96Box W_CLongDoubleBox = W_Complex192Box elif ENABLED_LONG_DOUBLE and long_double_size == 16: class W_Float128Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float128") W_LongDoubleBox = W_Float128Box class W_Complex256Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex256") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex256") _COMPONENTS_BOX = W_Float128Box W_CLongDoubleBox = W_Complex256Box @@ -456,6 +504,7 @@ __module__ = "numpypy", __new__ = interp2app(W_BoolBox.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_BoolBox.descr_reduce), ) W_NumberBox.typedef = TypeDef("number", W_GenericBox.typedef, @@ -478,42 +527,49 @@ __module__ = "numpypy", __new__ = interp2app(W_Int8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int8Box.descr_reduce), ) W_UInt8Box.typedef = TypeDef("uint8", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt8Box.descr_reduce), ) W_Int16Box.typedef = TypeDef("int16", W_SignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Int16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int16Box.descr_reduce), ) W_UInt16Box.typedef = TypeDef("uint16", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt16Box.descr_reduce), ) W_Int32Box.typedef = TypeDef("int32", (W_SignedIntegerBox.typedef,) + MIXIN_32, __module__ = "numpypy", __new__ = interp2app(W_Int32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int32Box.descr_reduce), ) W_UInt32Box.typedef = TypeDef("uint32", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt32Box.descr_reduce), ) W_Int64Box.typedef = TypeDef("int64", (W_SignedIntegerBox.typedef,) + MIXIN_64, __module__ = "numpypy", __new__ = interp2app(W_Int64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int64Box.descr_reduce), ) if LONG_BIT == 32: @@ -527,6 +583,7 @@ __module__ = "numpypy", __new__ = interp2app(W_UInt64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt64Box.descr_reduce), ) W_InexactBox.typedef = TypeDef("inexact", W_NumberBox.typedef, @@ -541,23 +598,27 @@ __module__ = "numpypy", __new__ = interp2app(W_Float16Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float16Box.descr_reduce), ) W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Float32Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float32Box.descr_reduce), ) W_Float64Box.typedef = TypeDef("float64", (W_FloatingBox.typedef, float_typedef), __module__ = "numpypy", __new__ = interp2app(W_Float64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float64Box.descr_reduce), ) if ENABLED_LONG_DOUBLE and long_double_size == 12: W_Float96Box.typedef = TypeDef("float96", (W_FloatingBox.typedef), __module__ = "numpypy", + __reduce__ = interp2app(W_Float96Box.descr_reduce), __new__ = interp2app(W_Float96Box.descr__new__.im_func), ) @@ -565,6 +626,7 @@ W_Complex192Box.typedef = TypeDef("complex192", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex192Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex192Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -574,11 +636,13 @@ __module__ = "numpypy", __new__ = interp2app(W_Float128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float128Box.descr_reduce), ) W_Complex256Box.typedef = TypeDef("complex256", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex256Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex256Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -616,6 +680,7 @@ W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex128Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -623,6 +688,7 @@ W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex64Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox .descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,6 +1051,17 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) + def build_scalar(space, w_dtype, w_state): + from rpython.rtyper.lltypesystem import rffi, lltype + + assert isinstance(w_dtype, interp_dtype.W_Dtype) + + state = rffi.str2charp(space.str_w(w_state)) + box = w_dtype.itemtype.box_raw_data(state) + lltype.free(state, flavor="raw") + return box + + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -786,7 +786,7 @@ def test_create_subarrays(self): from numpypy import dtype - d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + d = dtype([("x", "float", (2,)), ("y", "int64", (2,))]) assert d.itemsize == 32 assert d.name == "void256" keys = d.fields.keys() diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2715,7 +2715,7 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") @@ -2735,7 +2735,7 @@ def test_multidim_subarray(self): from numpypy import dtype, array - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -0,0 +1,23 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +class AppTestScalar(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) + + def test_pickle(self): + from numpypy import dtype, int32, float64, complex128, zeros, sum + from numpypy.core.multiarray import scalar + from cPickle import loads, dumps + i = int32(1337) + f = float64(13.37) + c = complex128(13 + 37.j) + + assert i.__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) + assert f.__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) + assert c.__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) + + assert loads(dumps(i)) == i + assert loads(dumps(f)) == f + assert loads(dumps(c)) == c + + a = zeros(3) + assert loads(dumps(sum(a))) == sum(a) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -145,6 +145,11 @@ #XXX this is the place to display a warning return self.box(real) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box(array[0]) + @specialize.argtype(1) def unbox(self, box): assert isinstance(box, self.BoxType) @@ -1108,6 +1113,11 @@ rffi.cast(self.T, real), rffi.cast(self.T, imag)) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box_complex(array[0], array[1]) + def unbox(self, box): assert isinstance(box, self.BoxType) # do this in two stages since real, imag are read only @@ -1705,8 +1715,10 @@ def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match + from interp_dtype import W_Dtype items_w = space.fixedview(w_items) subdtype = dtype.subdtype + assert isinstance(subdtype, W_Dtype) itemtype = subdtype.itemtype if len(shape) <= 1: for i in range(len(items_w)): diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py --- a/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py +++ b/pypy/module/test_lib_pypy/ctypes_tests/test_structures.py @@ -239,6 +239,9 @@ pass pos = POSITION(1, 2) assert (pos.x, pos.y) == (1, 2) + # Try a second time, result may be different (cf. issue1498) + pos = POSITION(1, 2) + assert (pos.x, pos.y) == (1, 2) def test_invalid_field_types(self): diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -412,7 +412,7 @@ # No more items to compare -- compare sizes return space.newbool(op(self.length(), w_list2.length())) - return func_with_new_name(compare_unwrappeditems, name + '__List_List') + return func_with_new_name(compare_unwrappeditems, 'descr_' + name) descr_lt = _make_list_comparison('lt') descr_le = _make_list_comparison('le') diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT, VOID from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -27,6 +27,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.arm import callbuilder class AssemblerARM(ResOpAssembler): @@ -934,23 +935,6 @@ asm_math_operations[oopspecindex](self, op, arglocs, regalloc, fcond) return fcond - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 4: - return - if size == 1: - if not signed: # unsigned char - self.mc.AND_ri(resloc.value, resloc.value, 0xFF) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 24) - self.mc.ASR_ri(resloc.value, resloc.value, 24) - elif size == 2: - if not signed: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.LSR_ri(resloc.value, resloc.value, 16) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.ASR_ri(resloc.value, resloc.value, 16) - def patch_trace(self, faildescr, looptoken, bridge_addr, regalloc): b = InstrBuilder(self.cpu.cpuinfo.arch_version) patch_addr = faildescr._arm_failure_recovery_block @@ -1012,20 +996,32 @@ mc.gen_load_int(helper.value, ofs, cond=cond) mc.STR_rr(source.value, base.value, helper.value, cond=cond) + def get_tmp_reg(self, forbidden_regs=None): + if forbidden_regs is None: + return r.ip, False + for x in [r.ip, r.lr]: + if x not in forbidden_regs: + return x, False + # pick some reg, that we need to save + for x in r.all_regs: + if x not in forbidden_regs: + return x, True + assert 0 + def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL): - if not loc.is_reg() and not (loc.is_stack() and loc.type != FLOAT): + if loc.type == FLOAT: raise AssertionError("invalid target for move from imm value") if loc.is_reg(): new_loc = loc - elif loc.is_stack(): - self.mc.PUSH([r.lr.value], cond=cond) + elif loc.is_stack() or loc.is_raw_sp(): new_loc = r.lr else: raise AssertionError("invalid target for move from imm value") self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond) if loc.is_stack(): self.regalloc_mov(new_loc, loc) - self.mc.POP([r.lr.value], cond=cond) + elif loc.is_raw_sp(): + self.store_reg(self.mc, new_loc, r.sp, loc.value, cond=cond, helper=r.ip) def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_imm(): @@ -1034,60 +1030,77 @@ self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond) elif loc.is_stack() and loc.type != FLOAT: # spill a core register - if prev_loc is r.ip: - temp = r.lr - else: - temp = r.ip + temp, save = self.get_tmp_reg([prev_loc, loc]) offset = loc.value is_imm = check_imm_arg(offset, size=0xFFF) - if not is_imm: + if not is_imm and save: self.mc.PUSH([temp.value], cond=cond) self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) - if not is_imm: + if not is_imm and save: self.mc.POP([temp.value], cond=cond) + elif loc.is_raw_sp() and loc.type != FLOAT: + temp, save = self.get_tmp_reg([prev_loc]) + assert not save + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) else: assert 0, 'unsupported case' def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL): - # disabled for now, has side effects in combination with remap_frame_layout when called from a jump - helper = None # self._regalloc.get_free_reg() + helper = None + offset = prev_loc.value + tmp = None if loc.is_reg(): assert prev_loc.type != FLOAT, 'trying to load from an \ incompatible location into a core register' - assert loc is not r.lr, 'lr is not supported as a target \ - when moving from the stack' # unspill a core register - offset = prev_loc.value is_imm = check_imm_arg(offset, size=0xFFF) - helper = r.lr if helper is None else helper - save_helper = not is_imm and helper is r.lr + helper, save = self.get_tmp_reg([loc]) + save_helper = not is_imm and save elif loc.is_vfp_reg(): assert prev_loc.type == FLOAT, 'trying to load from an \ incompatible location into a float register' # load spilled value into vfp reg - offset = prev_loc.value is_imm = check_imm_arg(offset) - helper = r.ip if helper is None else helper - save_helper = not is_imm and helper is r.ip + helper, save = self.get_tmp_reg() + save_helper = not is_imm and save + elif loc.is_raw_sp(): + assert (loc.type == prev_loc.type == FLOAT + or (loc.type != FLOAT and prev_loc.type != FLOAT)) + tmp = loc + if loc.is_float(): + loc = r.vfp_ip + else: + loc, save_helper = self.get_tmp_reg() + assert not save_helper + helper, save_helper = self.get_tmp_reg([loc]) + assert not save_helper else: assert 0, 'unsupported case' + if save_helper: self.mc.PUSH([helper.value], cond=cond) self.load_reg(self.mc, loc, r.fp, offset, cond=cond, helper=helper) if save_helper: self.mc.POP([helper.value], cond=cond) + if tmp and tmp.is_raw_sp(): + self.store_reg(self.mc, loc, r.sp, tmp.value, cond=cond, helper=helper) + def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_vfp_reg(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond) - self.load_reg(self.mc, loc, r.ip, 0, cond=cond) - self.mc.POP([r.ip.value], cond=cond) - elif loc.is_stack(): - self.regalloc_push(r.vfp_ip) + helper, save_helper = self.get_tmp_reg([loc]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, prev_loc.getint(), cond=cond) + self.load_reg(self.mc, loc, helper, 0, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) + elif loc.is_stack() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - self.regalloc_pop(r.vfp_ip) + elif loc.is_raw_sp() and loc.type == FLOAT: + self.regalloc_mov(prev_loc, r.vfp_ip, cond) + self.regalloc_mov(r.vfp_ip, loc, cond) else: assert 0, 'unsupported case' @@ -1100,11 +1113,11 @@ # spill vfp register offset = loc.value is_imm = check_imm_arg(offset) - if not is_imm: - self.mc.PUSH([r.ip.value], cond=cond) - self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond) - if not is_imm: - self.mc.POP([r.ip.value], cond=cond) + self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) + elif loc.is_raw_sp(): + assert loc.type == FLOAT, 'trying to store to an \ + incompatible location from a float register' + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' @@ -1120,6 +1133,8 @@ self._mov_imm_float_to_loc(prev_loc, loc, cond) elif prev_loc.is_vfp_reg(): self._mov_vfp_reg_to_loc(prev_loc, loc, cond) + elif prev_loc.is_raw_sp(): + assert 0, 'raw sp locs are not supported as source loc' else: assert 0, 'unsupported case' mov_loc_loc = regalloc_mov @@ -1131,23 +1146,29 @@ if vfp_loc.is_vfp_reg(): self.mc.VMOV_rc(reg1.value, reg2.value, vfp_loc.value, cond=cond) elif vfp_loc.is_imm_float(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, vfp_loc.getint(), cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, vfp_loc.getint(), cond=cond) # we need to load one word to loc and one to loc+1 which are # two 32-bit core registers - self.mc.LDR_ri(reg1.value, r.ip.value, cond=cond) - self.mc.LDR_ri(reg2.value, r.ip.value, imm=WORD, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + self.mc.LDR_ri(reg1.value, helper.value, cond=cond) + self.mc.LDR_ri(reg2.value, helper.value, imm=WORD, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif vfp_loc.is_stack() and vfp_loc.type == FLOAT: # load spilled vfp value into two core registers offset = vfp_loc.value if not check_imm_arg(offset, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.LDR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.LDR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.LDR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.LDR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.LDR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.LDR_ri(reg2.value, r.fp.value, @@ -1165,12 +1186,15 @@ # move from two core registers to a float stack location offset = vfp_loc.value if not check_imm_arg(offset + WORD, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.STR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.STR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.STR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.STR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.STR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.STR_ri(reg2.value, r.fp.value, @@ -1417,6 +1441,26 @@ # return shiftsize + def simple_call(self, fnloc, arglocs, result_loc=r.r0): + if result_loc is None: + result_type = VOID + result_size = 0 + elif result_loc.is_vfp_reg(): + result_type = FLOAT + result_size = DOUBLE_WORD + else: + result_type = INT + result_size = WORD + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() + + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs) + cb.emit_no_collect() + + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/callbuilder.py @@ -0,0 +1,304 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT, REF +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.assembler import saved_registers +from rpython.jit.backend.arm.helper.regalloc import check_imm_arg + + +class ARMCallbuilder(AbstractCallBuilder): + def __init__(self, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) + self.current_sp = 0 + + def push_gcmap(self): + assert not self.is_call_release_gil + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r0], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + self.asm.pop_gcmap(self.mc) + + def emit_raw_call(self): + #the actual call + if self.fnloc.is_imm(): + self.mc.BL(self.fnloc.value) + return + if self.fnloc.is_stack(): + self.asm.mov_loc_loc(self.fnloc, r.ip) + self.fnloc = r.ip + assert self.fnloc.is_reg() + self.mc.BLX(self.fnloc.value) + + def restore_stack_pointer(self): + # readjust the sp in case we passed some args on the stack + assert self.current_sp % 8 == 0 # sanity check + if self.current_sp != 0: + self._adjust_sp(self.current_sp) + self.current_sp = 0 + + def _push_stack_args(self, stack_args, on_stack): + assert on_stack % 8 == 0 + self._adjust_sp(-on_stack) + self.current_sp = on_stack + ofs = 0 + for i, arg in enumerate(stack_args): + if arg is not None: + sp_loc = RawSPStackLocation(ofs, arg.type) + self.asm.regalloc_mov(arg, sp_loc) + ofs += sp_loc.width + else: # alignment word + ofs += WORD + + def _adjust_sp(self, n): + # adjust the current stack pointer by n bytes + if n > 0: + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value) + else: + n = abs(n) + if check_imm_arg(n): + self.mc.SUB_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value) + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + + def call_releasegil_addr_and_move_real_arguments(self): + assert not self.asm._is_asmgcc() + from rpython.jit.backend.arm.regalloc import CoreRegisterManager + with saved_registers(self.mc, + CoreRegisterManager.save_around_call_regs): + self.mc.BL(self.asm.releasegil_addr) + + if not we_are_translated(): # for testing: we should not access + self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got + assert not self.asm._is_asmgcc() + gpr_to_save, vfp_to_save = self.get_result_locs() + with saved_registers(self.mc, gpr_to_save, vfp_to_save): + self.mc.BL(self.asm.reacqgil_addr) + + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again + + # for shadowstack, done for us by _reload_frame_if_necessary() + + def get_result_locs(self): + raise NotImplementedError + + def _ensure_result_bit_extension(self, resloc, size, signed): + if size == 4: + return + if size == 1: + if not signed: # unsigned char + self.mc.AND_ri(resloc.value, resloc.value, 0xFF) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 24) + self.mc.ASR_ri(resloc.value, resloc.value, 24) + elif size == 2: + if not signed: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.LSR_ri(resloc.value, resloc.value, 16) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.ASR_ri(resloc.value, resloc.value, 16) + + + +class SoftFloatCallBuilder(ARMCallbuilder): + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [r.r0, r.r1], [] + assert self.resloc.is_reg() + return [r.r0], [] + + def load_result(self): + # ensure the result is wellformed and stored in the correct location + resloc = self.resloc + if resloc is None: + return + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + # move result to the allocated register + if resloc is not r.r0: + self.asm.mov_loc_loc(r.r0, resloc) + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + + def _collect_and_push_stack_args(self, arglocs): + n_args = len(arglocs) + reg_args = count_reg_args(arglocs) + # all arguments past the 4th go on the stack + # first we need to prepare the list so it stays aligned + stack_args = [] + count = 0 + on_stack = 0 + if n_args > reg_args: + for i in range(reg_args, n_args): + arg = arglocs[i] + if arg.type != FLOAT: + count += 1 + on_stack += 1 + else: + on_stack += 2 + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + if count % 2 != 0: + on_stack += 1 + stack_args.append(None) + if on_stack > 0: + self._push_stack_args(stack_args, on_stack*WORD) + + def prepare_arguments(self): + arglocs = self.arglocs + reg_args = count_reg_args(arglocs) + self._collect_and_push_stack_args(arglocs) + # collect variables that need to go in registers and the registers they + # will be stored in + num = 0 + count = 0 + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(reg_args): + arg = arglocs[i] + if arg.type == FLOAT and count % 2 != 0: + num += 1 + count = 0 + reg = r.caller_resp[num] + + if arg.type == FLOAT: + float_locs.append((arg, reg)) + else: + non_float_locs.append(arg) + non_float_regs.append(reg) + + if arg.type == FLOAT: + num += 2 + else: + num += 1 + count += 1 + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in r.argument_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + + for loc, reg in float_locs: + self.asm.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) + +class HardFloatCallBuilder(ARMCallbuilder): + + def prepare_arguments(self): + non_float_locs = [] + non_float_regs = [] + float_locs = [] + float_regs = [] + stack_args = [] + + arglocs = self.arglocs + argtypes = self.argtypes + + count = 0 # stack alignment counter + on_stack = 0 + for arg in arglocs: + if arg.type != FLOAT: + if len(non_float_regs) < len(r.argument_regs): + reg = r.argument_regs[len(non_float_regs)] + non_float_locs.append(arg) + non_float_regs.append(reg) + else: # non-float argument that needs to go on the stack + count += 1 + on_stack += 1 + stack_args.append(arg) + else: + if len(float_regs) < len(r.vfp_argument_regs): + reg = r.vfp_argument_regs[len(float_regs)] + float_locs.append(arg) + float_regs.append(reg) + else: # float argument that needs to go on the stack + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + on_stack += 2 + # align the stack + if count % 2 != 0: + stack_args.append(None) + on_stack += 1 + self._push_stack_args(stack_args, on_stack*WORD) + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + # remap values stored in vfp registers + remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip) + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None and resloc.is_reg(): + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [], [r.d0] + assert self.resloc.is_reg() + return [r.r0], [] + + +def get_callbuilder(cpu, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + if cpu.cpuinfo.hf_abi: + return HardFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) + else: + return SoftFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) diff --git a/rpython/jit/backend/arm/locations.py b/rpython/jit/backend/arm/locations.py --- a/rpython/jit/backend/arm/locations.py +++ b/rpython/jit/backend/arm/locations.py @@ -12,6 +12,9 @@ def is_stack(self): return False + def is_raw_sp(self): + return False + def is_reg(self): return False @@ -145,7 +148,27 @@ return self.position + 10000 def is_float(self): - return type == FLOAT + return self.type == FLOAT + +class RawSPStackLocation(AssemblerLocation): + _immutable_ = True + + def __init__(self, sp_offset, type=INT): + if type == FLOAT: + self.width = DOUBLE_WORD + else: + self.width = WORD + self.value = sp_offset + self.type = type + + def __repr__(self): + return 'SP(%s)+%d' % (self.type, self.value,) + + def is_raw_sp(self): + return True + + def is_float(self): + return self.type == FLOAT def imm(i): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -13,8 +13,7 @@ gen_emit_float_cmp_op, gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, - saved_registers, - count_reg_args) + saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout @@ -31,8 +30,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.arm import callbuilder class ArmGuardToken(GuardToken): @@ -339,217 +337,36 @@ return fcond def emit_op_call(self, op, arglocs, regalloc, fcond): - resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + return self._emit_call(op, arglocs, fcond=fcond) + + def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): + # args = [resloc, size, sign, args...] + from rpython.jit.backend.llsupport.descr import CallDescr + + cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3], arglocs[4:], arglocs[0]) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - cond = self._emit_call(adr, arglist, - fcond, resloc, (size, signed)) - return cond + assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[1] + assert sizeloc.is_imm() + cb.ressize = sizeloc.value + signloc = arglocs[2] + assert signloc.is_imm() + cb.ressign = signloc.value - def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None, - result_info=(-1, -1), - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True): - if self.cpu.cpuinfo.hf_abi: - stack_args, adr = self._setup_call_hf(adr, arglocs, fcond, - resloc, result_info) + if is_call_release_gil: + cb.emit_call_release_gil() else: - stack_args, adr = self._setup_call_sf(adr, arglocs, fcond, - resloc, result_info) - - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - #the actual call - if adr.is_imm(): - self.mc.BL(adr.value) - elif adr.is_stack(): - self.mov_loc_loc(adr, r.ip) - adr = r.ip - else: - assert adr.is_reg() - if adr.is_reg(): - self.mc.BLX(adr.value) - self._restore_sp(stack_args, fcond) - - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg() and not self.cpu.cpuinfo.hf_abi: - # move result to the allocated register - self.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg() and result_info != (-1, -1): - self._ensure_result_bit_extension(resloc, result_info[0], - result_info[1]) - if can_collect: - self._reload_frame_if_necessary(self.mc) - self.pop_gcmap(self.mc) + cb.emit() return fcond - def _restore_sp(self, stack_args, fcond): - # readjust the sp in case we passed some args on the stack - if len(stack_args) > 0: - n = 0 - for arg in stack_args: - if arg is None or arg.type != FLOAT: - n += WORD - else: - n += DOUBLE_WORD - self._adjust_sp(-n, fcond=fcond) - assert n % 8 == 0 # sanity check - - def _adjust_sp(self, n, cb=None, fcond=c.AL, base_reg=r.sp): - if cb is None: - cb = self.mc - if n < 0: - n = -n - rev = True - else: - rev = False - if n <= 0xFF and fcond == c.AL: - if rev: - cb.ADD_ri(r.sp.value, base_reg.value, n) - else: - cb.SUB_ri(r.sp.value, base_reg.value, n) - else: - cb.gen_load_int(r.ip.value, n, cond=fcond) - if rev: - cb.ADD_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - else: - cb.SUB_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - - - def _collect_stack_args_sf(self, arglocs): - n_args = len(arglocs) - reg_args = count_reg_args(arglocs) - # all arguments past the 4th go on the stack - # first we need to prepare the list so it stays aligned - stack_args = [] - count = 0 - if n_args > reg_args: - for i in range(reg_args, n_args): - arg = arglocs[i] - if arg.type != FLOAT: - count += 1 - else: - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - if count % 2 != 0: - stack_args.append(None) - return stack_args - - def _push_stack_args(self, stack_args): - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.regalloc_push(arg) - - def _setup_call_sf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - reg_args = count_reg_args(arglocs) - stack_args = self._collect_stack_args_sf(arglocs) - self._push_stack_args(stack_args) - # collect variables that need to go in registers and the registers they - # will be stored in - num = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - for i in range(reg_args): - arg = arglocs[i] - if arg.type == FLOAT and count % 2 != 0: - num += 1 - count = 0 - reg = r.caller_resp[num] - - if arg.type == FLOAT: - float_locs.append((arg, reg)) - else: - non_float_locs.append(arg) - non_float_regs.append(reg) - - if arg.type == FLOAT: - num += 2 - else: - num += 1 - count += 1 - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - - for loc, reg in float_locs: - self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) - return stack_args, adr - - def _setup_call_hf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - count = 0 # stack alignment counter - for arg in arglocs: - if arg.type != FLOAT: - if len(non_float_regs) < len(r.argument_regs): - reg = r.argument_regs[len(non_float_regs)] - non_float_locs.append(arg) - non_float_regs.append(reg) - else: # non-float argument that needs to go on the stack - count += 1 - stack_args.append(arg) - else: - if len(float_regs) < len(r.vfp_argument_regs): - reg = r.vfp_argument_regs[len(float_regs)] - float_locs.append(arg) - float_regs.append(reg) - else: # float argument that needs to go on the stack - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - # align the stack - if count % 2 != 0: - stack_args.append(None) - self._push_stack_args(stack_args) - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - # remap values stored in vfp registers - remap_frame_layout(self, float_locs, float_regs, r.vfp_ip) - - return stack_args, adr - def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs - self.mov_loc_loc(argloc, resloc) + if argloc is not resloc: + self.mov_loc_loc(argloc, resloc) return fcond emit_op_cast_ptr_to_int = emit_op_same_as @@ -1037,9 +854,8 @@ length_loc = bytes_loc # call memcpy() regalloc.before_call() - self._emit_call(imm(self.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.simple_call_no_collect(imm(self.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.rm.possibly_free_var(length_box) regalloc.rm.possibly_free_var(dstaddr_box) regalloc.rm.possibly_free_var(srcaddr_box) @@ -1127,14 +943,14 @@ vloc = imm(0) self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op), guard_op.numargs()) + regalloc._prepare_guard(guard_op)) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self._emit_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], result_loc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self._emit_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, result_loc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') @@ -1213,20 +1029,14 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed)) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) + self._emit_call(op, callargs, fcond=fcond) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def _emit_guard_may_force(self, guard_op, arglocs, numargs): + def _emit_guard_may_force(self, guard_op, arglocs): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) @@ -1235,68 +1045,14 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): - + numargs = op.numargs() + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - # do the call - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed), - can_collect=False) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - self.pop_gcmap(self.mc) # remove the gcmap saved above - - self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) + self._emit_call(op, callargs, is_call_release_gil=True) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): - # Save caller saved registers and do the call - # NOTE: We assume that the floating point registers won't be modified. - assert gcrootmap.is_shadow_stack - with saved_registers(self.mc, regalloc.rm.save_around_call_regs): - self._emit_call(imm(self.releasegil_addr), [], - fcond, can_collect=False) - - def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): - # save the previous result into the stack temporarily, in case it is in - # a caller saved register. - # NOTE: like with call_release_gil(), we assume that we don't need to - # save vfp regs in this case. Besides the result location - regs_to_save = [] - vfp_regs_to_save = [] - if save_loc and save_loc in regalloc.rm.save_around_call_regs: - regs_to_save.append(save_loc) - regs_to_save.append(r.ip) # for alingment - elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs: - vfp_regs_to_save.append(save_loc) - assert gcrootmap.is_shadow_stack - # call the reopenstack() function (also reacquiring the GIL) - with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): - self._emit_call(imm(self.reacqgil_addr), [], fcond, - can_collect=False) - self._reload_frame_if_necessary(self.mc) - def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -34,6 +34,7 @@ from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr from rpython.rlib.rarithmetic import r_uint +from rpython.jit.backend.llsupport.descr import CallDescr # xxx hack: set a default value for TargetToken._ll_loop_code. If 0, we know @@ -555,9 +556,27 @@ return self._prepare_call(op) def _prepare_call(self, op, force_store=[], save_all_regs=False): - args = [None] * (op.numargs() + 1) + args = [None] * (op.numargs() + 3) + calldescr = op.getdescr() + assert isinstance(calldescr, CallDescr) + assert len(calldescr.arg_classes) == op.numargs() - 1 + for i in range(op.numargs()): - args[i + 1] = self.loc(op.getarg(i)) + args[i + 3] = self.loc(op.getarg(i)) + + size = calldescr.get_result_size() + sign = calldescr.is_result_signed() + if sign: + sign_loc = imm(1) + else: + sign_loc = imm(0) + args[1] = imm(size) + args[2] = sign_loc + + args[0] = self._call(op, args, force_store, save_all_regs) + return args + + def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls self.vfprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -565,11 +584,11 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(save_all_regs=save_all_regs) + self.before_call_called = True + resloc = None if op.result: resloc = self.after_call(op.result) - args[0] = resloc - self.before_call_called = True - return args + return resloc def prepare_op_call_malloc_gc(self, op, fcond): return self._prepare_call(op) @@ -1153,9 +1172,9 @@ def prepare_guard_call_assembler(self, op, guard_op, fcond): locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) - call_locs = self._prepare_call(op, save_all_regs=True) + resloc = self._call(op, locs + [tmploc], save_all_regs=True) self.possibly_free_vars(guard_op.getfailargs()) - return locs + [call_locs[0], tmploc] + return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -1,9 +1,10 @@ from rpython.rlib.objectmodel import instantiate from rpython.jit.backend.arm.assembler import AssemblerARM -from rpython.jit.backend.arm.locations import imm, ConstFloatLoc,\ - RegisterLocation, StackLocation, \ - VFPRegisterLocation, get_fp_offset -from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip +from rpython.jit.backend.arm.locations import imm, ConstFloatLoc +from rpython.jit.backend.arm.locations import RegisterLocation, StackLocation +from rpython.jit.backend.arm.locations import VFPRegisterLocation, get_fp_offset +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.registers import lr, ip, fp, vfp_ip, sp from rpython.jit.backend.arm.conditions import AL from rpython.jit.backend.arm.arch import WORD from rpython.jit.metainterp.history import FLOAT @@ -54,6 +55,12 @@ addr = int(value) # whatever return ConstFloatLoc(addr) +def raw_stack(i): + return RawSPStackLocation(i) + +def raw_stack_float(i): + return RawSPStackLocation(i, type=FLOAT) + class MockBuilder(object): def __init__(self): @@ -79,13 +86,13 @@ result = self.builder.instrs assert result == expected - -class TestRegallocMov(BaseMovTest): - def mov(self, a, b, expected=None): self.asm.regalloc_mov(a, b) self.validate(expected) + +class TestRegallocMov(BaseMovTest): + def test_mov_imm_to_reg(self): val = imm(123) reg = r(7) @@ -102,45 +109,37 @@ val = imm(100) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 100, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_stacklock(self): val = imm(65536) s = stack(7) expected = [ - mi('PUSH', [lr.value], cond=AL), mi('gen_load_int', lr.value, 65536, cond=AL), mi('STR_ri', lr.value, fp.value, imm=s.value, cond=AL), - mi('POP', [lr.value], cond=AL)] - + ] self.mov(val, s, expected) def test_mov_imm_to_big_stacklock(self): val = imm(100) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), - mi('gen_load_int', lr.value, 100, cond=AL), - mi('PUSH', [ip.value], cond=AL), + expected = [ mi('gen_load_int', lr.value, 100, cond=AL), mi('gen_load_int', ip.value, s.value, cond=AL), mi('STR_rr', lr.value, fp.value, ip.value, cond=AL), - mi('POP', [ip.value], cond=AL), - mi('POP', [lr.value], cond=AL)] + ] self.mov(val, s, expected) def test_mov_big_imm_to_big_stacklock(self): val = imm(65536) s = stack(8191) - expected = [mi('PUSH', [lr.value], cond=AL), From noreply at buildbot.pypy.org Tue May 28 15:46:53 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 15:46:53 +0200 (CEST) Subject: [pypy-commit] pypy kill-gen-store-back-in: simplify Message-ID: <20130528134653.6D1D41C021A@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: kill-gen-store-back-in Changeset: r64618:331b467d0c3d Date: 2013-05-28 15:46 +0200 http://bitbucket.org/pypy/pypy/changeset/331b467d0c3d/ Log: simplify diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py --- a/rpython/jit/backend/llgraph/runner.py +++ b/rpython/jit/backend/llgraph/runner.py @@ -258,9 +258,6 @@ def get_latest_descr(self, deadframe): return deadframe._latest_descr - def get_force_descr(self, deadframe): - xxx - def grab_exc_value(self, deadframe): if deadframe._last_exception is not None: result = deadframe._last_exception.args[1] diff --git a/rpython/jit/backend/model.py b/rpython/jit/backend/model.py --- a/rpython/jit/backend/model.py +++ b/rpython/jit/backend/model.py @@ -101,11 +101,6 @@ """Returns the Descr for the last operation executed by the frame.""" raise NotImplementedError - def get_force_descr(self, deadframe): - """Returns the Descr of last GUARD_NOT_FORCED - """ - raise NotImplementedError - def get_int_value(self, deadframe, index): """Returns the value for the index'th argument to the last executed operation (from 'fail_args' if it was a guard, diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -703,11 +703,9 @@ rstack._stack_criticalcode_start() try: deadframe = cpu.force(token) + # this should set descr to ResumeGuardForceDescr, if it + # was not that already faildescr = cpu.get_latest_descr(deadframe) - if not isinstance(faildescr, ResumeGuardForcedDescr): - assert faildescr.final_descr # we have to fish from - # guard_exc_descr instead - faildescr = cpu.get_force_descr(deadframe) assert isinstance(faildescr, ResumeGuardForcedDescr) faildescr.handle_async_forcing(deadframe) finally: From noreply at buildbot.pypy.org Tue May 28 16:01:11 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 16:01:11 +0200 (CEST) Subject: [pypy-commit] pypy default: fix broken merge Message-ID: <20130528140111.472071C0FF8@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64619:f5f6bc6f2837 Date: 2013-05-28 16:00 +0200 http://bitbucket.org/pypy/pypy/changeset/f5f6bc6f2837/ Log: fix broken merge diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,7 +1051,7 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) - def build_scalar(space, w_dtype, w_state): +def build_scalar(space, w_dtype, w_state): from rpython.rtyper.lltypesystem import rffi, lltype assert isinstance(w_dtype, interp_dtype.W_Dtype) From noreply at buildbot.pypy.org Tue May 28 16:03:43 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 16:03:43 +0200 (CEST) Subject: [pypy-commit] pypy default: fix test_whatsnew Message-ID: <20130528140343.75C601C0FF8@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64620:7240a74dd496 Date: 2013-05-28 16:03 +0200 http://bitbucket.org/pypy/pypy/changeset/7240a74dd496/ Log: fix test_whatsnew 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 @@ -34,3 +34,8 @@ .. branch: remove-iter-smm Remove multi-methods on iterators + +.. branch: emit-call-x86 +.. branch: emit-call-arm +.. branch: on-abort-resops + From noreply at buildbot.pypy.org Tue May 28 16:06:59 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 28 May 2013 16:06:59 +0200 (CEST) Subject: [pypy-commit] pypy default: Include a branch description. Message-ID: <20130528140659.29C9C1C13C1@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64621:33651f093624 Date: 2013-05-28 07:05 -0700 http://bitbucket.org/pypy/pypy/changeset/33651f093624/ Log: Include a branch description. 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 @@ -37,5 +37,6 @@ .. branch: emit-call-x86 .. branch: emit-call-arm + .. branch: on-abort-resops - +Added list of resops to the pypyjit on_abort hook. From noreply at buildbot.pypy.org Tue May 28 16:11:09 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 16:11:09 +0200 (CEST) Subject: [pypy-commit] pypy default: fix test_array Message-ID: <20130528141109.44E191C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64622:d7a42e01760e Date: 2013-05-28 16:07 +0200 http://bitbucket.org/pypy/pypy/changeset/d7a42e01760e/ Log: fix test_array diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -39,7 +39,7 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - guard_not_invalidated(descr=...) + guard_not_invalidated? i13 = int_lt(i7, i9) guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=) @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) From noreply at buildbot.pypy.org Tue May 28 16:11:10 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 16:11:10 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130528141110.687961C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64623:3413b6c72956 Date: 2013-05-28 16:10 +0200 http://bitbucket.org/pypy/pypy/changeset/3413b6c72956/ Log: merge 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 @@ -37,5 +37,6 @@ .. branch: emit-call-x86 .. branch: emit-call-arm + .. branch: on-abort-resops - +Added list of resops to the pypyjit on_abort hook. From noreply at buildbot.pypy.org Tue May 28 16:19:03 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 28 May 2013 16:19:03 +0200 (CEST) Subject: [pypy-commit] pypy default: Attempt to have error messages reach the buildbot output Message-ID: <20130528141903.14BA01C13C1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64624:e68b3de71eb7 Date: 2013-05-28 16:18 +0200 http://bitbucket.org/pypy/pypy/changeset/e68b3de71eb7/ Log: Attempt to have error messages reach the buildbot output diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -9,6 +9,7 @@ cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] - popen = subprocess.Popen(cmdline) + popen = subprocess.Popen(cmdline, stderr=subprocess.PIPE) + errmsg = popen.stderr.read() err = popen.wait() - assert err == 0 + assert err == 0, "err = %r, errmsg:\n%s" % (err, errmsg) From noreply at buildbot.pypy.org Tue May 28 17:41:06 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 17:41:06 +0200 (CEST) Subject: [pypy-commit] pypy default: ok, screw that, let's not be that magical and repeat that line a few times Message-ID: <20130528154106.47D5D1C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64625:72b57729949f Date: 2013-05-28 17:39 +0200 http://bitbucket.org/pypy/pypy/changeset/72b57729949f/ Log: ok, screw that, let's not be that magical and repeat that line a few times 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 @@ -59,7 +59,7 @@ arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') EQ, NE, LT, LE, GT, GE = range(6) -def compare_arrays(space, arr1, arr2, comp_op, comp_func): +def compare_arrays(space, arr1, arr2, comp_op): if (not isinstance(arr1, W_ArrayBase) or not isinstance(arr2, W_ArrayBase)): return space.w_NotImplemented @@ -69,22 +69,31 @@ return space.w_True lgt = min(arr1.len, arr2.len) for i in range(lgt): - arr_eq_driver.jit_merge_point(comp_func=comp_func) + arr_eq_driver.jit_merge_point(comp_func=comp_op) w_elem1 = arr1.w_getitem(space, i) w_elem2 = arr2.w_getitem(space, i) - res = space.is_true(comp_func(w_elem1, w_elem2)) if comp_op == EQ: + res = space.is_true(space.eq(w_elem1, w_elem2)) if not res: return space.w_False elif comp_op == NE: + res = space.is_true(space.ne(w_elem1, w_elem2)) if res: return space.w_True elif comp_op == LT or comp_op == GT: + if comp_op == LT: + res = space.is_true(space.lt(w_elem1, w_elem2)) + else: + res = space.is_true(space.gt(w_elem1, w_elem2)) if res: return space.w_True elif not space.is_true(space.eq(w_elem1, w_elem2)): return space.w_False else: + if comp_op == LE: + res = space.is_true(space.le(w_elem1, w_elem2)) + else: + res = space.is_true(space.ge(w_elem1, w_elem2)) if not res: return space.w_False elif not space.is_true(space.eq(w_elem1, w_elem2)): @@ -362,27 +371,27 @@ def descr_eq(self, space, w_arr2): "x.__eq__(y) <==> x==y" - return compare_arrays(space, self, w_arr2, EQ, space.eq) + return compare_arrays(space, self, w_arr2, EQ) def descr_ne(self, space, w_arr2): "x.__ne__(y) <==> x!=y" - return compare_arrays(space, self, w_arr2, NE, space.ne) + return compare_arrays(space, self, w_arr2, NE) def descr_lt(self, space, w_arr2): "x.__lt__(y) <==> x x<=y" - return compare_arrays(space, self, w_arr2, LE, space.le) + return compare_arrays(space, self, w_arr2, LE) def descr_gt(self, space, w_arr2): "x.__gt__(y) <==> x>y" - return compare_arrays(space, self, w_arr2, GT, space.gt) + return compare_arrays(space, self, w_arr2, GT) def descr_ge(self, space, w_arr2): "x.__ge__(y) <==> x>=y" - return compare_arrays(space, self, w_arr2, GE, space.ge) + return compare_arrays(space, self, w_arr2, GE) # Basic get/set/append/extend methods From noreply at buildbot.pypy.org Tue May 28 17:41:07 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 17:41:07 +0200 (CEST) Subject: [pypy-commit] pypy default: merge Message-ID: <20130528154107.217091C00BD@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64626:727e5e38dd75 Date: 2013-05-28 17:40 +0200 http://bitbucket.org/pypy/pypy/changeset/727e5e38dd75/ Log: merge diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -9,6 +9,7 @@ cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] - popen = subprocess.Popen(cmdline) + popen = subprocess.Popen(cmdline, stderr=subprocess.PIPE) + errmsg = popen.stderr.read() err = popen.wait() - assert err == 0 + assert err == 0, "err = %r, errmsg:\n%s" % (err, errmsg) From noreply at buildbot.pypy.org Tue May 28 18:27:18 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 28 May 2013 18:27:18 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: moved the returning-context identification from the copy of returnTopFromMethod to s_home, because simply overwriting returnTopFromMethod in MethodContextShadow is not sufficient for implementing Non-local-return. E.g. ReturnNil also needs that changed behavior. Message-ID: <20130528162718.8985E1C021A@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r418:0c6b78a77dca Date: 2013-05-28 18:24 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/0c6b78a77dca/ Log: moved the returning-context identification from the copy of returnTopFromMethod to s_home, because simply overwriting returnTopFromMethod in MethodContextShadow is not sufficient for implementing Non-local-return. E.g. ReturnNil also needs that changed behavior. diff --git a/spyvm/interpreter.py b/spyvm/interpreter.py --- a/spyvm/interpreter.py +++ b/spyvm/interpreter.py @@ -447,7 +447,6 @@ return self._return(interp.space.w_nil, interp, self.s_home().s_sender()) def returnTopFromMethod(self, interp, current_bytecode): - # overwritten in MethodContextShadow return self._return(self.pop(), interp, self.s_home().s_sender()) def returnTopFromBlock(self, interp, current_bytecode): diff --git a/spyvm/shadow.py b/spyvm/shadow.py --- a/spyvm/shadow.py +++ b/spyvm/shadow.py @@ -947,7 +947,18 @@ return self.w_self() def s_home(self): - return self + if self.is_closure_context(): + # this is a context for a blockClosure + w_outerContext = self.w_closure_or_nil.fetch(self.space, + constants.BLKCLSR_OUTER_CONTEXT) + assert isinstance(w_outerContext, model.W_PointersObject) + s_outerContext = w_outerContext.as_context_get_shadow(self.space) + # XXX check whether we can actually return from that context + if s_outerContext.pc() == -1: + raise error.BlockCannotReturnError() + return s_outerContext.s_home() + else: + return self def stackpointer_offset(self): return constants.MTHDCTX_TEMP_FRAME_START @@ -958,21 +969,6 @@ def myblocksize(self): return self.size() - self.tempsize() - def returnTopFromMethod(self, interp, current_bytecode): - if self.is_closure_context(): - # this is a context for a blockClosure - w_outerContext = self.w_closure_or_nil.fetch(self.space, - constants.BLKCLSR_OUTER_CONTEXT) - assert isinstance(w_outerContext, model.W_PointersObject) - s_outerContext = w_outerContext.as_context_get_shadow(self.space) - # XXX check whether we can actually return from that context - if s_outerContext.pc() == -1: - raise error.BlockCannotReturnError() - return_to_context = s_outerContext.s_home().s_sender() - else: - return_to_context = self.s_home().s_sender() - return self._return(self.pop(), interp, return_to_context) - def is_closure_context(self): return self.w_closure_or_nil is not self.space.w_nil diff --git a/spyvm/test/test_shadow.py b/spyvm/test/test_shadow.py --- a/spyvm/test/test_shadow.py +++ b/spyvm/test/test_shadow.py @@ -282,3 +282,14 @@ assert w_context.fetch(space, constants.CTXPART_PC_INDEX) is not space.w_nil s_context.mark_returned() assert w_context.fetch(space, constants.CTXPART_PC_INDEX) is space.w_nil + +def test_methodcontext_s_home(): + from spyvm.wrapper import BlockClosureWrapper + w_context = methodcontext() + s_context = w_context.as_methodcontext_get_shadow(space) + w_middle_context = methodcontext(w_sender=w_context) + s_middle_context = w_middle_context.as_methodcontext_get_shadow(space) + + w_closure = space.newClosure(w_context, 3, 0, []) + s_closure_context = BlockClosureWrapper(space, w_closure).asContextWithSender(w_middle_context, []) + assert s_closure_context.s_home() is s_context From noreply at buildbot.pypy.org Tue May 28 18:27:19 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Tue, 28 May 2013 18:27:19 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: Changed the priority of eventual spawned processes to 41, because 40 is the user-priority in newer Squeak images. Message-ID: <20130528162719.5A0A81C0FF8@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r419:7518cab03fce Date: 2013-05-28 18:27 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/7518cab03fce/ Log: Changed the priority of eventual spawned processes to 41, because 40 is the user-priority in newer Squeak images. This breaks the method- calling behavior for the mini-images but hopefully re-enables benchmarking. diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -36,7 +36,7 @@ # third variable is priority priority = space.unwrap_int(w_hpp.fetch(space, 2)) / 2 + 1 # Priorities below 10 are not allowed in newer versions of Squeak. - priority = max(11, priority) + priority = max(41, priority) w_benchmark_proc.store(space, 2, space.wrap_int(priority)) # make process eligible for scheduling From noreply at buildbot.pypy.org Tue May 28 19:08:12 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 28 May 2013 19:08:12 +0200 (CEST) Subject: [pypy-commit] stmgc default: Next fix for test_multi_thread Message-ID: <20130528170812.D0DE61C13C1@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r48:3d90299fb3ec Date: 2013-05-28 19:07 +0200 http://bitbucket.org/pypy/stmgc/changeset/3d90299fb3ec/ Log: Next fix for test_multi_thread diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -745,6 +745,25 @@ g2l_clear(&d->public_to_private); } +void UpdateProtectedChainHeads(struct tx_descriptor *d, revision_t cur_time, + revision_t localrev) +{ + revision_t new_revision = cur_time + 1; // make an odd number + assert(new_revision & 1); + + long i, size = d->protected_with_private_copy.size; + gcptr *items = d->protected_with_private_copy.items; + for (i = 0; i < size; i++) + { + gcptr R = items[i]; + if (R->h_tid & GCFLAG_STOLEN) /* ignore stolen objects */ + continue; + gcptr L = (gcptr)R->h_revision; + assert(L->h_revision == localrev); + L->h_revision = new_revision; + } +} + void CommitTransaction(void) { /* must save roots around this call */ revision_t cur_time; @@ -806,6 +825,7 @@ assert(d->local_revision_ref = &stm_local_revision); UpdateChainHeads(d, cur_time, localrev); + UpdateProtectedChainHeads(d, cur_time, localrev); stmgc_committed_transaction(d); d->num_commits++; From noreply at buildbot.pypy.org Tue May 28 19:08:11 2013 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 28 May 2013 19:08:11 +0200 (CEST) Subject: [pypy-commit] stmgc default: Progress Message-ID: <20130528170812.001EE1C0FF8@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r47:0dfc3a9bc0a7 Date: 2013-05-27 21:38 +0200 http://bitbucket.org/pypy/stmgc/changeset/0dfc3a9bc0a7/ Log: Progress diff --git a/c3/doc.txt b/c3/doc.txt --- a/c3/doc.txt +++ b/c3/doc.txt @@ -53,3 +53,6 @@ - how to handle immutable objects? they might only be initialized after they are moved; check + +- commit should not increase the global_cur_time if it only changed + protected objects diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -357,6 +357,8 @@ if (W->h_tid & GCFLAG_WRITE_BARRIER) stmgc_write_barrier(W); + fprintf(stderr, "write_barrier: %p -> %p\n", P, W); + return W; } @@ -382,7 +384,10 @@ v = ACCESS_ONCE(R->h_revision); if (!(v & 1)) // "is a pointer", i.e. { // "has a more recent revision" - /* ... unless it is a GCFLAG_STOLEN object */ + /* ... unless it's a protected-to-private link */ + if (((gcptr)v)->h_revision == stm_local_revision) + continue; + /* ... or unless it is a GCFLAG_STOLEN object */ if (R->h_tid & GCFLAG_STOLEN) { assert(is_young(R)); diff --git a/c3/gcpage.c b/c3/gcpage.c --- a/c3/gcpage.c +++ b/c3/gcpage.c @@ -273,7 +273,7 @@ if (obj->h_tid & GCFLAG_VISITED) return; /* already seen */ - if (obj->h_tid & GCFLAG_PUBLIC_TO_PRIVATE) { + if (obj->h_tid & (GCFLAG_PUBLIC_TO_PRIVATE | GCFLAG_STUB)) { if (obj->h_revision & 1) { // "is not a ptr", so no more recent version obj->h_tid &= ~GCFLAG_PUBLIC_TO_PRIVATE; // see also fix_outdated() } diff --git a/c3/test/support.py b/c3/test/support.py --- a/c3/test/support.py +++ b/c3/test/support.py @@ -136,6 +136,7 @@ void rawsetptr(gcptr obj, long index, gcptr newvalue) { + fprintf(stderr, "%p->[%ld] = %p\n", obj, index, newvalue); assert(stm_dbgmem_is_active(obj, 1)); assert(gettid(obj) > 421 + index); ((gcptr *)(obj + 1))[index] = newvalue; diff --git a/c3/test/test_random.py b/c3/test/test_random.py --- a/c3/test/test_random.py +++ b/c3/test/test_random.py @@ -220,7 +220,8 @@ is_too_recent = False except model.Deleted: is_too_recent = True - assert is_too_recent == (result < 0) + if result < 0: + assert is_too_recent if is_too_recent: continue # can't really check more in this case From noreply at buildbot.pypy.org Tue May 28 19:08:37 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 28 May 2013 19:08:37 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: merged default in Message-ID: <20130528170837.8C4951C0FF8@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64627:a03d4b2f9258 Date: 2013-05-28 10:06 -0700 http://bitbucket.org/pypy/pypy/changeset/a03d4b2f9258/ Log: merged default in 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 @@ -34,3 +34,9 @@ .. branch: remove-iter-smm Remove multi-methods on iterators + +.. branch: emit-call-x86 +.. branch: emit-call-arm + +.. branch: on-abort-resops +Added list of resops to the pypyjit on_abort hook. 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 @@ -59,7 +59,7 @@ arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') EQ, NE, LT, LE, GT, GE = range(6) -def compare_arrays(space, arr1, arr2, comp_op, comp_func): +def compare_arrays(space, arr1, arr2, comp_op): if (not isinstance(arr1, W_ArrayBase) or not isinstance(arr2, W_ArrayBase)): return space.w_NotImplemented @@ -69,22 +69,31 @@ return space.w_True lgt = min(arr1.len, arr2.len) for i in range(lgt): - arr_eq_driver.jit_merge_point(comp_func=comp_func) + arr_eq_driver.jit_merge_point(comp_func=comp_op) w_elem1 = arr1.w_getitem(space, i) w_elem2 = arr2.w_getitem(space, i) - res = space.is_true(comp_func(w_elem1, w_elem2)) if comp_op == EQ: + res = space.is_true(space.eq(w_elem1, w_elem2)) if not res: return space.w_False elif comp_op == NE: + res = space.is_true(space.ne(w_elem1, w_elem2)) if res: return space.w_True elif comp_op == LT or comp_op == GT: + if comp_op == LT: + res = space.is_true(space.lt(w_elem1, w_elem2)) + else: + res = space.is_true(space.gt(w_elem1, w_elem2)) if res: return space.w_True elif not space.is_true(space.eq(w_elem1, w_elem2)): return space.w_False else: + if comp_op == LE: + res = space.is_true(space.le(w_elem1, w_elem2)) + else: + res = space.is_true(space.ge(w_elem1, w_elem2)) if not res: return space.w_False elif not space.is_true(space.eq(w_elem1, w_elem2)): @@ -362,27 +371,27 @@ def descr_eq(self, space, w_arr2): "x.__eq__(y) <==> x==y" - return compare_arrays(space, self, w_arr2, EQ, space.eq) + return compare_arrays(space, self, w_arr2, EQ) def descr_ne(self, space, w_arr2): "x.__ne__(y) <==> x!=y" - return compare_arrays(space, self, w_arr2, NE, space.ne) + return compare_arrays(space, self, w_arr2, NE) def descr_lt(self, space, w_arr2): "x.__lt__(y) <==> x x<=y" - return compare_arrays(space, self, w_arr2, LE, space.le) + return compare_arrays(space, self, w_arr2, LE) def descr_gt(self, space, w_arr2): "x.__gt__(y) <==> x>y" - return compare_arrays(space, self, w_arr2, GT, space.gt) + return compare_arrays(space, self, w_arr2, GT) def descr_ge(self, space, w_arr2): "x.__ge__(y) <==> x>=y" - return compare_arrays(space, self, w_arr2, GE, space.ge) + return compare_arrays(space, self, w_arr2, GE) # Basic get/set/append/extend methods diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -13,6 +13,7 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', '_reconstruct' : 'interp_numarray._reconstruct', + 'scalar' : 'interp_numarray.build_scalar', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -11,6 +11,8 @@ from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from rpython.rlib.objectmodel import specialize +from pypy.interpreter.mixedmodule import MixedModule MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else () MIXIN_64 = (int_typedef,) if LONG_BIT == 64 else () @@ -33,7 +35,11 @@ def new(space, w_subtype, w_value): dtype = _get_dtype(space) return dtype.itemtype.coerce_subtype(space, w_subtype, w_value) - return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype) + + def descr_reduce(self, space): + return self.reduce(space) + + return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype), func_with_new_name(descr_reduce, "descr_reduce") class PrimitiveBox(object): @@ -48,6 +54,26 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.value) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, flavor="raw") + value[0] = self.value + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.value))) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret + class ComplexBox(object): _mixin_ = True @@ -64,6 +90,26 @@ def convert_imag_to(self, dtype): return dtype.box(self.imag) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, flavor="raw") + value[0] = self.real + value[1] = self.imag + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.real)) * 2) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret class W_GenericBox(W_Root): _attrs_ = () @@ -187,7 +233,7 @@ return convert_to_array(space, w_values) class W_BoolBox(W_GenericBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("bool") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("bool") class W_NumberBox(W_GenericBox): _attrs_ = () @@ -203,40 +249,40 @@ pass class W_Int8Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int8") class W_UInt8Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint8") class W_Int16Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int16") class W_UInt16Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint16") class W_Int32Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int32") class W_UInt32Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint32") class W_LongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("long") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("long") class W_ULongBox(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("ulong") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("ulong") class W_Int64Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int64") class W_LongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('longlong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('longlong') class W_UInt64Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint64") class W_ULongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('ulonglong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('ulonglong') class W_InexactBox(W_NumberBox): _attrs_ = () @@ -245,13 +291,13 @@ _attrs_ = () class W_Float16Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float16") class W_Float32Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float32") class W_Float64Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): _attrs_ = ['ofs', 'dtype', 'arr'] @@ -356,33 +402,33 @@ class W_Complex64Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex64") _COMPONENTS_BOX = W_Float32Box class W_Complex128Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex128") _COMPONENTS_BOX = W_Float64Box if ENABLED_LONG_DOUBLE and long_double_size == 12: class W_Float96Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float96") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float96") W_LongDoubleBox = W_Float96Box class W_Complex192Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex192") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex192") _COMPONENTS_BOX = W_Float96Box W_CLongDoubleBox = W_Complex192Box elif ENABLED_LONG_DOUBLE and long_double_size == 16: class W_Float128Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float128") W_LongDoubleBox = W_Float128Box class W_Complex256Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex256") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex256") _COMPONENTS_BOX = W_Float128Box W_CLongDoubleBox = W_Complex256Box @@ -458,6 +504,7 @@ __module__ = "numpypy", __new__ = interp2app(W_BoolBox.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_BoolBox.descr_reduce), ) W_NumberBox.typedef = TypeDef("number", W_GenericBox.typedef, @@ -480,42 +527,49 @@ __module__ = "numpypy", __new__ = interp2app(W_Int8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int8Box.descr_reduce), ) W_UInt8Box.typedef = TypeDef("uint8", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt8Box.descr_reduce), ) W_Int16Box.typedef = TypeDef("int16", W_SignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Int16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int16Box.descr_reduce), ) W_UInt16Box.typedef = TypeDef("uint16", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt16Box.descr_reduce), ) W_Int32Box.typedef = TypeDef("int32", (W_SignedIntegerBox.typedef,) + MIXIN_32, __module__ = "numpypy", __new__ = interp2app(W_Int32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int32Box.descr_reduce), ) W_UInt32Box.typedef = TypeDef("uint32", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt32Box.descr_reduce), ) W_Int64Box.typedef = TypeDef("int64", (W_SignedIntegerBox.typedef,) + MIXIN_64, __module__ = "numpypy", __new__ = interp2app(W_Int64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int64Box.descr_reduce), ) if LONG_BIT == 32: @@ -529,6 +583,7 @@ __module__ = "numpypy", __new__ = interp2app(W_UInt64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt64Box.descr_reduce), ) W_InexactBox.typedef = TypeDef("inexact", W_NumberBox.typedef, @@ -543,23 +598,27 @@ __module__ = "numpypy", __new__ = interp2app(W_Float16Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float16Box.descr_reduce), ) W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Float32Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float32Box.descr_reduce), ) W_Float64Box.typedef = TypeDef("float64", (W_FloatingBox.typedef, float_typedef), __module__ = "numpypy", __new__ = interp2app(W_Float64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float64Box.descr_reduce), ) if ENABLED_LONG_DOUBLE and long_double_size == 12: W_Float96Box.typedef = TypeDef("float96", (W_FloatingBox.typedef), __module__ = "numpypy", + __reduce__ = interp2app(W_Float96Box.descr_reduce), __new__ = interp2app(W_Float96Box.descr__new__.im_func), ) @@ -567,6 +626,7 @@ W_Complex192Box.typedef = TypeDef("complex192", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex192Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex192Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -576,11 +636,13 @@ __module__ = "numpypy", __new__ = interp2app(W_Float128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float128Box.descr_reduce), ) W_Complex256Box.typedef = TypeDef("complex256", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex256Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex256Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -618,6 +680,7 @@ W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex128Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -625,6 +688,7 @@ W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex64Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox .descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,6 +1051,17 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) +def build_scalar(space, w_dtype, w_state): + from rpython.rtyper.lltypesystem import rffi, lltype + + assert isinstance(w_dtype, interp_dtype.W_Dtype) + + state = rffi.str2charp(space.str_w(w_state)) + box = w_dtype.itemtype.box_raw_data(state) + lltype.free(state, flavor="raw") + return box + + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -0,0 +1,23 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +class AppTestScalar(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) + + def test_pickle(self): + from numpypy import dtype, int32, float64, complex128, zeros, sum + from numpypy.core.multiarray import scalar + from cPickle import loads, dumps + i = int32(1337) + f = float64(13.37) + c = complex128(13 + 37.j) + + assert i.__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) + assert f.__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) + assert c.__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) + + assert loads(dumps(i)) == i + assert loads(dumps(f)) == f + assert loads(dumps(c)) == c + + a = zeros(3) + assert loads(dumps(sum(a))) == sum(a) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -145,6 +145,11 @@ #XXX this is the place to display a warning return self.box(real) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box(array[0]) + @specialize.argtype(1) def unbox(self, box): assert isinstance(box, self.BoxType) @@ -1108,6 +1113,11 @@ rffi.cast(self.T, real), rffi.cast(self.T, imag)) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box_complex(array[0], array[1]) + def unbox(self, box): assert isinstance(box, self.BoxType) # do this in two stages since real, imag are read only diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -39,7 +39,7 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - guard_not_invalidated(descr=...) + guard_not_invalidated? i13 = int_lt(i7, i9) guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=) @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -9,6 +9,7 @@ cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] - popen = subprocess.Popen(cmdline) + popen = subprocess.Popen(cmdline, stderr=subprocess.PIPE) + errmsg = popen.stderr.read() err = popen.wait() - assert err == 0 + assert err == 0, "err = %r, errmsg:\n%s" % (err, errmsg) From noreply at buildbot.pypy.org Tue May 28 19:08:38 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 28 May 2013 19:08:38 +0200 (CEST) Subject: [pypy-commit] pypy logging-perf: Closed branch for merge. Message-ID: <20130528170838.72D3A1C0FF8@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: logging-perf Changeset: r64628:5c9de90cf312 Date: 2013-05-28 10:06 -0700 http://bitbucket.org/pypy/pypy/changeset/5c9de90cf312/ Log: Closed branch for merge. From noreply at buildbot.pypy.org Tue May 28 19:08:39 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 28 May 2013 19:08:39 +0200 (CEST) Subject: [pypy-commit] pypy default: Merged logging-perf branch. Message-ID: <20130528170839.8B0111C0FF8@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64629:21a05f62d97f Date: 2013-05-28 10:08 -0700 http://bitbucket.org/pypy/pypy/changeset/21a05f62d97f/ Log: Merged logging-perf branch. This speeds up logging in many (all?) cases by unrolling sys._getframe() which allows much of the logging code to be constant folded. Note that this can still have poor performance in the case that something is logged in a long loop, which causes an abort due to trace too long. logging traces have a TON of stuff that is constant folded in optimizeopt/ which means that their unoptimized trace is often an order of magnitude more than their optimized length. diff --git a/pypy/module/pypyjit/test_pypy_c/test_getframe.py b/pypy/module/pypyjit/test_pypy_c/test_getframe.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_getframe.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGetFrame(BaseTestPyPyC): + def test_getframe_one(self): + def main(n): + import sys + + i = 0 + while i < n: + assert sys._getframe(0).f_code.co_filename == __file__ + i += 1 + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i54 = int_lt(i47, i28) + guard_true(i54, descr=...) + guard_not_invalidated(descr=...) + i55 = int_add(i47, 1) + --TICK-- + jump(..., descr=...) + """) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -1,14 +1,18 @@ """ Implementation of interpreter-level 'sys' routines. """ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import unwrap_spec, WrappedDefault + from rpython.rlib import jit from rpython.rlib.runicode import MAXUNICODE +from pypy.interpreter import gateway +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec + + # ____________________________________________________________ + @unwrap_spec(depth=int) def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is @@ -21,6 +25,11 @@ if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) + return getframe(space, depth) + + + at jit.look_inside_iff(lambda space, depth: jit.isconstant(depth)) +def getframe(space, depth): ec = space.getexecutioncontext() f = ec.gettopframe_nohidden() while True: @@ -28,11 +37,11 @@ raise OperationError(space.w_ValueError, space.wrap("call stack is not deep enough")) if depth == 0: - break + f.mark_as_escaped() + return space.wrap(f) depth -= 1 f = ec.getnextframe_nohidden(f) - f.mark_as_escaped() - return space.wrap(f) + @unwrap_spec(new_limit="c_int") def setrecursionlimit(space, new_limit): diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -156,7 +156,7 @@ iteritems = self._fields.iteritems() if not we_are_translated(): #random order is fine, except for tests iteritems = list(iteritems) - iteritems.sort(key = lambda (x,y): x.sort_key()) + iteritems.sort(key=lambda (x, y): x.sort_key()) for ofs, value in iteritems: if value.is_null(): continue diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1158,6 +1158,7 @@ obj = box.getref_base() vref = vrefinfo.virtual_ref_during_tracing(obj) resbox = history.BoxPtr(vref) + self.metainterp.heapcache.new(resbox) cindex = history.ConstInt(len(metainterp.virtualref_boxes) // 2) metainterp.history.record(rop.VIRTUAL_REF, [box, cindex], resbox) # Note: we allocate a JIT_VIRTUAL_REF here From noreply at buildbot.pypy.org Tue May 28 19:31:56 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Tue, 28 May 2013 19:31:56 +0200 (CEST) Subject: [pypy-commit] pypy default: mark this function as elidable Message-ID: <20130528173156.788BB1C00BD@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64630:7bac0a805c70 Date: 2013-05-28 10:30 -0700 http://bitbucket.org/pypy/pypy/changeset/7bac0a805c70/ Log: mark this function as elidable diff --git a/pypy/objspace/std/stringtype.py b/pypy/objspace/std/stringtype.py --- a/pypy/objspace/std/stringtype.py +++ b/pypy/objspace/std/stringtype.py @@ -1,13 +1,14 @@ +from sys import maxint + +from rpython.rlib import jit +from rpython.rlib.objectmodel import specialize + from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.register_all import register_all -from sys import maxint -from rpython.rlib.objectmodel import specialize -from rpython.rlib.jit import we_are_jitted - def wrapstr(space, s): from pypy.objspace.std.stringobject import W_StringObject if space.config.objspace.std.sharesmallstr: @@ -27,7 +28,7 @@ def wrapchar(space, c): from pypy.objspace.std.stringobject import W_StringObject - if space.config.objspace.std.withprebuiltchar and not we_are_jitted(): + if space.config.objspace.std.withprebuiltchar and not jit.we_are_jitted(): return W_StringObject.PREBUILT[ord(c)] else: return W_StringObject(c) @@ -293,11 +294,13 @@ str_typedef.registermethods(globals()) + # ____________________________________________________________ # Helpers for several string implementations @specialize.argtype(0) + at jit.elidable def stringendswith(u_self, suffix, start, end): begin = end - len(suffix) if begin < start: @@ -308,6 +311,7 @@ return True @specialize.argtype(0) + at jit.elidable def stringstartswith(u_self, prefix, start, end): stop = start + len(prefix) if stop > end: From noreply at buildbot.pypy.org Tue May 28 21:36:57 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 21:36:57 +0200 (CEST) Subject: [pypy-commit] pypy py3k: reapply 5911ba2ee308 from default: Message-ID: <20130528193657.675701C2FC0@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64632:d0b2e22a1edf Date: 2013-05-28 12:35 -0700 http://bitbucket.org/pypy/pypy/changeset/d0b2e22a1edf/ Log: reapply 5911ba2ee308 from default: Backported 5629bf4c6bba from CPython. diff --git a/lib-python/3/logging/__init__.py b/lib-python/3/logging/__init__.py --- a/lib-python/3/logging/__init__.py +++ b/lib-python/3/logging/__init__.py @@ -129,20 +129,22 @@ DEBUG = 10 NOTSET = 0 -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO : 'INFO', - DEBUG : 'DEBUG', - NOTSET : 'NOTSET', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARNING, - 'WARNING' : WARNING, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'NOTSET' : NOTSET, +_levelToName = { + CRITICAL: 'CRITICAL', + ERROR: 'ERROR', + WARNING: 'WARNING', + INFO: 'INFO', + DEBUG: 'DEBUG', + NOTSET: 'NOTSET', +} +_nameToLevel = { + 'CRITICAL': CRITICAL, + 'ERROR': ERROR, + 'WARN': WARNING, + 'WARNING': WARNING, + 'INFO': INFO, + 'DEBUG': DEBUG, + 'NOTSET': NOTSET, } def getLevelName(level): @@ -159,7 +161,7 @@ Otherwise, the string "Level %s" % level is returned. """ - return _levelNames.get(level, ("Level %s" % level)) + return _levelToName.get(level, ("Level %s" % level)) def addLevelName(level, levelName): """ @@ -169,8 +171,8 @@ """ _acquireLock() try: #unlikely to cause an exception, but you never know... - _levelNames[level] = levelName - _levelNames[levelName] = level + _levelToName[level] = levelName + _nameToLevel[levelName] = level finally: _releaseLock() @@ -178,9 +180,9 @@ if isinstance(level, int): rv = level elif str(level) == level: - if level not in _levelNames: + if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) - rv = _levelNames[level] + rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv diff --git a/lib-python/3/logging/config.py b/lib-python/3/logging/config.py --- a/lib-python/3/logging/config.py +++ b/lib-python/3/logging/config.py @@ -144,7 +144,7 @@ h = klass(*args) if "level" in section: level = section["level"] - h.setLevel(logging._levelNames[level]) + h.setLevel(level) if len(fmt): h.setFormatter(formatters[fmt]) if issubclass(klass, logging.handlers.MemoryHandler): @@ -191,7 +191,7 @@ log = root if "level" in section: level = section["level"] - log.setLevel(logging._levelNames[level]) + log.setLevel(level) for h in root.handlers[:]: root.removeHandler(h) hlist = section["handlers"] @@ -237,7 +237,7 @@ existing.remove(qn) if "level" in section: level = section["level"] - logger.setLevel(logging._levelNames[level]) + logger.setLevel(level) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate diff --git a/lib-python/3/test/test_logging.py b/lib-python/3/test/test_logging.py --- a/lib-python/3/test/test_logging.py +++ b/lib-python/3/test/test_logging.py @@ -69,7 +69,8 @@ self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] self.saved_loggers = saved_loggers = logger_dict.copy() - self.saved_level_names = logging._levelNames.copy() + self.saved_name_to_level = logging._nameToLevel.copy() + self.saved_level_to_name = logging._levelToName.copy() self.logger_states = logger_states = {} for name in saved_loggers: logger_states[name] = getattr(saved_loggers[name], @@ -113,8 +114,10 @@ self.root_logger.setLevel(self.original_logging_level) logging._acquireLock() try: - logging._levelNames.clear() - logging._levelNames.update(self.saved_level_names) + logging._levelToName.clear() + logging._levelToName.update(self.saved_level_to_name) + logging._nameToLevel.clear() + logging._nameToLevel.update(self.saved_name_to_level) logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list From noreply at buildbot.pypy.org Tue May 28 21:36:56 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 21:36:56 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130528193656.748191C13C1@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64631:eea100ee2698 Date: 2013-05-28 12:31 -0700 http://bitbucket.org/pypy/pypy/changeset/eea100ee2698/ Log: merge default diff too long, truncating to 2000 out of 2799 lines diff --git a/lib-python/2.7/logging/__init__.py b/lib-python/2.7/logging/__init__.py --- a/lib-python/2.7/logging/__init__.py +++ b/lib-python/2.7/logging/__init__.py @@ -134,20 +134,22 @@ DEBUG = 10 NOTSET = 0 -_levelNames = { - CRITICAL : 'CRITICAL', - ERROR : 'ERROR', - WARNING : 'WARNING', - INFO : 'INFO', - DEBUG : 'DEBUG', - NOTSET : 'NOTSET', - 'CRITICAL' : CRITICAL, - 'ERROR' : ERROR, - 'WARN' : WARNING, - 'WARNING' : WARNING, - 'INFO' : INFO, - 'DEBUG' : DEBUG, - 'NOTSET' : NOTSET, +_levelToName = { + CRITICAL: 'CRITICAL', + ERROR: 'ERROR', + WARNING: 'WARNING', + INFO: 'INFO', + DEBUG: 'DEBUG', + NOTSET: 'NOTSET', +} +_nameToLevel = { + 'CRITICAL': CRITICAL, + 'ERROR': ERROR, + 'WARN': WARNING, + 'WARNING': WARNING, + 'INFO': INFO, + 'DEBUG': DEBUG, + 'NOTSET': NOTSET, } def getLevelName(level): @@ -164,7 +166,7 @@ Otherwise, the string "Level %s" % level is returned. """ - return _levelNames.get(level, ("Level %s" % level)) + return _levelToName.get(level, ("Level %s" % level)) def addLevelName(level, levelName): """ @@ -174,8 +176,8 @@ """ _acquireLock() try: #unlikely to cause an exception, but you never know... - _levelNames[level] = levelName - _levelNames[levelName] = level + _levelToName[level] = levelName + _nameToLevel[levelName] = level finally: _releaseLock() @@ -183,9 +185,9 @@ if isinstance(level, int): rv = level elif str(level) == level: - if level not in _levelNames: + if level not in _nameToLevel: raise ValueError("Unknown level: %r" % level) - rv = _levelNames[level] + rv = _nameToLevel[level] else: raise TypeError("Level not an integer or a valid string: %r" % level) return rv @@ -277,7 +279,7 @@ self.lineno = lineno self.funcName = func self.created = ct - self.msecs = (ct - long(ct)) * 1000 + self.msecs = (ct - int(ct)) * 1000 self.relativeCreated = (self.created - _startTime) * 1000 if logThreads and thread: self.thread = thread.get_ident() diff --git a/lib-python/2.7/logging/config.py b/lib-python/2.7/logging/config.py --- a/lib-python/2.7/logging/config.py +++ b/lib-python/2.7/logging/config.py @@ -156,7 +156,7 @@ h = klass(*args) if "level" in opts: level = cp.get(sectname, "level") - h.setLevel(logging._levelNames[level]) + h.setLevel(level) if len(fmt): h.setFormatter(formatters[fmt]) if issubclass(klass, logging.handlers.MemoryHandler): @@ -187,7 +187,7 @@ opts = cp.options(sectname) if "level" in opts: level = cp.get(sectname, "level") - log.setLevel(logging._levelNames[level]) + log.setLevel(level) for h in root.handlers[:]: root.removeHandler(h) hlist = cp.get(sectname, "handlers") @@ -237,7 +237,7 @@ existing.remove(qn) if "level" in opts: level = cp.get(sectname, "level") - logger.setLevel(logging._levelNames[level]) + logger.setLevel(level) for h in logger.handlers[:]: logger.removeHandler(h) logger.propagate = propagate diff --git a/lib-python/2.7/test/test_logging.py b/lib-python/2.7/test/test_logging.py --- a/lib-python/2.7/test/test_logging.py +++ b/lib-python/2.7/test/test_logging.py @@ -65,7 +65,8 @@ self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] self.saved_loggers = logger_dict.copy() - self.saved_level_names = logging._levelNames.copy() + self.saved_name_to_level = logging._nameToLevel.copy() + self.saved_level_to_name = logging._levelToName.copy() finally: logging._releaseLock() @@ -97,8 +98,10 @@ self.root_logger.setLevel(self.original_logging_level) logging._acquireLock() try: - logging._levelNames.clear() - logging._levelNames.update(self.saved_level_names) + logging._levelToName.clear() + logging._levelToName.update(self.saved_level_to_name) + logging._nameToLevel.clear() + logging._nameToLevel.update(self.saved_name_to_level) logging._handlers.clear() logging._handlers.update(self.saved_handlers) logging._handlerList[:] = self.saved_handler_list 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 @@ -34,3 +34,9 @@ .. branch: remove-iter-smm Remove multi-methods on iterators + +.. branch: emit-call-x86 +.. branch: emit-call-arm + +.. branch: on-abort-resops +Added list of resops to the pypyjit on_abort hook. 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 @@ -62,7 +62,7 @@ arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') EQ, NE, LT, LE, GT, GE = range(6) -def compare_arrays(space, arr1, arr2, comp_op, comp_func): +def compare_arrays(space, arr1, arr2, comp_op): if (not isinstance(arr1, W_ArrayBase) or not isinstance(arr2, W_ArrayBase)): return space.w_NotImplemented @@ -72,22 +72,31 @@ return space.w_True lgt = min(arr1.len, arr2.len) for i in range(lgt): - arr_eq_driver.jit_merge_point(comp_func=comp_func) + arr_eq_driver.jit_merge_point(comp_func=comp_op) w_elem1 = arr1.w_getitem(space, i) w_elem2 = arr2.w_getitem(space, i) - res = space.is_true(comp_func(w_elem1, w_elem2)) if comp_op == EQ: + res = space.is_true(space.eq(w_elem1, w_elem2)) if not res: return space.w_False elif comp_op == NE: + res = space.is_true(space.ne(w_elem1, w_elem2)) if res: return space.w_True elif comp_op == LT or comp_op == GT: + if comp_op == LT: + res = space.is_true(space.lt(w_elem1, w_elem2)) + else: + res = space.is_true(space.gt(w_elem1, w_elem2)) if res: return space.w_True elif not space.is_true(space.eq(w_elem1, w_elem2)): return space.w_False else: + if comp_op == LE: + res = space.is_true(space.le(w_elem1, w_elem2)) + else: + res = space.is_true(space.ge(w_elem1, w_elem2)) if not res: return space.w_False elif not space.is_true(space.eq(w_elem1, w_elem2)): @@ -414,27 +423,27 @@ def descr_eq(self, space, w_arr2): "x.__eq__(y) <==> x==y" - return compare_arrays(space, self, w_arr2, EQ, space.eq) + return compare_arrays(space, self, w_arr2, EQ) def descr_ne(self, space, w_arr2): "x.__ne__(y) <==> x!=y" - return compare_arrays(space, self, w_arr2, NE, space.ne) + return compare_arrays(space, self, w_arr2, NE) def descr_lt(self, space, w_arr2): "x.__lt__(y) <==> x x<=y" - return compare_arrays(space, self, w_arr2, LE, space.le) + return compare_arrays(space, self, w_arr2, LE) def descr_gt(self, space, w_arr2): "x.__gt__(y) <==> x>y" - return compare_arrays(space, self, w_arr2, GT, space.gt) + return compare_arrays(space, self, w_arr2, GT) def descr_ge(self, space, w_arr2): "x.__ge__(y) <==> x>=y" - return compare_arrays(space, self, w_arr2, GE, space.ge) + return compare_arrays(space, self, w_arr2, GE) # Basic get/set/append/extend methods diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -13,6 +13,7 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', '_reconstruct' : 'interp_numarray._reconstruct', + 'scalar' : 'interp_numarray.build_scalar', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -11,6 +11,8 @@ from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from rpython.rlib.objectmodel import specialize +from pypy.interpreter.mixedmodule import MixedModule MIXIN_32 = (long_typedef,) if LONG_BIT == 32 else () MIXIN_64 = (long_typedef,) if LONG_BIT == 64 else () @@ -33,7 +35,11 @@ def new(space, w_subtype, w_value): dtype = _get_dtype(space) return dtype.itemtype.coerce_subtype(space, w_subtype, w_value) - return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype) + + def descr_reduce(self, space): + return self.reduce(space) + + return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype), func_with_new_name(descr_reduce, "descr_reduce") class PrimitiveBox(object): @@ -48,6 +54,26 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.value) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, flavor="raw") + value[0] = self.value + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.value))) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret + class ComplexBox(object): _mixin_ = True @@ -64,6 +90,26 @@ def convert_imag_to(self, dtype): return dtype.box(self.imag) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, flavor="raw") + value[0] = self.real + value[1] = self.imag + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.real)) * 2) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret class W_GenericBox(W_Root): _attrs_ = () @@ -187,7 +233,7 @@ return convert_to_array(space, w_values) class W_BoolBox(W_GenericBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("bool") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("bool") class W_NumberBox(W_GenericBox): _attrs_ = () @@ -203,40 +249,40 @@ pass class W_Int8Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int8") class W_UInt8Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint8") class W_Int16Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int16") class W_UInt16Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint16") class W_Int32Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int32") class W_UInt32Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint32") class W_LongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("long") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("long") class W_ULongBox(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("ulong") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("ulong") class W_Int64Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int64") class W_LongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('longlong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('longlong') class W_UInt64Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint64") class W_ULongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('ulonglong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('ulonglong') class W_InexactBox(W_NumberBox): _attrs_ = () @@ -245,15 +291,17 @@ _attrs_ = () class W_Float16Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float16") class W_Float32Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float32") class W_Float64Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): + _attrs_ = ['ofs', 'dtype', 'arr'] + _immutable_fields_ = ['ofs'] def __init__(self, arr, ofs, dtype): self.arr = arr # we have to keep array alive self.ofs = ofs @@ -354,33 +402,33 @@ class W_Complex64Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex64") _COMPONENTS_BOX = W_Float32Box class W_Complex128Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex128") _COMPONENTS_BOX = W_Float64Box if ENABLED_LONG_DOUBLE and long_double_size == 12: class W_Float96Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float96") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float96") W_LongDoubleBox = W_Float96Box class W_Complex192Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex192") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex192") _COMPONENTS_BOX = W_Float96Box W_CLongDoubleBox = W_Complex192Box elif ENABLED_LONG_DOUBLE and long_double_size == 16: class W_Float128Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float128") W_LongDoubleBox = W_Float128Box class W_Complex256Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex256") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex256") _COMPONENTS_BOX = W_Float128Box W_CLongDoubleBox = W_Complex256Box @@ -456,6 +504,7 @@ __module__ = "numpypy", __new__ = interp2app(W_BoolBox.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_BoolBox.descr_reduce), ) W_NumberBox.typedef = TypeDef("number", W_GenericBox.typedef, @@ -478,42 +527,49 @@ __module__ = "numpypy", __new__ = interp2app(W_Int8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int8Box.descr_reduce), ) W_UInt8Box.typedef = TypeDef("uint8", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt8Box.descr_reduce), ) W_Int16Box.typedef = TypeDef("int16", W_SignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Int16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int16Box.descr_reduce), ) W_UInt16Box.typedef = TypeDef("uint16", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt16Box.descr_reduce), ) W_Int32Box.typedef = TypeDef("int32", (W_SignedIntegerBox.typedef,) + MIXIN_32, __module__ = "numpypy", __new__ = interp2app(W_Int32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int32Box.descr_reduce), ) W_UInt32Box.typedef = TypeDef("uint32", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt32Box.descr_reduce), ) W_Int64Box.typedef = TypeDef("int64", (W_SignedIntegerBox.typedef,) + MIXIN_64, __module__ = "numpypy", __new__ = interp2app(W_Int64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int64Box.descr_reduce), ) if LONG_BIT == 32: @@ -527,6 +583,7 @@ __module__ = "numpypy", __new__ = interp2app(W_UInt64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt64Box.descr_reduce), ) W_InexactBox.typedef = TypeDef("inexact", W_NumberBox.typedef, @@ -541,23 +598,27 @@ __module__ = "numpypy", __new__ = interp2app(W_Float16Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float16Box.descr_reduce), ) W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Float32Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float32Box.descr_reduce), ) W_Float64Box.typedef = TypeDef("float64", (W_FloatingBox.typedef, float_typedef), __module__ = "numpypy", __new__ = interp2app(W_Float64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float64Box.descr_reduce), ) if ENABLED_LONG_DOUBLE and long_double_size == 12: W_Float96Box.typedef = TypeDef("float96", (W_FloatingBox.typedef), __module__ = "numpypy", + __reduce__ = interp2app(W_Float96Box.descr_reduce), __new__ = interp2app(W_Float96Box.descr__new__.im_func), ) @@ -565,6 +626,7 @@ W_Complex192Box.typedef = TypeDef("complex192", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex192Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex192Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -574,11 +636,13 @@ __module__ = "numpypy", __new__ = interp2app(W_Float128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float128Box.descr_reduce), ) W_Complex256Box.typedef = TypeDef("complex256", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex256Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex256Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -616,6 +680,7 @@ W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex128Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -623,6 +688,7 @@ W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex64Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox .descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,6 +1051,17 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) +def build_scalar(space, w_dtype, w_state): + from rpython.rtyper.lltypesystem import rffi, lltype + + assert isinstance(w_dtype, interp_dtype.W_Dtype) + + state = rffi.str2charp(space.str_w(w_state)) + box = w_dtype.itemtype.box_raw_data(state) + lltype.free(state, flavor="raw") + return box + + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -785,7 +785,7 @@ def test_create_subarrays(self): from numpypy import dtype - d = dtype([("x", "float", (2,)), ("y", "int", (2,))]) + d = dtype([("x", "float", (2,)), ("y", "int64", (2,))]) assert d.itemsize == 32 assert d.name == "void256" keys = d.fields.keys() diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -2716,7 +2716,7 @@ a[0]["x"][0] = 200 assert a[0]["x"][0] == 200 - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") @@ -2736,7 +2736,7 @@ def test_multidim_subarray(self): from numpypy import dtype, array - d = dtype([("x", "int", (2, 3))]) + d = dtype([("x", "int64", (2, 3))]) a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d) assert a[0]["x"].dtype == dtype("int64") diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -0,0 +1,23 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +class AppTestScalar(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) + + def test_pickle(self): + from numpypy import dtype, int32, float64, complex128, zeros, sum + from numpypy.core.multiarray import scalar + from cPickle import loads, dumps + i = int32(1337) + f = float64(13.37) + c = complex128(13 + 37.j) + + assert i.__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) + assert f.__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) + assert c.__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) + + assert loads(dumps(i)) == i + assert loads(dumps(f)) == f + assert loads(dumps(c)) == c + + a = zeros(3) + assert loads(dumps(sum(a))) == sum(a) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -145,6 +145,11 @@ #XXX this is the place to display a warning return self.box(real) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box(array[0]) + @specialize.argtype(1) def unbox(self, box): assert isinstance(box, self.BoxType) @@ -1108,6 +1113,11 @@ rffi.cast(self.T, real), rffi.cast(self.T, imag)) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box_complex(array[0], array[1]) + def unbox(self, box): assert isinstance(box, self.BoxType) # do this in two stages since real, imag are read only @@ -1705,8 +1715,10 @@ def _coerce(self, space, arr, ofs, dtype, w_items, shape): # TODO: Make sure the shape and the array match + from interp_dtype import W_Dtype items_w = space.fixedview(w_items) subdtype = dtype.subdtype + assert isinstance(subdtype, W_Dtype) itemtype = subdtype.itemtype if len(shape) <= 1: for i in range(len(items_w)): diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -39,7 +39,7 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - guard_not_invalidated(descr=...) + guard_not_invalidated? i13 = int_lt(i7, i9) guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=) @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -9,6 +9,7 @@ cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] - popen = subprocess.Popen(cmdline) + popen = subprocess.Popen(cmdline, stderr=subprocess.PIPE) + errmsg = popen.stderr.read() err = popen.wait() - assert err == 0 + assert err == 0, "err = %r, errmsg:\n%s" % (err, errmsg) diff --git a/pypy/module/pypyjit/test_pypy_c/test_getframe.py b/pypy/module/pypyjit/test_pypy_c/test_getframe.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_getframe.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGetFrame(BaseTestPyPyC): + def test_getframe_one(self): + def main(n): + import sys + + i = 0 + while i < n: + assert sys._getframe(0).f_code.co_filename == __file__ + i += 1 + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i54 = int_lt(i47, i28) + guard_true(i54, descr=...) + guard_not_invalidated(descr=...) + i55 = int_add(i47, 1) + --TICK-- + jump(..., descr=...) + """) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -1,14 +1,18 @@ """ Implementation of interpreter-level 'sys' routines. """ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import unwrap_spec, WrappedDefault + from rpython.rlib import jit from rpython.rlib.runicode import MAXUNICODE +from pypy.interpreter import gateway +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec + + # ____________________________________________________________ + @unwrap_spec(depth=int) def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is @@ -21,6 +25,11 @@ if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) + return getframe(space, depth) + + + at jit.look_inside_iff(lambda space, depth: jit.isconstant(depth)) +def getframe(space, depth): ec = space.getexecutioncontext() f = ec.gettopframe_nohidden() while True: @@ -28,11 +37,11 @@ raise OperationError(space.w_ValueError, space.wrap("call stack is not deep enough")) if depth == 0: - break + f.mark_as_escaped() + return space.wrap(f) depth -= 1 f = ec.getnextframe_nohidden(f) - f.mark_as_escaped() - return space.wrap(f) + @unwrap_spec(new_limit="c_int") def setrecursionlimit(space, new_limit): diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -417,7 +417,7 @@ # No more items to compare -- compare sizes return space.newbool(op(self.length(), w_list2.length())) - return func_with_new_name(compare_unwrappeditems, name + '__List_List') + return func_with_new_name(compare_unwrappeditems, 'descr_' + name) descr_lt = _make_list_comparison('lt') descr_le = _make_list_comparison('le') diff --git a/pypy/objspace/std/stringtype.py b/pypy/objspace/std/stringtype.py --- a/pypy/objspace/std/stringtype.py +++ b/pypy/objspace/std/stringtype.py @@ -1,12 +1,13 @@ +from sys import maxint + +from rpython.rlib import jit +from rpython.rlib.objectmodel import newlist_hint, resizelist_hint, specialize + from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.error import OperationError, operationerrfmt from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.register_all import register_all -from sys import maxint -from rpython.rlib.objectmodel import newlist_hint, resizelist_hint, specialize -from rpython.rlib.jit import we_are_jitted - def wrapstr(space, s): from pypy.objspace.std.stringobject import W_StringObject if space.config.objspace.std.sharesmallstr: @@ -26,7 +27,7 @@ def wrapchar(space, c): from pypy.objspace.std.stringobject import W_StringObject - if space.config.objspace.std.withprebuiltchar and not we_are_jitted(): + if space.config.objspace.std.withprebuiltchar and not jit.we_are_jitted(): return W_StringObject.PREBUILT[ord(c)] else: return W_StringObject(c) @@ -394,11 +395,13 @@ str_typedef.registermethods(globals()) + # ____________________________________________________________ # Helpers for several string implementations @specialize.argtype(0) + at jit.elidable def stringendswith(u_self, suffix, start, end): begin = end - len(suffix) if begin < start: @@ -409,6 +412,7 @@ return True @specialize.argtype(0) + at jit.elidable def stringstartswith(u_self, prefix, start, end): stop = start + len(prefix) if stop > end: diff --git a/rpython/jit/backend/arm/assembler.py b/rpython/jit/backend/arm/assembler.py --- a/rpython/jit/backend/arm/assembler.py +++ b/rpython/jit/backend/arm/assembler.py @@ -19,7 +19,7 @@ from rpython.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper from rpython.jit.backend.model import CompiledLoopToken from rpython.jit.codewriter.effectinfo import EffectInfo -from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT +from rpython.jit.metainterp.history import AbstractFailDescr, FLOAT, INT, VOID from rpython.jit.metainterp.resoperation import rop from rpython.rlib.debug import debug_print, debug_start, debug_stop from rpython.rlib.jit import AsmInfo @@ -27,6 +27,7 @@ from rpython.rlib.rarithmetic import r_uint from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_gcref from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.jit.backend.arm import callbuilder class AssemblerARM(ResOpAssembler): @@ -934,23 +935,6 @@ asm_math_operations[oopspecindex](self, op, arglocs, regalloc, fcond) return fcond - def _ensure_result_bit_extension(self, resloc, size, signed): - if size == 4: - return - if size == 1: - if not signed: # unsigned char - self.mc.AND_ri(resloc.value, resloc.value, 0xFF) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 24) - self.mc.ASR_ri(resloc.value, resloc.value, 24) - elif size == 2: - if not signed: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.LSR_ri(resloc.value, resloc.value, 16) - else: - self.mc.LSL_ri(resloc.value, resloc.value, 16) - self.mc.ASR_ri(resloc.value, resloc.value, 16) - def patch_trace(self, faildescr, looptoken, bridge_addr, regalloc): b = InstrBuilder(self.cpu.cpuinfo.arch_version) patch_addr = faildescr._arm_failure_recovery_block @@ -1012,20 +996,32 @@ mc.gen_load_int(helper.value, ofs, cond=cond) mc.STR_rr(source.value, base.value, helper.value, cond=cond) + def get_tmp_reg(self, forbidden_regs=None): + if forbidden_regs is None: + return r.ip, False + for x in [r.ip, r.lr]: + if x not in forbidden_regs: + return x, False + # pick some reg, that we need to save + for x in r.all_regs: + if x not in forbidden_regs: + return x, True + assert 0 + def _mov_imm_to_loc(self, prev_loc, loc, cond=c.AL): - if not loc.is_reg() and not (loc.is_stack() and loc.type != FLOAT): + if loc.type == FLOAT: raise AssertionError("invalid target for move from imm value") if loc.is_reg(): new_loc = loc - elif loc.is_stack(): - self.mc.PUSH([r.lr.value], cond=cond) + elif loc.is_stack() or loc.is_raw_sp(): new_loc = r.lr else: raise AssertionError("invalid target for move from imm value") self.mc.gen_load_int(new_loc.value, prev_loc.value, cond=cond) if loc.is_stack(): self.regalloc_mov(new_loc, loc) - self.mc.POP([r.lr.value], cond=cond) + elif loc.is_raw_sp(): + self.store_reg(self.mc, new_loc, r.sp, loc.value, cond=cond, helper=r.ip) def _mov_reg_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_imm(): @@ -1034,60 +1030,77 @@ self.mc.MOV_rr(loc.value, prev_loc.value, cond=cond) elif loc.is_stack() and loc.type != FLOAT: # spill a core register - if prev_loc is r.ip: - temp = r.lr - else: - temp = r.ip + temp, save = self.get_tmp_reg([prev_loc, loc]) offset = loc.value is_imm = check_imm_arg(offset, size=0xFFF) - if not is_imm: + if not is_imm and save: self.mc.PUSH([temp.value], cond=cond) self.store_reg(self.mc, prev_loc, r.fp, offset, helper=temp, cond=cond) - if not is_imm: + if not is_imm and save: self.mc.POP([temp.value], cond=cond) + elif loc.is_raw_sp() and loc.type != FLOAT: + temp, save = self.get_tmp_reg([prev_loc]) + assert not save + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond, helper=temp) else: assert 0, 'unsupported case' def _mov_stack_to_loc(self, prev_loc, loc, cond=c.AL): - # disabled for now, has side effects in combination with remap_frame_layout when called from a jump - helper = None # self._regalloc.get_free_reg() + helper = None + offset = prev_loc.value + tmp = None if loc.is_reg(): assert prev_loc.type != FLOAT, 'trying to load from an \ incompatible location into a core register' - assert loc is not r.lr, 'lr is not supported as a target \ - when moving from the stack' # unspill a core register - offset = prev_loc.value is_imm = check_imm_arg(offset, size=0xFFF) - helper = r.lr if helper is None else helper - save_helper = not is_imm and helper is r.lr + helper, save = self.get_tmp_reg([loc]) + save_helper = not is_imm and save elif loc.is_vfp_reg(): assert prev_loc.type == FLOAT, 'trying to load from an \ incompatible location into a float register' # load spilled value into vfp reg - offset = prev_loc.value is_imm = check_imm_arg(offset) - helper = r.ip if helper is None else helper - save_helper = not is_imm and helper is r.ip + helper, save = self.get_tmp_reg() + save_helper = not is_imm and save + elif loc.is_raw_sp(): + assert (loc.type == prev_loc.type == FLOAT + or (loc.type != FLOAT and prev_loc.type != FLOAT)) + tmp = loc + if loc.is_float(): + loc = r.vfp_ip + else: + loc, save_helper = self.get_tmp_reg() + assert not save_helper + helper, save_helper = self.get_tmp_reg([loc]) + assert not save_helper else: assert 0, 'unsupported case' + if save_helper: self.mc.PUSH([helper.value], cond=cond) self.load_reg(self.mc, loc, r.fp, offset, cond=cond, helper=helper) if save_helper: self.mc.POP([helper.value], cond=cond) + if tmp and tmp.is_raw_sp(): + self.store_reg(self.mc, loc, r.sp, tmp.value, cond=cond, helper=helper) + def _mov_imm_float_to_loc(self, prev_loc, loc, cond=c.AL): if loc.is_vfp_reg(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, prev_loc.getint(), cond=cond) - self.load_reg(self.mc, loc, r.ip, 0, cond=cond) - self.mc.POP([r.ip.value], cond=cond) - elif loc.is_stack(): - self.regalloc_push(r.vfp_ip) + helper, save_helper = self.get_tmp_reg([loc]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, prev_loc.getint(), cond=cond) + self.load_reg(self.mc, loc, helper, 0, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) + elif loc.is_stack() and loc.type == FLOAT: self.regalloc_mov(prev_loc, r.vfp_ip, cond) self.regalloc_mov(r.vfp_ip, loc, cond) - self.regalloc_pop(r.vfp_ip) + elif loc.is_raw_sp() and loc.type == FLOAT: + self.regalloc_mov(prev_loc, r.vfp_ip, cond) + self.regalloc_mov(r.vfp_ip, loc, cond) else: assert 0, 'unsupported case' @@ -1100,11 +1113,11 @@ # spill vfp register offset = loc.value is_imm = check_imm_arg(offset) - if not is_imm: - self.mc.PUSH([r.ip.value], cond=cond) - self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond) - if not is_imm: - self.mc.POP([r.ip.value], cond=cond) + self.store_reg(self.mc, prev_loc, r.fp, offset, cond=cond, helper=r.ip) + elif loc.is_raw_sp(): + assert loc.type == FLOAT, 'trying to store to an \ + incompatible location from a float register' + self.store_reg(self.mc, prev_loc, r.sp, loc.value, cond=cond) else: assert 0, 'unsupported case' @@ -1120,6 +1133,8 @@ self._mov_imm_float_to_loc(prev_loc, loc, cond) elif prev_loc.is_vfp_reg(): self._mov_vfp_reg_to_loc(prev_loc, loc, cond) + elif prev_loc.is_raw_sp(): + assert 0, 'raw sp locs are not supported as source loc' else: assert 0, 'unsupported case' mov_loc_loc = regalloc_mov @@ -1131,23 +1146,29 @@ if vfp_loc.is_vfp_reg(): self.mc.VMOV_rc(reg1.value, reg2.value, vfp_loc.value, cond=cond) elif vfp_loc.is_imm_float(): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, vfp_loc.getint(), cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, vfp_loc.getint(), cond=cond) # we need to load one word to loc and one to loc+1 which are # two 32-bit core registers - self.mc.LDR_ri(reg1.value, r.ip.value, cond=cond) - self.mc.LDR_ri(reg2.value, r.ip.value, imm=WORD, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + self.mc.LDR_ri(reg1.value, helper.value, cond=cond) + self.mc.LDR_ri(reg2.value, helper.value, imm=WORD, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) elif vfp_loc.is_stack() and vfp_loc.type == FLOAT: # load spilled vfp value into two core registers offset = vfp_loc.value if not check_imm_arg(offset, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.LDR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.LDR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.LDR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.LDR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.LDR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.LDR_ri(reg2.value, r.fp.value, @@ -1165,12 +1186,15 @@ # move from two core registers to a float stack location offset = vfp_loc.value if not check_imm_arg(offset + WORD, size=0xFFF): - self.mc.PUSH([r.ip.value], cond=cond) - self.mc.gen_load_int(r.ip.value, offset, cond=cond) - self.mc.STR_rr(reg1.value, r.fp.value, r.ip.value, cond=cond) - self.mc.ADD_ri(r.ip.value, r.ip.value, imm=WORD, cond=cond) - self.mc.STR_rr(reg2.value, r.fp.value, r.ip.value, cond=cond) - self.mc.POP([r.ip.value], cond=cond) + helper, save_helper = self.get_tmp_reg([reg1, reg2]) + if save_helper: + self.mc.PUSH([helper.value], cond=cond) + self.mc.gen_load_int(helper.value, offset, cond=cond) + self.mc.STR_rr(reg1.value, r.fp.value, helper.value, cond=cond) + self.mc.ADD_ri(helper.value, helper.value, imm=WORD, cond=cond) + self.mc.STR_rr(reg2.value, r.fp.value, helper.value, cond=cond) + if save_helper: + self.mc.POP([helper.value], cond=cond) else: self.mc.STR_ri(reg1.value, r.fp.value, imm=offset, cond=cond) self.mc.STR_ri(reg2.value, r.fp.value, @@ -1417,6 +1441,26 @@ # return shiftsize + def simple_call(self, fnloc, arglocs, result_loc=r.r0): + if result_loc is None: + result_type = VOID + result_size = 0 + elif result_loc.is_vfp_reg(): + result_type = FLOAT + result_size = DOUBLE_WORD + else: + result_type = INT + result_size = WORD + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs, + result_loc, result_type, + result_size) + cb.emit() + + def simple_call_no_collect(self, fnloc, arglocs): + cb = callbuilder.get_callbuilder(self.cpu, self, fnloc, arglocs) + cb.emit_no_collect() + + def not_implemented(msg): os.write(2, '[ARM/asm] %s\n' % msg) raise NotImplementedError(msg) diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py new file mode 100644 --- /dev/null +++ b/rpython/jit/backend/arm/callbuilder.py @@ -0,0 +1,304 @@ +from rpython.rlib.clibffi import FFI_DEFAULT_ABI +from rpython.rlib.objectmodel import we_are_translated +from rpython.jit.metainterp.history import INT, FLOAT, REF +from rpython.jit.backend.arm.arch import WORD +from rpython.jit.backend.arm import registers as r +from rpython.jit.backend.arm import conditions as c +from rpython.jit.backend.arm.locations import RawSPStackLocation +from rpython.jit.backend.arm.jump import remap_frame_layout +from rpython.jit.backend.llsupport.callbuilder import AbstractCallBuilder +from rpython.jit.backend.arm.helper.assembler import count_reg_args +from rpython.jit.backend.arm.helper.assembler import saved_registers +from rpython.jit.backend.arm.helper.regalloc import check_imm_arg + + +class ARMCallbuilder(AbstractCallBuilder): + def __init__(self, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + AbstractCallBuilder.__init__(self, assembler, fnloc, arglocs, + resloc, restype, ressize) + self.current_sp = 0 + + def push_gcmap(self): + assert not self.is_call_release_gil + # we push *now* the gcmap, describing the status of GC registers + # after the rearrangements done just above, ignoring the return + # value eax, if necessary + noregs = self.asm.cpu.gc_ll_descr.is_shadow_stack() + gcmap = self.asm._regalloc.get_gcmap([r.r0], noregs=noregs) + self.asm.push_gcmap(self.mc, gcmap, store=True) + + def pop_gcmap(self): + self.asm._reload_frame_if_necessary(self.mc) + self.asm.pop_gcmap(self.mc) + + def emit_raw_call(self): + #the actual call + if self.fnloc.is_imm(): + self.mc.BL(self.fnloc.value) + return + if self.fnloc.is_stack(): + self.asm.mov_loc_loc(self.fnloc, r.ip) + self.fnloc = r.ip + assert self.fnloc.is_reg() + self.mc.BLX(self.fnloc.value) + + def restore_stack_pointer(self): + # readjust the sp in case we passed some args on the stack + assert self.current_sp % 8 == 0 # sanity check + if self.current_sp != 0: + self._adjust_sp(self.current_sp) + self.current_sp = 0 + + def _push_stack_args(self, stack_args, on_stack): + assert on_stack % 8 == 0 + self._adjust_sp(-on_stack) + self.current_sp = on_stack + ofs = 0 + for i, arg in enumerate(stack_args): + if arg is not None: + sp_loc = RawSPStackLocation(ofs, arg.type) + self.asm.regalloc_mov(arg, sp_loc) + ofs += sp_loc.width + else: # alignment word + ofs += WORD + + def _adjust_sp(self, n): + # adjust the current stack pointer by n bytes + if n > 0: + if check_imm_arg(n): + self.mc.ADD_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.ADD_rr(r.sp.value, r.sp.value, r.ip.value) + else: + n = abs(n) + if check_imm_arg(n): + self.mc.SUB_ri(r.sp.value, r.sp.value, n) + else: + self.mc.gen_load_int(r.ip.value, n) + self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value) + + def select_call_release_gil_mode(self): + AbstractCallBuilder.select_call_release_gil_mode(self) + + def call_releasegil_addr_and_move_real_arguments(self): + assert not self.asm._is_asmgcc() + from rpython.jit.backend.arm.regalloc import CoreRegisterManager + with saved_registers(self.mc, + CoreRegisterManager.save_around_call_regs): + self.mc.BL(self.asm.releasegil_addr) + + if not we_are_translated(): # for testing: we should not access + self.mc.ADD_ri(r.fp.value, r.fp.value, 1) # fp any more + + def move_real_result_and_call_reacqgil_addr(self): + # save the result we just got + assert not self.asm._is_asmgcc() + gpr_to_save, vfp_to_save = self.get_result_locs() + with saved_registers(self.mc, gpr_to_save, vfp_to_save): + self.mc.BL(self.asm.reacqgil_addr) + + if not we_are_translated(): # for testing: now we can accesss + self.mc.SUB_ri(r.fp.value, r.fp.value, 1) # fp again + + # for shadowstack, done for us by _reload_frame_if_necessary() + + def get_result_locs(self): + raise NotImplementedError + + def _ensure_result_bit_extension(self, resloc, size, signed): + if size == 4: + return + if size == 1: + if not signed: # unsigned char + self.mc.AND_ri(resloc.value, resloc.value, 0xFF) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 24) + self.mc.ASR_ri(resloc.value, resloc.value, 24) + elif size == 2: + if not signed: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.LSR_ri(resloc.value, resloc.value, 16) + else: + self.mc.LSL_ri(resloc.value, resloc.value, 16) + self.mc.ASR_ri(resloc.value, resloc.value, 16) + + + +class SoftFloatCallBuilder(ARMCallbuilder): + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [r.r0, r.r1], [] + assert self.resloc.is_reg() + return [r.r0], [] + + def load_result(self): + # ensure the result is wellformed and stored in the correct location + resloc = self.resloc + if resloc is None: + return + if resloc.is_vfp_reg(): + # move result to the allocated register + self.asm.mov_to_vfp_loc(r.r0, r.r1, resloc) + elif resloc.is_reg(): + # move result to the allocated register + if resloc is not r.r0: + self.asm.mov_loc_loc(r.r0, resloc) + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + + def _collect_and_push_stack_args(self, arglocs): + n_args = len(arglocs) + reg_args = count_reg_args(arglocs) + # all arguments past the 4th go on the stack + # first we need to prepare the list so it stays aligned + stack_args = [] + count = 0 + on_stack = 0 + if n_args > reg_args: + for i in range(reg_args, n_args): + arg = arglocs[i] + if arg.type != FLOAT: + count += 1 + on_stack += 1 + else: + on_stack += 2 + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + if count % 2 != 0: + on_stack += 1 + stack_args.append(None) + if on_stack > 0: + self._push_stack_args(stack_args, on_stack*WORD) + + def prepare_arguments(self): + arglocs = self.arglocs + reg_args = count_reg_args(arglocs) + self._collect_and_push_stack_args(arglocs) + # collect variables that need to go in registers and the registers they + # will be stored in + num = 0 + count = 0 + non_float_locs = [] + non_float_regs = [] + float_locs = [] + for i in range(reg_args): + arg = arglocs[i] + if arg.type == FLOAT and count % 2 != 0: + num += 1 + count = 0 + reg = r.caller_resp[num] + + if arg.type == FLOAT: + float_locs.append((arg, reg)) + else: + non_float_locs.append(arg) + non_float_regs.append(reg) + + if arg.type == FLOAT: + num += 2 + else: + num += 1 + count += 1 + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in r.argument_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + + for loc, reg in float_locs: + self.asm.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) + +class HardFloatCallBuilder(ARMCallbuilder): + + def prepare_arguments(self): + non_float_locs = [] + non_float_regs = [] + float_locs = [] + float_regs = [] + stack_args = [] + + arglocs = self.arglocs + argtypes = self.argtypes + + count = 0 # stack alignment counter + on_stack = 0 + for arg in arglocs: + if arg.type != FLOAT: + if len(non_float_regs) < len(r.argument_regs): + reg = r.argument_regs[len(non_float_regs)] + non_float_locs.append(arg) + non_float_regs.append(reg) + else: # non-float argument that needs to go on the stack + count += 1 + on_stack += 1 + stack_args.append(arg) + else: + if len(float_regs) < len(r.vfp_argument_regs): + reg = r.vfp_argument_regs[len(float_regs)] + float_locs.append(arg) + float_regs.append(reg) + else: # float argument that needs to go on the stack + if count % 2 != 0: + stack_args.append(None) + count = 0 + on_stack += 1 + stack_args.append(arg) + on_stack += 2 + # align the stack + if count % 2 != 0: + stack_args.append(None) + on_stack += 1 + self._push_stack_args(stack_args, on_stack*WORD) + # Check that the address of the function we want to call is not + # currently stored in one of the registers used to pass the arguments + # or on the stack, which we can not access later + # If this happens to be the case we remap the register to r4 and use r4 + # to call the function + if self.fnloc in non_float_regs or self.fnloc.is_stack(): + non_float_locs.append(self.fnloc) + non_float_regs.append(r.r4) + self.fnloc = r.r4 + # remap values stored in core registers + remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip) + # remap values stored in vfp registers + remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip) + + def load_result(self): + resloc = self.resloc + # ensure the result is wellformed and stored in the correct location + if resloc is not None and resloc.is_reg(): + self._ensure_result_bit_extension(resloc, + self.ressize, self.ressign) + + def get_result_locs(self): + if self.resloc is None: + return [], [] + if self.resloc.is_vfp_reg(): + return [], [r.d0] + assert self.resloc.is_reg() + return [r.r0], [] + + +def get_callbuilder(cpu, assembler, fnloc, arglocs, + resloc=r.r0, restype=INT, ressize=WORD, ressigned=True): + if cpu.cpuinfo.hf_abi: + return HardFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) + else: + return SoftFloatCallBuilder(assembler, fnloc, arglocs, resloc, + restype, ressize, ressigned) diff --git a/rpython/jit/backend/arm/locations.py b/rpython/jit/backend/arm/locations.py --- a/rpython/jit/backend/arm/locations.py +++ b/rpython/jit/backend/arm/locations.py @@ -12,6 +12,9 @@ def is_stack(self): return False + def is_raw_sp(self): + return False + def is_reg(self): return False @@ -145,7 +148,27 @@ return self.position + 10000 def is_float(self): - return type == FLOAT + return self.type == FLOAT + +class RawSPStackLocation(AssemblerLocation): + _immutable_ = True + + def __init__(self, sp_offset, type=INT): + if type == FLOAT: + self.width = DOUBLE_WORD + else: + self.width = WORD + self.value = sp_offset + self.type = type + + def __repr__(self): + return 'SP(%s)+%d' % (self.type, self.value,) + + def is_raw_sp(self): + return True + + def is_float(self): + return self.type == FLOAT def imm(i): diff --git a/rpython/jit/backend/arm/opassembler.py b/rpython/jit/backend/arm/opassembler.py --- a/rpython/jit/backend/arm/opassembler.py +++ b/rpython/jit/backend/arm/opassembler.py @@ -13,8 +13,7 @@ gen_emit_float_cmp_op, gen_emit_float_cmp_op_guard, gen_emit_unary_float_op, - saved_registers, - count_reg_args) + saved_registers) from rpython.jit.backend.arm.helper.regalloc import check_imm_arg from rpython.jit.backend.arm.codebuilder import InstrBuilder, OverwritingBuilder from rpython.jit.backend.arm.jump import remap_frame_layout @@ -31,8 +30,7 @@ from rpython.rlib.objectmodel import we_are_translated from rpython.rtyper.lltypesystem import rstr, rffi, lltype from rpython.rtyper.annlowlevel import cast_instance_to_gcref - -NO_FORCE_INDEX = -1 +from rpython.jit.backend.arm import callbuilder class ArmGuardToken(GuardToken): @@ -339,217 +337,36 @@ return fcond def emit_op_call(self, op, arglocs, regalloc, fcond): - resloc = arglocs[0] - adr = arglocs[1] - arglist = arglocs[2:] + return self._emit_call(op, arglocs, fcond=fcond) + + def _emit_call(self, op, arglocs, is_call_release_gil=False, fcond=c.AL): + # args = [resloc, size, sign, args...] + from rpython.jit.backend.llsupport.descr import CallDescr + + cb = callbuilder.get_callbuilder(self.cpu, self, arglocs[3], arglocs[4:], arglocs[0]) + descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - cond = self._emit_call(adr, arglist, - fcond, resloc, (size, signed)) - return cond + assert isinstance(descr, CallDescr) + cb.callconv = descr.get_call_conv() + cb.argtypes = descr.get_arg_types() + cb.restype = descr.get_result_type() + sizeloc = arglocs[1] + assert sizeloc.is_imm() + cb.ressize = sizeloc.value + signloc = arglocs[2] + assert signloc.is_imm() + cb.ressign = signloc.value - def _emit_call(self, adr, arglocs, fcond=c.AL, resloc=None, - result_info=(-1, -1), - # whether to worry about a CALL that can collect; this - # is always true except in call_release_gil - can_collect=True): - if self.cpu.cpuinfo.hf_abi: - stack_args, adr = self._setup_call_hf(adr, arglocs, fcond, - resloc, result_info) + if is_call_release_gil: + cb.emit_call_release_gil() else: - stack_args, adr = self._setup_call_sf(adr, arglocs, fcond, - resloc, result_info) - - if can_collect: - # we push *now* the gcmap, describing the status of GC registers - # after the rearrangements done just above, ignoring the return - # value eax, if necessary - noregs = self.cpu.gc_ll_descr.is_shadow_stack() - gcmap = self._regalloc.get_gcmap([r.r0], noregs=noregs) - self.push_gcmap(self.mc, gcmap, store=True) - #the actual call - if adr.is_imm(): - self.mc.BL(adr.value) - elif adr.is_stack(): - self.mov_loc_loc(adr, r.ip) - adr = r.ip - else: - assert adr.is_reg() - if adr.is_reg(): - self.mc.BLX(adr.value) - self._restore_sp(stack_args, fcond) - - # ensure the result is wellformed and stored in the correct location - if resloc is not None: - if resloc.is_vfp_reg() and not self.cpu.cpuinfo.hf_abi: - # move result to the allocated register - self.mov_to_vfp_loc(r.r0, r.r1, resloc) - elif resloc.is_reg() and result_info != (-1, -1): - self._ensure_result_bit_extension(resloc, result_info[0], - result_info[1]) - if can_collect: - self._reload_frame_if_necessary(self.mc) - self.pop_gcmap(self.mc) + cb.emit() return fcond - def _restore_sp(self, stack_args, fcond): - # readjust the sp in case we passed some args on the stack - if len(stack_args) > 0: - n = 0 - for arg in stack_args: - if arg is None or arg.type != FLOAT: - n += WORD - else: - n += DOUBLE_WORD - self._adjust_sp(-n, fcond=fcond) - assert n % 8 == 0 # sanity check - - def _adjust_sp(self, n, cb=None, fcond=c.AL, base_reg=r.sp): - if cb is None: - cb = self.mc - if n < 0: - n = -n - rev = True - else: - rev = False - if n <= 0xFF and fcond == c.AL: - if rev: - cb.ADD_ri(r.sp.value, base_reg.value, n) - else: - cb.SUB_ri(r.sp.value, base_reg.value, n) - else: - cb.gen_load_int(r.ip.value, n, cond=fcond) - if rev: - cb.ADD_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - else: - cb.SUB_rr(r.sp.value, base_reg.value, r.ip.value, cond=fcond) - - - def _collect_stack_args_sf(self, arglocs): - n_args = len(arglocs) - reg_args = count_reg_args(arglocs) - # all arguments past the 4th go on the stack - # first we need to prepare the list so it stays aligned - stack_args = [] - count = 0 - if n_args > reg_args: - for i in range(reg_args, n_args): - arg = arglocs[i] - if arg.type != FLOAT: - count += 1 - else: - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - if count % 2 != 0: - stack_args.append(None) - return stack_args - - def _push_stack_args(self, stack_args): - #then we push every thing on the stack - for i in range(len(stack_args) - 1, -1, -1): - arg = stack_args[i] - if arg is None: - self.mc.PUSH([r.ip.value]) - else: - self.regalloc_push(arg) - - def _setup_call_sf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - reg_args = count_reg_args(arglocs) - stack_args = self._collect_stack_args_sf(arglocs) - self._push_stack_args(stack_args) - # collect variables that need to go in registers and the registers they - # will be stored in - num = 0 - count = 0 - non_float_locs = [] - non_float_regs = [] - float_locs = [] - for i in range(reg_args): - arg = arglocs[i] - if arg.type == FLOAT and count % 2 != 0: - num += 1 - count = 0 - reg = r.caller_resp[num] - - if arg.type == FLOAT: - float_locs.append((arg, reg)) - else: - non_float_locs.append(arg) - non_float_regs.append(reg) - - if arg.type == FLOAT: - num += 2 - else: - num += 1 - count += 1 - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - - for loc, reg in float_locs: - self.mov_from_vfp_loc(loc, reg, r.all_regs[reg.value + 1]) - return stack_args, adr - - def _setup_call_hf(self, adr, arglocs, fcond=c.AL, - resloc=None, result_info=(-1, -1)): - non_float_locs = [] - non_float_regs = [] - float_locs = [] - float_regs = [] - stack_args = [] - count = 0 # stack alignment counter - for arg in arglocs: - if arg.type != FLOAT: - if len(non_float_regs) < len(r.argument_regs): - reg = r.argument_regs[len(non_float_regs)] - non_float_locs.append(arg) - non_float_regs.append(reg) - else: # non-float argument that needs to go on the stack - count += 1 - stack_args.append(arg) - else: - if len(float_regs) < len(r.vfp_argument_regs): - reg = r.vfp_argument_regs[len(float_regs)] - float_locs.append(arg) - float_regs.append(reg) - else: # float argument that needs to go on the stack - if count % 2 != 0: - stack_args.append(None) - count = 0 - stack_args.append(arg) - # align the stack - if count % 2 != 0: - stack_args.append(None) - self._push_stack_args(stack_args) - # Check that the address of the function we want to call is not - # currently stored in one of the registers used to pass the arguments. - # If this happens to be the case we remap the register to r4 and use r4 - # to call the function - if adr in non_float_regs: - non_float_locs.append(adr) - non_float_regs.append(r.r4) - adr = r.r4 - # remap values stored in core registers - remap_frame_layout(self, non_float_locs, non_float_regs, r.ip) - # remap values stored in vfp registers - remap_frame_layout(self, float_locs, float_regs, r.vfp_ip) - - return stack_args, adr - def emit_op_same_as(self, op, arglocs, regalloc, fcond): argloc, resloc = arglocs - self.mov_loc_loc(argloc, resloc) + if argloc is not resloc: + self.mov_loc_loc(argloc, resloc) return fcond emit_op_cast_ptr_to_int = emit_op_same_as @@ -1037,9 +854,8 @@ length_loc = bytes_loc # call memcpy() regalloc.before_call() - self._emit_call(imm(self.memcpy_addr), - [dstaddr_loc, srcaddr_loc, length_loc], - can_collect=False) + self.simple_call_no_collect(imm(self.memcpy_addr), + [dstaddr_loc, srcaddr_loc, length_loc]) regalloc.rm.possibly_free_var(length_box) regalloc.rm.possibly_free_var(dstaddr_box) regalloc.rm.possibly_free_var(srcaddr_box) @@ -1127,14 +943,14 @@ vloc = imm(0) self.call_assembler(op, guard_op, argloc, vloc, result_loc, tmploc) self._emit_guard_may_force(guard_op, - regalloc._prepare_guard(guard_op), guard_op.numargs()) + regalloc._prepare_guard(guard_op)) return fcond def _call_assembler_emit_call(self, addr, argloc, resloc): - self._emit_call(addr, [argloc], resloc=resloc) + self.simple_call(addr, [argloc], result_loc=resloc) def _call_assembler_emit_helper_call(self, addr, arglocs, resloc): - self._emit_call(addr, arglocs, resloc=resloc) + self.simple_call(addr, arglocs, result_loc=resloc) def _call_assembler_check_descr(self, value, tmploc): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') @@ -1213,20 +1029,14 @@ fcond): self._store_force_index(guard_op) numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed)) - self._emit_guard_may_force(guard_op, arglocs[1 + numargs:], numargs) + self._emit_call(op, callargs, fcond=fcond) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def _emit_guard_may_force(self, guard_op, arglocs, numargs): + def _emit_guard_may_force(self, guard_op, arglocs): ofs = self.cpu.get_ofs_of_frame_field('jf_descr') self.mc.LDR_ri(r.ip.value, r.fp.value, imm=ofs) self.mc.CMP_ri(r.ip.value, 0) @@ -1235,68 +1045,14 @@ def emit_guard_call_release_gil(self, op, guard_op, arglocs, regalloc, fcond): - + numargs = op.numargs() + callargs = arglocs[:numargs + 3] # extract the arguments to the call + guardargs = arglocs[len(callargs):] # extrat the arguments for the guard self._store_force_index(guard_op) - # first, close the stack in the sense of the asmgcc GC root tracker - gcrootmap = self.cpu.gc_ll_descr.gcrootmap - numargs = op.numargs() - callargs = arglocs[2:numargs + 1] # extract the arguments to the call - adr = arglocs[1] - resloc = arglocs[0] - - if gcrootmap: - # we put the gcmap now into the frame before releasing the GIL, - # and pop it below after reacquiring the GIL. The assumption - # is that this gcmap describes correctly the situation at any - # point in-between: all values containing GC pointers should - # be safely saved out of registers by now, and will not be - # manipulated by any of the following CALLs. - gcmap = self._regalloc.get_gcmap(noregs=True) - self.push_gcmap(self.mc, gcmap, store=True) - self.call_release_gil(gcrootmap, arglocs, regalloc, fcond) - # do the call - descr = op.getdescr() - size = descr.get_result_size() - signed = descr.is_result_signed() - # - self._emit_call(adr, callargs, fcond, - resloc, (size, signed), - can_collect=False) - # then reopen the stack - if gcrootmap: - self.call_reacquire_gil(gcrootmap, resloc, regalloc, fcond) - self.pop_gcmap(self.mc) # remove the gcmap saved above - - self._emit_guard_may_force(guard_op, arglocs[numargs+1:], numargs) + self._emit_call(op, callargs, is_call_release_gil=True) + self._emit_guard_may_force(guard_op, guardargs) return fcond - def call_release_gil(self, gcrootmap, save_registers, regalloc, fcond): - # Save caller saved registers and do the call - # NOTE: We assume that the floating point registers won't be modified. - assert gcrootmap.is_shadow_stack - with saved_registers(self.mc, regalloc.rm.save_around_call_regs): - self._emit_call(imm(self.releasegil_addr), [], - fcond, can_collect=False) - - def call_reacquire_gil(self, gcrootmap, save_loc, regalloc, fcond): - # save the previous result into the stack temporarily, in case it is in - # a caller saved register. - # NOTE: like with call_release_gil(), we assume that we don't need to - # save vfp regs in this case. Besides the result location - regs_to_save = [] - vfp_regs_to_save = [] - if save_loc and save_loc in regalloc.rm.save_around_call_regs: - regs_to_save.append(save_loc) - regs_to_save.append(r.ip) # for alingment - elif save_loc and save_loc in regalloc.vfprm.save_around_call_regs: - vfp_regs_to_save.append(save_loc) - assert gcrootmap.is_shadow_stack - # call the reopenstack() function (also reacquiring the GIL) - with saved_registers(self.mc, regs_to_save, vfp_regs_to_save): - self._emit_call(imm(self.reacqgil_addr), [], fcond, - can_collect=False) - self._reload_frame_if_necessary(self.mc) - def _store_force_index(self, guard_op): faildescr = guard_op.getdescr() ofs = self.cpu.get_ofs_of_frame_field('jf_force_descr') diff --git a/rpython/jit/backend/arm/regalloc.py b/rpython/jit/backend/arm/regalloc.py --- a/rpython/jit/backend/arm/regalloc.py +++ b/rpython/jit/backend/arm/regalloc.py @@ -34,6 +34,7 @@ from rpython.jit.backend.llsupport.descr import unpack_fielddescr from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr from rpython.rlib.rarithmetic import r_uint +from rpython.jit.backend.llsupport.descr import CallDescr # xxx hack: set a default value for TargetToken._ll_loop_code. If 0, we know @@ -555,9 +556,27 @@ return self._prepare_call(op) def _prepare_call(self, op, force_store=[], save_all_regs=False): - args = [None] * (op.numargs() + 1) + args = [None] * (op.numargs() + 3) + calldescr = op.getdescr() + assert isinstance(calldescr, CallDescr) + assert len(calldescr.arg_classes) == op.numargs() - 1 + for i in range(op.numargs()): - args[i + 1] = self.loc(op.getarg(i)) + args[i + 3] = self.loc(op.getarg(i)) + + size = calldescr.get_result_size() + sign = calldescr.is_result_signed() + if sign: + sign_loc = imm(1) + else: + sign_loc = imm(0) + args[1] = imm(size) + args[2] = sign_loc + + args[0] = self._call(op, args, force_store, save_all_regs) + return args + + def _call(self, op, arglocs, force_store=[], save_all_regs=False): # spill variables that need to be saved around calls self.vfprm.before_call(save_all_regs=save_all_regs) if not save_all_regs: @@ -565,11 +584,11 @@ if gcrootmap and gcrootmap.is_shadow_stack: save_all_regs = 2 self.rm.before_call(save_all_regs=save_all_regs) + self.before_call_called = True + resloc = None if op.result: resloc = self.after_call(op.result) - args[0] = resloc - self.before_call_called = True - return args + return resloc def prepare_op_call_malloc_gc(self, op, fcond): return self._prepare_call(op) @@ -1153,9 +1172,9 @@ def prepare_guard_call_assembler(self, op, guard_op, fcond): locs = self.locs_for_call_assembler(op, guard_op) tmploc = self.get_scratch_reg(INT, selected_reg=r.r0) - call_locs = self._prepare_call(op, save_all_regs=True) + resloc = self._call(op, locs + [tmploc], save_all_regs=True) self.possibly_free_vars(guard_op.getfailargs()) - return locs + [call_locs[0], tmploc] + return locs + [resloc, tmploc] def _prepare_args_for_new_op(self, new_args): gc_ll_descr = self.cpu.gc_ll_descr diff --git a/rpython/jit/backend/arm/test/test_regalloc_mov.py b/rpython/jit/backend/arm/test/test_regalloc_mov.py --- a/rpython/jit/backend/arm/test/test_regalloc_mov.py +++ b/rpython/jit/backend/arm/test/test_regalloc_mov.py @@ -1,9 +1,10 @@ from rpython.rlib.objectmodel import instantiate from rpython.jit.backend.arm.assembler import AssemblerARM -from rpython.jit.backend.arm.locations import imm, ConstFloatLoc,\ From noreply at buildbot.pypy.org Tue May 28 21:44:23 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 21:44:23 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: merge default Message-ID: <20130528194423.0E0441C021A@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64633:1d387bc97dc7 Date: 2013-05-28 12:38 -0700 http://bitbucket.org/pypy/pypy/changeset/1d387bc97dc7/ Log: merge default 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 @@ -34,3 +34,9 @@ .. branch: remove-iter-smm Remove multi-methods on iterators + +.. branch: emit-call-x86 +.. branch: emit-call-arm + +.. branch: on-abort-resops +Added list of resops to the pypyjit on_abort hook. 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 @@ -59,7 +59,7 @@ arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto') EQ, NE, LT, LE, GT, GE = range(6) -def compare_arrays(space, arr1, arr2, comp_op, comp_func): +def compare_arrays(space, arr1, arr2, comp_op): if (not isinstance(arr1, W_ArrayBase) or not isinstance(arr2, W_ArrayBase)): return space.w_NotImplemented @@ -69,22 +69,31 @@ return space.w_True lgt = min(arr1.len, arr2.len) for i in range(lgt): - arr_eq_driver.jit_merge_point(comp_func=comp_func) + arr_eq_driver.jit_merge_point(comp_func=comp_op) w_elem1 = arr1.w_getitem(space, i) w_elem2 = arr2.w_getitem(space, i) - res = space.is_true(comp_func(w_elem1, w_elem2)) if comp_op == EQ: + res = space.is_true(space.eq(w_elem1, w_elem2)) if not res: return space.w_False elif comp_op == NE: + res = space.is_true(space.ne(w_elem1, w_elem2)) if res: return space.w_True elif comp_op == LT or comp_op == GT: + if comp_op == LT: + res = space.is_true(space.lt(w_elem1, w_elem2)) + else: + res = space.is_true(space.gt(w_elem1, w_elem2)) if res: return space.w_True elif not space.is_true(space.eq(w_elem1, w_elem2)): return space.w_False else: + if comp_op == LE: + res = space.is_true(space.le(w_elem1, w_elem2)) + else: + res = space.is_true(space.ge(w_elem1, w_elem2)) if not res: return space.w_False elif not space.is_true(space.eq(w_elem1, w_elem2)): @@ -362,27 +371,27 @@ def descr_eq(self, space, w_arr2): "x.__eq__(y) <==> x==y" - return compare_arrays(space, self, w_arr2, EQ, space.eq) + return compare_arrays(space, self, w_arr2, EQ) def descr_ne(self, space, w_arr2): "x.__ne__(y) <==> x!=y" - return compare_arrays(space, self, w_arr2, NE, space.ne) + return compare_arrays(space, self, w_arr2, NE) def descr_lt(self, space, w_arr2): "x.__lt__(y) <==> x x<=y" - return compare_arrays(space, self, w_arr2, LE, space.le) + return compare_arrays(space, self, w_arr2, LE) def descr_gt(self, space, w_arr2): "x.__gt__(y) <==> x>y" - return compare_arrays(space, self, w_arr2, GT, space.gt) + return compare_arrays(space, self, w_arr2, GT) def descr_ge(self, space, w_arr2): "x.__ge__(y) <==> x>=y" - return compare_arrays(space, self, w_arr2, GE, space.ge) + return compare_arrays(space, self, w_arr2, GE) # Basic get/set/append/extend methods diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -13,6 +13,7 @@ 'empty': 'interp_numarray.zeros', 'ones': 'interp_numarray.ones', '_reconstruct' : 'interp_numarray._reconstruct', + 'scalar' : 'interp_numarray.build_scalar', 'dot': 'interp_arrayops.dot', 'fromstring': 'interp_support.fromstring', 'flatiter': 'interp_flatiter.W_FlatIterator', diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -11,6 +11,8 @@ from rpython.rtyper.lltypesystem import rffi from rpython.tool.sourcetools import func_with_new_name from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage +from rpython.rlib.objectmodel import specialize +from pypy.interpreter.mixedmodule import MixedModule MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else () MIXIN_64 = (int_typedef,) if LONG_BIT == 64 else () @@ -33,7 +35,11 @@ def new(space, w_subtype, w_value): dtype = _get_dtype(space) return dtype.itemtype.coerce_subtype(space, w_subtype, w_value) - return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype) + + def descr_reduce(self, space): + return self.reduce(space) + + return func_with_new_name(new, name + "_box_new"), staticmethod(_get_dtype), func_with_new_name(descr_reduce, "descr_reduce") class PrimitiveBox(object): @@ -48,6 +54,26 @@ def __repr__(self): return '%s(%s)' % (self.__class__.__name__, self.value) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.value)), 1, flavor="raw") + value[0] = self.value + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.value))) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret + class ComplexBox(object): _mixin_ = True @@ -64,6 +90,26 @@ def convert_imag_to(self, dtype): return dtype.box(self.imag) + def reduce(self, space): + from rpython.rlib.rstring import StringBuilder + from rpython.rtyper.lltypesystem import rffi, lltype + + numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(numpypy, MixedModule) + multiarray = numpypy.get("multiarray") + assert isinstance(multiarray, MixedModule) + scalar = multiarray.get("scalar") + + value = lltype.malloc(rffi.CArray(lltype.typeOf(self.real)), 2, flavor="raw") + value[0] = self.real + value[1] = self.imag + + builder = StringBuilder() + builder.append_charpsize(rffi.cast(rffi.CCHARP, value), rffi.sizeof(lltype.typeOf(self.real)) * 2) + + ret = space.newtuple([scalar, space.newtuple([space.wrap(self._get_dtype(space)), space.wrap(builder.build())])]) + lltype.free(value, flavor="raw") + return ret class W_GenericBox(W_Root): _attrs_ = () @@ -187,7 +233,7 @@ return convert_to_array(space, w_values) class W_BoolBox(W_GenericBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("bool") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("bool") class W_NumberBox(W_GenericBox): _attrs_ = () @@ -203,40 +249,40 @@ pass class W_Int8Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int8") class W_UInt8Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint8") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint8") class W_Int16Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int16") class W_UInt16Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint16") class W_Int32Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int32") class W_UInt32Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint32") class W_LongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("long") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("long") class W_ULongBox(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("ulong") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("ulong") class W_Int64Box(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("int64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("int64") class W_LongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('longlong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('longlong') class W_UInt64Box(W_UnsignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("uint64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("uint64") class W_ULongLongBox(W_SignedIntegerBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter('ulonglong') + descr__new__, _get_dtype, descr_reduce = new_dtype_getter('ulonglong') class W_InexactBox(W_NumberBox): _attrs_ = () @@ -245,13 +291,13 @@ _attrs_ = () class W_Float16Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float16") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float16") class W_Float32Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float32") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float32") class W_Float64Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64") class W_FlexibleBox(W_GenericBox): _attrs_ = ['ofs', 'dtype', 'arr'] @@ -356,33 +402,33 @@ class W_Complex64Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex64") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex64") _COMPONENTS_BOX = W_Float32Box class W_Complex128Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex128") _COMPONENTS_BOX = W_Float64Box if ENABLED_LONG_DOUBLE and long_double_size == 12: class W_Float96Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float96") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float96") W_LongDoubleBox = W_Float96Box class W_Complex192Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex192") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex192") _COMPONENTS_BOX = W_Float96Box W_CLongDoubleBox = W_Complex192Box elif ENABLED_LONG_DOUBLE and long_double_size == 16: class W_Float128Box(W_FloatingBox, PrimitiveBox): - descr__new__, _get_dtype = new_dtype_getter("float128") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float128") W_LongDoubleBox = W_Float128Box class W_Complex256Box(ComplexBox, W_ComplexFloatingBox): - descr__new__, _get_dtype = new_dtype_getter("complex256") + descr__new__, _get_dtype, descr_reduce = new_dtype_getter("complex256") _COMPONENTS_BOX = W_Float128Box W_CLongDoubleBox = W_Complex256Box @@ -458,6 +504,7 @@ __module__ = "numpypy", __new__ = interp2app(W_BoolBox.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_BoolBox.descr_reduce), ) W_NumberBox.typedef = TypeDef("number", W_GenericBox.typedef, @@ -480,42 +527,49 @@ __module__ = "numpypy", __new__ = interp2app(W_Int8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int8Box.descr_reduce), ) W_UInt8Box.typedef = TypeDef("uint8", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt8Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt8Box.descr_reduce), ) W_Int16Box.typedef = TypeDef("int16", W_SignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Int16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int16Box.descr_reduce), ) W_UInt16Box.typedef = TypeDef("uint16", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt16Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt16Box.descr_reduce), ) W_Int32Box.typedef = TypeDef("int32", (W_SignedIntegerBox.typedef,) + MIXIN_32, __module__ = "numpypy", __new__ = interp2app(W_Int32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int32Box.descr_reduce), ) W_UInt32Box.typedef = TypeDef("uint32", W_UnsignedIntegerBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_UInt32Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt32Box.descr_reduce), ) W_Int64Box.typedef = TypeDef("int64", (W_SignedIntegerBox.typedef,) + MIXIN_64, __module__ = "numpypy", __new__ = interp2app(W_Int64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_Int64Box.descr_reduce), ) if LONG_BIT == 32: @@ -529,6 +583,7 @@ __module__ = "numpypy", __new__ = interp2app(W_UInt64Box.descr__new__.im_func), __index__ = interp2app(descr_index), + __reduce__ = interp2app(W_UInt64Box.descr_reduce), ) W_InexactBox.typedef = TypeDef("inexact", W_NumberBox.typedef, @@ -543,23 +598,27 @@ __module__ = "numpypy", __new__ = interp2app(W_Float16Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float16Box.descr_reduce), ) W_Float32Box.typedef = TypeDef("float32", W_FloatingBox.typedef, __module__ = "numpypy", __new__ = interp2app(W_Float32Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float32Box.descr_reduce), ) W_Float64Box.typedef = TypeDef("float64", (W_FloatingBox.typedef, float_typedef), __module__ = "numpypy", __new__ = interp2app(W_Float64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float64Box.descr_reduce), ) if ENABLED_LONG_DOUBLE and long_double_size == 12: W_Float96Box.typedef = TypeDef("float96", (W_FloatingBox.typedef), __module__ = "numpypy", + __reduce__ = interp2app(W_Float96Box.descr_reduce), __new__ = interp2app(W_Float96Box.descr__new__.im_func), ) @@ -567,6 +626,7 @@ W_Complex192Box.typedef = TypeDef("complex192", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex192Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex192Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -576,11 +636,13 @@ __module__ = "numpypy", __new__ = interp2app(W_Float128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Float128Box.descr_reduce), ) W_Complex256Box.typedef = TypeDef("complex256", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex256Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex256Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -618,6 +680,7 @@ W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex128Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex128Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox.descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) @@ -625,6 +688,7 @@ W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef), __module__ = "numpypy", __new__ = interp2app(W_Complex64Box.descr__new__.im_func), + __reduce__ = interp2app(W_Complex64Box.descr_reduce), real = GetSetProperty(W_ComplexFloatingBox .descr_get_real), imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag), ) diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -1051,6 +1051,17 @@ def _reconstruct(space, w_subtype, w_shape, w_dtype): return descr_new_array(space, w_subtype, w_shape, w_dtype) +def build_scalar(space, w_dtype, w_state): + from rpython.rtyper.lltypesystem import rffi, lltype + + assert isinstance(w_dtype, interp_dtype.W_Dtype) + + state = rffi.str2charp(space.str_w(w_state)) + box = w_dtype.itemtype.box_raw_data(state) + lltype.free(state, flavor="raw") + return box + + W_FlatIterator.typedef = TypeDef( 'flatiter', __iter__ = interp2app(W_FlatIterator.descr_iter), diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py new file mode 100644 --- /dev/null +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -0,0 +1,23 @@ +from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest + +class AppTestScalar(BaseNumpyAppTest): + spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) + + def test_pickle(self): + from numpypy import dtype, int32, float64, complex128, zeros, sum + from numpypy.core.multiarray import scalar + from cPickle import loads, dumps + i = int32(1337) + f = float64(13.37) + c = complex128(13 + 37.j) + + assert i.__reduce__() == (scalar, (dtype('int32'), '9\x05\x00\x00')) + assert f.__reduce__() == (scalar, (dtype('float64'), '=\n\xd7\xa3p\xbd*@')) + assert c.__reduce__() == (scalar, (dtype('complex128'), '\x00\x00\x00\x00\x00\x00*@\x00\x00\x00\x00\x00\x80B@')) + + assert loads(dumps(i)) == i + assert loads(dumps(f)) == f + assert loads(dumps(c)) == c + + a = zeros(3) + assert loads(dumps(sum(a))) == sum(a) diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -145,6 +145,11 @@ #XXX this is the place to display a warning return self.box(real) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box(array[0]) + @specialize.argtype(1) def unbox(self, box): assert isinstance(box, self.BoxType) @@ -1108,6 +1113,11 @@ rffi.cast(self.T, real), rffi.cast(self.T, imag)) + def box_raw_data(self, data): + # For pickle + array = rffi.cast(rffi.CArrayPtr(self.T), data) + return self.box_complex(array[0], array[1]) + def unbox(self, box): assert isinstance(box, self.BoxType) # do this in two stages since real, imag are read only diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py --- a/pypy/module/pypyjit/test_pypy_c/test_array.py +++ b/pypy/module/pypyjit/test_pypy_c/test_array.py @@ -39,7 +39,7 @@ assert log.result == 19507200 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" - guard_not_invalidated(descr=...) + guard_not_invalidated? i13 = int_lt(i7, i9) guard_true(i13, descr=...) i15 = getarrayitem_raw(i10, i7, descr=) @@ -105,6 +105,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) f13 = getarrayitem_raw(i8, i6, descr=) @@ -141,6 +142,7 @@ assert loop.match(""" i10 = int_lt(i6, 1000) guard_true(i10, descr=...) + guard_not_invalidated? i11 = int_lt(i6, i7) guard_true(i11, descr=...) i13 = getarrayitem_raw(i8, i6, descr=) diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -9,6 +9,7 @@ cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] - popen = subprocess.Popen(cmdline) + popen = subprocess.Popen(cmdline, stderr=subprocess.PIPE) + errmsg = popen.stderr.read() err = popen.wait() - assert err == 0 + assert err == 0, "err = %r, errmsg:\n%s" % (err, errmsg) diff --git a/pypy/module/pypyjit/test_pypy_c/test_getframe.py b/pypy/module/pypyjit/test_pypy_c/test_getframe.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/test_pypy_c/test_getframe.py @@ -0,0 +1,25 @@ +from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC + + +class TestGetFrame(BaseTestPyPyC): + def test_getframe_one(self): + def main(n): + import sys + + i = 0 + while i < n: + assert sys._getframe(0).f_code.co_filename == __file__ + i += 1 + return i + + log = self.run(main, [300]) + assert log.result == 300 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i54 = int_lt(i47, i28) + guard_true(i54, descr=...) + guard_not_invalidated(descr=...) + i55 = int_add(i47, 1) + --TICK-- + jump(..., descr=...) + """) diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py --- a/pypy/module/sys/vm.py +++ b/pypy/module/sys/vm.py @@ -1,14 +1,18 @@ """ Implementation of interpreter-level 'sys' routines. """ -from pypy.interpreter import gateway -from pypy.interpreter.error import OperationError -from pypy.interpreter.gateway import unwrap_spec, WrappedDefault + from rpython.rlib import jit from rpython.rlib.runicode import MAXUNICODE +from pypy.interpreter import gateway +from pypy.interpreter.error import OperationError +from pypy.interpreter.gateway import unwrap_spec + + # ____________________________________________________________ + @unwrap_spec(depth=int) def _getframe(space, depth=0): """Return a frame object from the call stack. If optional integer depth is @@ -21,6 +25,11 @@ if depth < 0: raise OperationError(space.w_ValueError, space.wrap("frame index must not be negative")) + return getframe(space, depth) + + + at jit.look_inside_iff(lambda space, depth: jit.isconstant(depth)) +def getframe(space, depth): ec = space.getexecutioncontext() f = ec.gettopframe_nohidden() while True: @@ -28,11 +37,11 @@ raise OperationError(space.w_ValueError, space.wrap("call stack is not deep enough")) if depth == 0: - break + f.mark_as_escaped() + return space.wrap(f) depth -= 1 f = ec.getnextframe_nohidden(f) - f.mark_as_escaped() - return space.wrap(f) + @unwrap_spec(new_limit="c_int") def setrecursionlimit(space, new_limit): diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py --- a/pypy/objspace/std/listobject.py +++ b/pypy/objspace/std/listobject.py @@ -412,7 +412,7 @@ # No more items to compare -- compare sizes return space.newbool(op(self.length(), w_list2.length())) - return func_with_new_name(compare_unwrappeditems, name + '__List_List') + return func_with_new_name(compare_unwrappeditems, 'descr_' + name) descr_lt = _make_list_comparison('lt') descr_le = _make_list_comparison('le') diff --git a/pypy/objspace/std/stringtype.py b/pypy/objspace/std/stringtype.py --- a/pypy/objspace/std/stringtype.py +++ b/pypy/objspace/std/stringtype.py @@ -1,13 +1,14 @@ +from sys import maxint + +from rpython.rlib import jit +from rpython.rlib.objectmodel import specialize + from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.basestringtype import basestring_typedef from pypy.objspace.std.register_all import register_all -from sys import maxint -from rpython.rlib.objectmodel import specialize -from rpython.rlib.jit import we_are_jitted - def wrapstr(space, s): from pypy.objspace.std.stringobject import W_StringObject if space.config.objspace.std.sharesmallstr: @@ -27,7 +28,7 @@ def wrapchar(space, c): from pypy.objspace.std.stringobject import W_StringObject - if space.config.objspace.std.withprebuiltchar and not we_are_jitted(): + if space.config.objspace.std.withprebuiltchar and not jit.we_are_jitted(): return W_StringObject.PREBUILT[ord(c)] else: return W_StringObject(c) @@ -293,11 +294,13 @@ str_typedef.registermethods(globals()) + # ____________________________________________________________ # Helpers for several string implementations @specialize.argtype(0) + at jit.elidable def stringendswith(u_self, suffix, start, end): begin = end - len(suffix) if begin < start: @@ -308,6 +311,7 @@ return True @specialize.argtype(0) + at jit.elidable def stringstartswith(u_self, prefix, start, end): stop = start + len(prefix) if stop > end: diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -156,7 +156,7 @@ iteritems = self._fields.iteritems() if not we_are_translated(): #random order is fine, except for tests iteritems = list(iteritems) - iteritems.sort(key = lambda (x,y): x.sort_key()) + iteritems.sort(key=lambda (x, y): x.sort_key()) for ofs, value in iteritems: if value.is_null(): continue @@ -353,7 +353,7 @@ # random order is fine, except for tests if not we_are_translated(): iteritems = list(iteritems) - iteritems.sort(key = lambda (x, y): x.sort_key()) + iteritems.sort(key=lambda (x, y): x.sort_key()) for descr, value in iteritems: subbox = value.force_box(optforce) op = ResOperation(rop.SETINTERIORFIELD_GC, @@ -426,7 +426,7 @@ if not we_are_translated(): op.name = 'FORCE ' + self.source_op.name optforce.emit_operation(self.source_op) - self.box = box = self.source_op.result + self.box = self.source_op.result for i in range(len(self.buffer.offsets)): # get a pointer to self.box+offset offset = self.buffer.offsets[i] @@ -533,8 +533,6 @@ self.emit_operation(op) def optimize_VIRTUAL_REF(self, op): - indexbox = op.getarg(1) - # # get some constants vrefinfo = self.optimizer.metainterp_sd.virtualref_info c_cls = vrefinfo.jit_virtual_ref_const_class @@ -570,7 +568,7 @@ objbox = op.getarg(1) if not CONST_NULL.same_constant(objbox): seo(ResOperation(rop.SETFIELD_GC, op.getarglist(), None, - descr = vrefinfo.descr_forced)) + descr=vrefinfo.descr_forced)) # - set 'virtual_token' to TOKEN_NONE (== NULL) args = [op.getarg(0), CONST_NULL] diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -1158,6 +1158,7 @@ obj = box.getref_base() vref = vrefinfo.virtual_ref_during_tracing(obj) resbox = history.BoxPtr(vref) + self.metainterp.heapcache.new(resbox) cindex = history.ConstInt(len(metainterp.virtualref_boxes) // 2) metainterp.history.record(rop.VIRTUAL_REF, [box, cindex], resbox) # Note: we allocate a JIT_VIRTUAL_REF here From noreply at buildbot.pypy.org Tue May 28 21:44:23 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 21:44:23 +0200 (CEST) Subject: [pypy-commit] pypy operrfmt-NT: close to be merged branch Message-ID: <20130528194423.CCE8F1C021A@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: operrfmt-NT Changeset: r64634:57ba2cfdb9e4 Date: 2013-05-28 12:39 -0700 http://bitbucket.org/pypy/pypy/changeset/57ba2cfdb9e4/ Log: close to be merged branch From noreply at buildbot.pypy.org Tue May 28 21:44:25 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 21:44:25 +0200 (CEST) Subject: [pypy-commit] pypy default: merge operrfmt-NT, adds convenient %N/%T format specifiers to operationerrfmt, Message-ID: <20130528194425.C45DF1C021A@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64635:60bfce6f9a92 Date: 2013-05-28 12:42 -0700 http://bitbucket.org/pypy/pypy/changeset/60bfce6f9a92/ Log: merge operrfmt-NT, adds convenient %N/%T format specifiers to operationerrfmt, though mostly for the sake of abstracting away/fixing str handling for py3k diff too long, truncating to 2000 out of 2538 lines diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -86,12 +86,9 @@ args_w = space.fixedview(w_stararg) except OperationError, e: if e.match(space, space.w_TypeError): - w_type = space.type(w_stararg) - typename = w_type.getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap("argument after * must be " - "a sequence, not %s" % (typename,))) + "argument after * must be a sequence, not %T", w_stararg) raise self.arguments_w = self.arguments_w + args_w @@ -116,12 +113,10 @@ w_keys = space.call_method(w_starstararg, "keys") except OperationError, e: if e.match(space, space.w_AttributeError): - w_type = space.type(w_starstararg) - typename = w_type.getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap("argument after ** must be " - "a mapping, not %s" % (typename,))) + "argument after ** must be a mapping, not %T", + w_starstararg) raise keys_w = space.unpackiterable(w_keys) keywords_w = [None] * len(keys_w) diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2793,8 +2793,7 @@ def Module_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2835,8 +2834,7 @@ def Interactive_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2881,8 +2879,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Expression_set_body(space, w_self, w_new_value): @@ -2925,8 +2922,7 @@ def Suite_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2971,8 +2967,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def stmt_set_lineno(space, w_self, w_new_value): @@ -2993,8 +2988,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def stmt_set_col_offset(space, w_self, w_new_value): @@ -3024,8 +3018,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def FunctionDef_set_name(space, w_self, w_new_value): @@ -3046,8 +3039,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') return space.wrap(w_self.args) def FunctionDef_set_args(space, w_self, w_new_value): @@ -3064,8 +3056,7 @@ def FunctionDef_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3081,8 +3072,7 @@ def FunctionDef_get_decorator_list(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'decorator_list') if w_self.w_decorator_list is None: if w_self.decorator_list is None: list_w = [] @@ -3131,8 +3121,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def ClassDef_set_name(space, w_self, w_new_value): @@ -3149,8 +3138,7 @@ def ClassDef_get_bases(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'bases') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'bases') if w_self.w_bases is None: if w_self.bases is None: list_w = [] @@ -3166,8 +3154,7 @@ def ClassDef_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3183,8 +3170,7 @@ def ClassDef_get_decorator_list(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'decorator_list') if w_self.w_decorator_list is None: if w_self.decorator_list is None: list_w = [] @@ -3234,8 +3220,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Return_set_value(space, w_self, w_new_value): @@ -3278,8 +3263,7 @@ def Delete_get_targets(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'targets') if w_self.w_targets is None: if w_self.targets is None: list_w = [] @@ -3320,8 +3304,7 @@ def Assign_get_targets(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'targets') if w_self.w_targets is None: if w_self.targets is None: list_w = [] @@ -3341,8 +3324,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Assign_set_value(space, w_self, w_new_value): @@ -3391,8 +3373,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def AugAssign_set_target(space, w_self, w_new_value): @@ -3415,8 +3396,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return operator_to_class[w_self.op - 1]() def AugAssign_set_op(space, w_self, w_new_value): @@ -3439,8 +3419,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def AugAssign_set_value(space, w_self, w_new_value): @@ -3489,8 +3468,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dest') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'dest') return space.wrap(w_self.dest) def Print_set_dest(space, w_self, w_new_value): @@ -3509,8 +3487,7 @@ def Print_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -3530,8 +3507,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'nl') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'nl') return space.wrap(w_self.nl) def Print_set_nl(space, w_self, w_new_value): @@ -3579,8 +3555,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def For_set_target(space, w_self, w_new_value): @@ -3603,8 +3578,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'iter') return space.wrap(w_self.iter) def For_set_iter(space, w_self, w_new_value): @@ -3623,8 +3597,7 @@ def For_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3640,8 +3613,7 @@ def For_get_orelse(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3690,8 +3662,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def While_set_test(space, w_self, w_new_value): @@ -3710,8 +3681,7 @@ def While_get_body(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3727,8 +3697,7 @@ def While_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3776,8 +3745,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def If_set_test(space, w_self, w_new_value): @@ -3796,8 +3764,7 @@ def If_get_body(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3813,8 +3780,7 @@ def If_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3862,8 +3828,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'context_expr') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'context_expr') return space.wrap(w_self.context_expr) def With_set_context_expr(space, w_self, w_new_value): @@ -3886,8 +3851,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'optional_vars') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'optional_vars') return space.wrap(w_self.optional_vars) def With_set_optional_vars(space, w_self, w_new_value): @@ -3906,8 +3870,7 @@ def With_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3954,8 +3917,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'type') return space.wrap(w_self.type) def Raise_set_type(space, w_self, w_new_value): @@ -3978,8 +3940,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'inst') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'inst') return space.wrap(w_self.inst) def Raise_set_inst(space, w_self, w_new_value): @@ -4002,8 +3963,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'tback') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'tback') return space.wrap(w_self.tback) def Raise_set_tback(space, w_self, w_new_value): @@ -4048,8 +4008,7 @@ def TryExcept_get_body(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -4065,8 +4024,7 @@ def TryExcept_get_handlers(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'handlers') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'handlers') if w_self.w_handlers is None: if w_self.handlers is None: list_w = [] @@ -4082,8 +4040,7 @@ def TryExcept_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -4128,8 +4085,7 @@ def TryFinally_get_body(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -4145,8 +4101,7 @@ def TryFinally_get_finalbody(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'finalbody') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'finalbody') if w_self.w_finalbody is None: if w_self.finalbody is None: list_w = [] @@ -4193,8 +4148,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def Assert_set_test(space, w_self, w_new_value): @@ -4217,8 +4171,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'msg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'msg') return space.wrap(w_self.msg) def Assert_set_msg(space, w_self, w_new_value): @@ -4262,8 +4215,7 @@ def Import_get_names(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4308,8 +4260,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'module') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'module') return space.wrap(w_self.module) def ImportFrom_set_module(space, w_self, w_new_value): @@ -4329,8 +4280,7 @@ def ImportFrom_get_names(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4350,8 +4300,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'level') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'level') return space.wrap(w_self.level) def ImportFrom_set_level(space, w_self, w_new_value): @@ -4399,8 +4348,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Exec_set_body(space, w_self, w_new_value): @@ -4423,8 +4371,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'globals') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'globals') return space.wrap(w_self.globals) def Exec_set_globals(space, w_self, w_new_value): @@ -4447,8 +4394,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'locals') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'locals') return space.wrap(w_self.locals) def Exec_set_locals(space, w_self, w_new_value): @@ -4493,8 +4439,7 @@ def Global_get_names(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4539,8 +4484,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Expr_set_value(space, w_self, w_new_value): @@ -4638,8 +4582,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def expr_set_lineno(space, w_self, w_new_value): @@ -4660,8 +4603,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def expr_set_col_offset(space, w_self, w_new_value): @@ -4691,8 +4633,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return boolop_to_class[w_self.op - 1]() def BoolOp_set_op(space, w_self, w_new_value): @@ -4711,8 +4652,7 @@ def BoolOp_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -4758,8 +4698,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'left') return space.wrap(w_self.left) def BinOp_set_left(space, w_self, w_new_value): @@ -4782,8 +4721,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return operator_to_class[w_self.op - 1]() def BinOp_set_op(space, w_self, w_new_value): @@ -4806,8 +4744,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'right') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'right') return space.wrap(w_self.right) def BinOp_set_right(space, w_self, w_new_value): @@ -4856,8 +4793,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return unaryop_to_class[w_self.op - 1]() def UnaryOp_set_op(space, w_self, w_new_value): @@ -4880,8 +4816,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'operand') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'operand') return space.wrap(w_self.operand) def UnaryOp_set_operand(space, w_self, w_new_value): @@ -4929,8 +4864,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') return space.wrap(w_self.args) def Lambda_set_args(space, w_self, w_new_value): @@ -4951,8 +4885,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Lambda_set_body(space, w_self, w_new_value): @@ -5000,8 +4933,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def IfExp_set_test(space, w_self, w_new_value): @@ -5024,8 +4956,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def IfExp_set_body(space, w_self, w_new_value): @@ -5048,8 +4979,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') return space.wrap(w_self.orelse) def IfExp_set_orelse(space, w_self, w_new_value): @@ -5094,8 +5024,7 @@ def Dict_get_keys(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keys') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'keys') if w_self.w_keys is None: if w_self.keys is None: list_w = [] @@ -5111,8 +5040,7 @@ def Dict_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -5155,8 +5083,7 @@ def Set_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -5201,8 +5128,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def ListComp_set_elt(space, w_self, w_new_value): @@ -5221,8 +5147,7 @@ def ListComp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5268,8 +5193,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def SetComp_set_elt(space, w_self, w_new_value): @@ -5288,8 +5212,7 @@ def SetComp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5335,8 +5258,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'key') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'key') return space.wrap(w_self.key) def DictComp_set_key(space, w_self, w_new_value): @@ -5359,8 +5281,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def DictComp_set_value(space, w_self, w_new_value): @@ -5379,8 +5300,7 @@ def DictComp_get_generators(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5427,8 +5347,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def GeneratorExp_set_elt(space, w_self, w_new_value): @@ -5447,8 +5366,7 @@ def GeneratorExp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5494,8 +5412,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Yield_set_value(space, w_self, w_new_value): @@ -5542,8 +5459,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'left') return space.wrap(w_self.left) def Compare_set_left(space, w_self, w_new_value): @@ -5562,8 +5478,7 @@ def Compare_get_ops(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ops') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ops') if w_self.w_ops is None: if w_self.ops is None: list_w = [] @@ -5579,8 +5494,7 @@ def Compare_get_comparators(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'comparators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'comparators') if w_self.w_comparators is None: if w_self.comparators is None: list_w = [] @@ -5628,8 +5542,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'func') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'func') return space.wrap(w_self.func) def Call_set_func(space, w_self, w_new_value): @@ -5648,8 +5561,7 @@ def Call_get_args(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') if w_self.w_args is None: if w_self.args is None: list_w = [] @@ -5665,8 +5577,7 @@ def Call_get_keywords(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keywords') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'keywords') if w_self.w_keywords is None: if w_self.keywords is None: list_w = [] @@ -5686,8 +5597,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'starargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'starargs') return space.wrap(w_self.starargs) def Call_set_starargs(space, w_self, w_new_value): @@ -5710,8 +5620,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 64: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwargs') return space.wrap(w_self.kwargs) def Call_set_kwargs(space, w_self, w_new_value): @@ -5764,8 +5673,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Repr_set_value(space, w_self, w_new_value): @@ -5812,8 +5720,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'n') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'n') return w_self.n def Num_set_n(space, w_self, w_new_value): @@ -5858,8 +5765,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 's') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 's') return w_self.s def Str_set_s(space, w_self, w_new_value): @@ -5904,8 +5810,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Attribute_set_value(space, w_self, w_new_value): @@ -5928,8 +5833,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'attr') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'attr') return space.wrap(w_self.attr) def Attribute_set_attr(space, w_self, w_new_value): @@ -5950,8 +5854,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Attribute_set_ctx(space, w_self, w_new_value): @@ -6000,8 +5903,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Subscript_set_value(space, w_self, w_new_value): @@ -6024,8 +5926,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'slice') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'slice') return space.wrap(w_self.slice) def Subscript_set_slice(space, w_self, w_new_value): @@ -6048,8 +5949,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Subscript_set_ctx(space, w_self, w_new_value): @@ -6098,8 +5998,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'id') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'id') return space.wrap(w_self.id) def Name_set_id(space, w_self, w_new_value): @@ -6120,8 +6019,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Name_set_ctx(space, w_self, w_new_value): @@ -6165,8 +6063,7 @@ def List_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -6186,8 +6083,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def List_set_ctx(space, w_self, w_new_value): @@ -6232,8 +6128,7 @@ def Tuple_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -6253,8 +6148,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Tuple_set_ctx(space, w_self, w_new_value): @@ -6303,8 +6197,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return w_self.value def Const_set_value(space, w_self, w_new_value): @@ -6422,8 +6315,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lower') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lower') return space.wrap(w_self.lower) def Slice_set_lower(space, w_self, w_new_value): @@ -6446,8 +6338,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'upper') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'upper') return space.wrap(w_self.upper) def Slice_set_upper(space, w_self, w_new_value): @@ -6470,8 +6361,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'step') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'step') return space.wrap(w_self.step) def Slice_set_step(space, w_self, w_new_value): @@ -6516,8 +6406,7 @@ def ExtSlice_get_dims(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dims') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'dims') if w_self.w_dims is None: if w_self.dims is None: list_w = [] @@ -6562,8 +6451,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Index_set_value(space, w_self, w_new_value): @@ -6834,8 +6722,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def comprehension_set_target(space, w_self, w_new_value): @@ -6858,8 +6745,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'iter') return space.wrap(w_self.iter) def comprehension_set_iter(space, w_self, w_new_value): @@ -6878,8 +6764,7 @@ def comprehension_get_ifs(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ifs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ifs') if w_self.w_ifs is None: if w_self.ifs is None: list_w = [] @@ -6926,8 +6811,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def excepthandler_set_lineno(space, w_self, w_new_value): @@ -6948,8 +6832,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def excepthandler_set_col_offset(space, w_self, w_new_value): @@ -6979,8 +6862,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'type') return space.wrap(w_self.type) def ExceptHandler_set_type(space, w_self, w_new_value): @@ -7003,8 +6885,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def ExceptHandler_set_name(space, w_self, w_new_value): @@ -7023,8 +6904,7 @@ def ExceptHandler_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -7067,8 +6947,7 @@ def arguments_get_args(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') if w_self.w_args is None: if w_self.args is None: list_w = [] @@ -7088,8 +6967,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'vararg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'vararg') return space.wrap(w_self.vararg) def arguments_set_vararg(space, w_self, w_new_value): @@ -7113,8 +6991,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwarg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwarg') return space.wrap(w_self.kwarg) def arguments_set_kwarg(space, w_self, w_new_value): @@ -7134,8 +7011,7 @@ def arguments_get_defaults(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'defaults') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'defaults') if w_self.w_defaults is None: if w_self.defaults is None: list_w = [] @@ -7184,8 +7060,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'arg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'arg') return space.wrap(w_self.arg) def keyword_set_arg(space, w_self, w_new_value): @@ -7206,8 +7081,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def keyword_set_value(space, w_self, w_new_value): @@ -7255,8 +7129,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') return space.wrap(w_self.name) def alias_set_name(space, w_self, w_new_value): @@ -7277,8 +7150,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'asname') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'asname') return space.wrap(w_self.asname) def alias_set_asname(space, w_self, w_new_value): diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -409,8 +409,7 @@ self.emit(" if w_obj is not None:", 1) self.emit(" return w_obj", 1) self.emit("if not w_self.initialization_state & %s:" % (flag,), 1) - self.emit("typename = space.type(w_self).getname(space)", 2) - self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%s' object has no attribute '%%s'\", typename, '%s')" % + self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%T' object has no attribute '%%s'\", w_self, '%s')" % (field.name,), 2) if field.seq: self.emit("if w_self.w_%s is None:" % (field.name,), 1) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -12,7 +12,7 @@ from pypy.interpreter.executioncontext import (ExecutionContext, ActionFlag, UserDelAction, FrameTraceAction) from pypy.interpreter.error import (OperationError, operationerrfmt, - new_exception_class, typed_unwrap_error_msg) + new_exception_class) from pypy.interpreter.argument import Arguments from pypy.interpreter.miscutils import ThreadLocals @@ -61,10 +61,9 @@ return False def setdict(self, space, w_dict): - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "attribute '__dict__' of %s objects " - "is not writable", typename) + "attribute '__dict__' of %T objects " + "is not writable", self) # to be used directly only by space.type implementations def getclass(self, space): @@ -124,9 +123,8 @@ classname = '?' else: classname = wrappable_class_name(RequiredClass) - msg = "'%s' object expected, got '%s' instead" - raise operationerrfmt(space.w_TypeError, msg, - classname, self.getclass(space).getname(space)) + msg = "'%s' object expected, got '%T' instead" + raise operationerrfmt(space.w_TypeError, msg, classname, self) # used by _weakref implemenation @@ -134,9 +132,8 @@ return None def setweakref(self, space, weakreflifeline): - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "cannot create weak reference to '%s' object", typename) + "cannot create weak reference to '%T' object", self) def delweakref(self): pass @@ -200,44 +197,39 @@ return None def str_w(self, space): - w_msg = typed_unwrap_error_msg(space, "string", self) - raise OperationError(space.w_TypeError, w_msg) + self._typed_unwrap_error(space, "string") def unicode_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "unicode", self)) + self._typed_unwrap_error(space, "unicode") def int_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "integer", self)) + self._typed_unwrap_error(space, "integer") def float_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "float", self)) + self._typed_unwrap_error(space, "float") def uint_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "integer", self)) + self._typed_unwrap_error(space, "integer") def bigint_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "integer", self)) + self._typed_unwrap_error(space, "integer") + + def _typed_unwrap_error(self, space, expected): + raise operationerrfmt(space.w_TypeError, "expected %s, got %T object", + expected, self) def int(self, space): w_impl = space.lookup(self, '__int__') if w_impl is None: - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "unsupported operand type for int(): '%s'", - typename) + "unsupported operand type for int(): '%T'", self) w_result = space.get_and_call_function(w_impl, self) if (space.isinstance_w(w_result, space.w_int) or space.isinstance_w(w_result, space.w_long)): return w_result - typename = space.type(w_result).getname(space) - msg = "__int__ returned non-int (type '%s')" - raise operationerrfmt(space.w_TypeError, msg, typename) + msg = "__int__ returned non-int (type '%T')" + raise operationerrfmt(space.w_TypeError, msg, w_result) def __spacebind__(self, space): return self @@ -749,10 +741,9 @@ if can_be_None and self.is_none(w_obj): return None if not isinstance(w_obj, RequiredClass): # or obj is None - msg = "'%s' object expected, got '%s' instead" + msg = "'%s' object expected, got '%N' instead" raise operationerrfmt(self.w_TypeError, msg, - wrappable_class_name(RequiredClass), - w_obj.getclass(self).getname(self)) + wrappable_class_name(RequiredClass), w_obj.getclass(self)) return w_obj interp_w._annspecialcase_ = 'specialize:arg(1)' @@ -1221,9 +1212,8 @@ except OperationError, err: if objdescr is None or not err.match(self, self.w_TypeError): raise - msg = "%s must be an integer, not %s" - raise operationerrfmt(self.w_TypeError, msg, - objdescr, self.type(w_obj).getname(self)) + msg = "%s must be an integer, not %T" + raise operationerrfmt(self.w_TypeError, msg, objdescr, w_obj) try: index = self.int_w(w_index) except OperationError, err: @@ -1237,9 +1227,8 @@ return sys.maxint else: raise operationerrfmt( - w_exception, - "cannot fit '%s' into an index-sized " - "integer", self.type(w_obj).getname(self)) + w_exception, "cannot fit '%T' into an index-sized integer", + w_obj) else: return index diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -1,4 +1,5 @@ import cStringIO +import itertools import os import sys import traceback @@ -59,7 +60,9 @@ "NOT_RPYTHON: Convenience for tracebacks." s = self._w_value if self.__class__ is not OperationError and s is None: - s = self._compute_value() + space = getattr(self.w_type, 'space') + if space is not None: + s = self._compute_value(space) return '[%s: %s]' % (self.w_type, s) def errorstr(self, space, use_repr=False): @@ -224,10 +227,9 @@ def _exception_getclass(self, space, w_inst): w_type = space.exception_getclass(w_inst) if not space.exception_is_valid_class_w(w_type): - typename = w_type.getname(space) msg = ("exceptions must be old-style classes or derived " - "from BaseException, not %s") - raise operationerrfmt(space.w_TypeError, msg, typename) + "from BaseException, not %N") + raise operationerrfmt(space.w_TypeError, msg, w_type) return w_type def write_unraisable(self, space, where, w_object=None, @@ -267,11 +269,11 @@ def get_w_value(self, space): w_value = self._w_value if w_value is None: - value = self._compute_value() + value = self._compute_value(space) self._w_value = w_value = space.wrap(value) return w_value - def _compute_value(self): + def _compute_value(self, space): raise NotImplementedError def get_traceback(self): @@ -305,6 +307,7 @@ _fmtcache = {} _fmtcache2 = {} +_FMTS = tuple('dsNT') def decompose_valuefmt(valuefmt): """Returns a tuple of string parts extracted from valuefmt, @@ -313,7 +316,7 @@ parts = valuefmt.split('%') i = 1 while i < len(parts): - if parts[i].startswith('s') or parts[i].startswith('d'): + if parts[i].startswith(_FMTS): formats.append(parts[i][0]) parts[i] = parts[i][1:] i += 1 @@ -321,7 +324,9 @@ parts[i-1] += '%' + parts[i+1] del parts[i:i+2] else: - raise ValueError("invalid format string (only %s or %d supported)") + fmts = '%%%s or %%%s' % (', %'.join(_FMTS[:-1]), _FMTS[-1]) + raise ValueError("invalid format string (only %s supported)" % + fmts) assert len(formats) > 0, "unsupported: no % command found" return tuple(parts), tuple(formats) @@ -333,24 +338,29 @@ except KeyError: from rpython.rlib.unroll import unrolling_iterable attrs = ['x%d' % i for i in range(len(formats))] - entries = unrolling_iterable(enumerate(attrs)) + entries = unrolling_iterable(zip(itertools.count(), formats, attrs)) class OpErrFmt(OperationError): def __init__(self, w_type, strings, *args): self.setup(w_type) assert len(args) == len(strings) - 1 self.xstrings = strings - for i, attr in entries: + for i, _, attr in entries: setattr(self, attr, args[i]) assert w_type is not None - def _compute_value(self): + def _compute_value(self, space): lst = [None] * (len(formats) + len(formats) + 1) - for i, attr in entries: - string = self.xstrings[i] + for i, fmt, attr in entries: + lst[i + i] = self.xstrings[i] value = getattr(self, attr) - lst[i+i] = string - lst[i+i+1] = str(value) + if fmt in 'NT': + if fmt == 'T': + value = space.type(value) + result = value.getname(space) + else: + result = str(value) + lst[i + i + 1] = result lst[-1] = self.xstrings[-1] return ''.join(lst) # @@ -368,7 +378,14 @@ def operationerrfmt(w_type, valuefmt, *args): """Equivalent to OperationError(w_type, space.wrap(valuefmt % args)). More efficient in the (common) case where the value is not actually - needed.""" + needed. + + Supports the standard %s and %d formats, plus the following: + + %N - The result of w_arg.getname(space) + %T - The result of space.type(w_arg).getname(space) + + """ OpErrFmt, strings = get_operationerr_class(valuefmt) return OpErrFmt(w_type, strings, *args) operationerrfmt._annspecialcase_ = 'specialize:arg(1)' @@ -477,7 +494,3 @@ if module: space.setattr(w_exc, space.wrap("__module__"), space.wrap(module)) return w_exc - -def typed_unwrap_error_msg(space, expected, w_obj): - type_name = space.type(w_obj).getname(space) - return space.wrap("expected %s, got %s object" % (expected, type_name)) diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -915,10 +915,9 @@ w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") if w_enter is None or w_descr is None: - typename = self.space.type(w_manager).getname(self.space) raise operationerrfmt(self.space.w_AttributeError, - "'%s' object is not a context manager" - " (no __enter__/__exit__ method)", typename) + "'%T' object is not a context manager" + " (no __enter__/__exit__ method)", w_manager) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) w_result = self.space.get_and_call_function(w_enter, w_manager) diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -12,27 +12,55 @@ assert (decompose_valuefmt("%s%d%%%s") == (("", "", "%", ""), ('s', 'd', 's'))) -def test_get_operrcls2(): +def test_get_operrcls2(space): cls, strings = get_operrcls2('abc %s def %d') assert strings == ("abc ", " def ", "") assert issubclass(cls, OperationError) inst = cls("w_type", strings, "hello", 42) - assert inst._compute_value() == "abc hello def 42" + assert inst._compute_value(space) == "abc hello def 42" cls2, strings2 = get_operrcls2('a %s b %d c') assert cls2 is cls # caching assert strings2 == ("a ", " b ", " c") -def test_operationerrfmt(): +def test_operationerrfmt(space): operr = operationerrfmt("w_type", "abc %s def %d", "foo", 42) assert isinstance(operr, OperationError) assert operr.w_type == "w_type" assert operr._w_value is None - assert operr._compute_value() == "abc foo def 42" + assert operr._compute_value(space) == "abc foo def 42" operr2 = operationerrfmt("w_type2", "a %s b %d c", "bar", 43) assert operr2.__class__ is operr.__class__ operr3 = operationerrfmt("w_type2", "a %s b %s c", "bar", "4b") assert operr3.__class__ is not operr.__class__ +def test_operationerrfmt_T(space): + operr = operationerrfmt(space.w_AttributeError, + "'%T' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%T' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + +def test_operationerrfmt_N(space): + operr = operationerrfmt(space.w_AttributeError, + "'%N' object has no attribute '%s'", + space.type(space.wrap('foo')), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%N' object has no attribute '%s'", + space.type(space.wrap('foo')), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + operr = operationerrfmt(space.w_AttributeError, + "'%N' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'?' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%N' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'?' object has no attribute 'foo'" + def test_operationerrfmt_empty(): py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -553,12 +553,9 @@ def typecheck(self, space, w_obj): if not space.isinstance_w(w_obj, self.w_cls): - raise operationerrfmt(space.w_TypeError, - "descriptor '%s' for '%s'" - " objects doesn't apply to '%s' object", - self.name, - self.w_cls.name, - space.type(w_obj).getname(space)) + m = "descriptor '%s' for '%s' objects doesn't apply to '%T' object" + raise operationerrfmt(space.w_TypeError, m, + self.name, self.w_cls.name, w_obj) def descr_member_get(self, space, w_obj, w_cls=None): """member.__get__(obj[, type]) -> value @@ -627,10 +624,8 @@ def descr_get_dict(space, w_obj): w_dict = w_obj.getdict(space) if w_dict is None: - typename = space.type(w_obj).getname(space) - raise operationerrfmt(space.w_TypeError, - "descriptor '__dict__' doesn't apply to" - " '%s' objects", typename) + msg = "descriptor '__dict__' doesn't apply to '%T' objects" + raise operationerrfmt(space.w_TypeError, msg, w_obj) return w_dict def descr_set_dict(space, w_obj, w_dict): diff --git a/pypy/module/__builtin__/interp_classobj.py b/pypy/module/__builtin__/interp_classobj.py --- a/pypy/module/__builtin__/interp_classobj.py +++ b/pypy/module/__builtin__/interp_classobj.py @@ -10,10 +10,8 @@ def raise_type_err(space, argument, expected, w_obj): - type_name = space.type(w_obj).getname(space) - raise operationerrfmt(space.w_TypeError, - "argument %s must be %s, not %s", - argument, expected, type_name) + raise operationerrfmt(space.w_TypeError, "argument %s must be %s, not %T", + argument, expected, w_obj) def unwrap_attr(space, w_attr): try: diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -27,8 +27,8 @@ # if not space.is_true(space.callable(w_callable)): raise operationerrfmt(space.w_TypeError, - "expected a callable object, not %s", - space.type(w_callable).getname(space)) + "expected a callable object, not %T", + w_callable) self.w_callable = w_callable # fresult = self.getfunctype().ctitem 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 @@ -54,8 +54,8 @@ else: raise operationerrfmt(space.w_TypeError, "argument %d passed in the variadic part " - "needs to be a cdata object (got %s)", - i + 1, space.type(w_obj).getname(space)) + "needs to be a cdata object (got %T)", + i + 1, w_obj) fvarargs[i] = ct ctypefunc = instantiate(W_CTypeFunc) ctypefunc.space = space 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 @@ -88,8 +88,7 @@ else: return operationerrfmt(space.w_TypeError, "initializer for ctype '%s' must be a %s, " - "not %s", self.name, expected, - space.type(w_got).getname(space)) + "not %T", self.name, expected, w_got) def _cannot_index(self): space = self.space diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -218,9 +218,8 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def xmlcharrefreplace_errors(space, w_exc): check_exception(space, w_exc) @@ -239,9 +238,8 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def backslashreplace_errors(space, w_exc): check_exception(space, w_exc) @@ -272,9 +270,8 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def register_builtin_error_handlers(space): "NOT_RPYTHON" diff --git a/pypy/module/_io/interp_bytesio.py b/pypy/module/_io/interp_bytesio.py --- a/pypy/module/_io/interp_bytesio.py +++ b/pypy/module/_io/interp_bytesio.py @@ -138,10 +138,8 @@ if space.len_w(w_state) != 3: raise operationerrfmt(space.w_TypeError, - "%s.__setstate__ argument should be 3-tuple, got %s", - space.type(self).getname(space), - space.type(w_state).getname(space) - ) + "%T.__setstate__ argument should be 3-tuple, got %T", + self, w_state) w_content, w_pos, w_dict = space.unpackiterable(w_state, 3) self.truncate(0) self.write_w(space, w_content) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -180,8 +180,8 @@ if not space.isinstance_w(w_readahead, space.w_str): raise operationerrfmt( space.w_IOError, - "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space)) + "peek() should have returned a bytes object, not '%T'", + w_readahead) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -206,8 +206,8 @@ if not space.isinstance_w(w_read, space.w_str): raise operationerrfmt( space.w_IOError, - "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space)) + "peek() should have returned a bytes object, not '%T'", + w_read) read = space.str_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -71,10 +71,8 @@ # backwards-compatibility if not space.isinstance_w(w_state, space.w_tuple) or space.len_w(w_state) < 4: raise operationerrfmt(space.w_TypeError, - "%s.__setstate__ argument should be a 4-tuple, got %s", - space.type(self).getname(space), - space.type(w_state).getname(space) - ) + "%T.__setstate__ argument should be a 4-tuple, got %T", + self, w_state) w_initval, w_readnl, w_pos, w_dict = space.unpackiterable(w_state, 4) # Initialize state self.descr_init(space, w_initval, w_readnl) @@ -98,9 +96,8 @@ if not space.is_w(w_dict, space.w_None): if not space.isinstance_w(w_dict, space.w_dict): raise operationerrfmt(space.w_TypeError, - "fourth item of state should be a dict, got a %s", - space.type(w_dict).getname(space) - ) + "fourth item of state should be a dict, got a %T", + w_dict) # Alternatively, we could replace the internal dictionary # completely. However, it seems more practical to just update it. space.call_method(self.w_dict, "update", w_dict) @@ -129,8 +126,8 @@ def write_w(self, space, w_obj): if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, - "unicode argument expected, got '%s'", - space.type(w_obj).getname(space)) + "unicode argument expected, got '%T'", + w_obj) self._check_closed(space) orig_size = space.len_w(w_obj) 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 @@ -31,9 +31,8 @@ try: name = space.str_w(l_w[0]) except OperationError: - raise OperationError(space.w_TypeError, space.wrap( - "structure field name must be string not %s" % - space.type(l_w[0]).getname(space))) + raise operationerrfmt(space.w_TypeError, + "structure field name must be string not %T", l_w[0]) tp = unpack_shape_with_length(space, l_w[1]) if len_l == 3: diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -1,6 +1,6 @@ import sys -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rarithmetic import r_singlefloat @@ -430,9 +430,8 @@ offset = capi.c_base_offset(space, w_obj.cppclass, self.cppclass, rawobject, 1) obj_address = capi.direct_ptradd(rawobject, offset) return rffi.cast(capi.C_OBJECT, obj_address) - raise OperationError(space.w_TypeError, - space.wrap("cannot pass %s as %s" % - (space.type(w_obj).getname(space, "?"), self.cppclass.name))) + raise operationerrfmt(space.w_TypeError, "cannot pass %T as %s", + w_obj, self.cppclass.name) def convert_argument(self, space, w_obj, address, call_local): x = rffi.cast(rffi.VOIDPP, address) diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -153,8 +153,9 @@ is the equivalent of the Python statement o[i] = v. This function does not steal a reference to v.""" if PyDict_Check(space, w_o) or not PySequence_Check(space, w_o): - raise operationerrfmt(space.w_TypeError, "'%s' object does not support item assignment", - space.type(w_o).getname(space)) + raise operationerrfmt(space.w_TypeError, + "'%T' object does not support item assignment", + w_o) space.setitem(w_o, space.wrap(i), w_v) return 0 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 @@ -274,11 +274,9 @@ if not space.is_true(space.issubtype(space.type(w_self), space.type(w_other))): - raise OperationError(space.w_TypeError, space.wrap( - "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'" % - (space.type(w_self).getname(space), - space.type(w_self).getname(space), - space.type(w_other).getname(space)))) + raise operationerrfmt(space.w_TypeError, + "%T.__cmp__(x,y) requires y to be a '%T', not a '%T'", + w_self, w_self, w_other) return space.wrap(generic_cpy_call(space, func_target, w_self, w_other)) diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -115,9 +115,9 @@ _attrs_ = () def descr__new__(space, w_subtype, __args__): - raise operationerrfmt(space.w_TypeError, "cannot create '%s' instances", - w_subtype.getname(space, '?') - ) + raise operationerrfmt(space.w_TypeError, + "cannot create '%N' instances", + w_subtype) def get_dtype(self, space): return self._get_dtype(space) diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py --- a/pypy/module/micronumpy/interp_dtype.py +++ b/pypy/module/micronumpy/interp_dtype.py @@ -1,7 +1,7 @@ import sys from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.interpreter.typedef import (TypeDef, GetSetProperty, interp_attrproperty, interp_attrproperty_w) @@ -401,10 +401,8 @@ return dtype if w_dtype is dtype.w_box_type: return dtype - typename = space.type(w_dtype).getname(space) - raise OperationError(space.w_TypeError, space.wrap( - "data type not understood (value of type " + - "%s not expected here)" % typename)) From noreply at buildbot.pypy.org Tue May 28 22:00:55 2013 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 28 May 2013 22:00:55 +0200 (CEST) Subject: [pypy-commit] pypy default: passing test Message-ID: <20130528200055.77EC61C13C1@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r64636:a8943ada15ee Date: 2013-05-28 22:00 +0200 http://bitbucket.org/pypy/pypy/changeset/a8943ada15ee/ Log: passing test 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 @@ -830,6 +830,30 @@ out = cbuilder.cmdexec('') assert out.strip() == '789' + def test_llhelper_stored_in_struct(self): + from rpython.rtyper.annlowlevel import llhelper + + def f(x): + return x + 3 + + FUNC_TP = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) + + S = lltype.GcStruct('s', ('f', FUNC_TP)) + + class Glob(object): + pass + + glob = Glob() + + def entry_point(argv): + x = llhelper(FUNC_TP, f) + s = lltype.malloc(S) + s.f = x + glob.s = s # escape + return 0 + + self.compile(entry_point) + # assert did not explode class TestMaemo(TestStandalone): def setup_class(cls): From noreply at buildbot.pypy.org Tue May 28 23:44:57 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:44:57 +0200 (CEST) Subject: [pypy-commit] pypy default: utillize %N Message-ID: <20130528214457.4C6351C021A@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64638:bcfcca1e51e3 Date: 2013-05-28 14:16 -0700 http://bitbucket.org/pypy/pypy/changeset/bcfcca1e51e3/ Log: utillize %N diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -364,8 +364,8 @@ instance.user_setup(self, w_subtype) else: raise operationerrfmt(self.w_TypeError, - "%s.__new__(%s): only for the type %s", - w_type.name, w_subtype.getname(self), w_type.name) + "%N.__new__(%N): only for the type %N", + w_type, w_subtype, w_type) return instance allocate_instance._annspecialcase_ = "specialize:arg(1)" From noreply at buildbot.pypy.org Tue May 28 23:44:56 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:44:56 +0200 (CEST) Subject: [pypy-commit] pypy default: document logging-perf/operrfmt-NT Message-ID: <20130528214456.50F691C00BD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64637:309a4880f4c8 Date: 2013-05-28 13:15 -0700 http://bitbucket.org/pypy/pypy/changeset/309a4880f4c8/ Log: document logging-perf/operrfmt-NT 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 @@ -40,3 +40,9 @@ .. branch: on-abort-resops Added list of resops to the pypyjit on_abort hook. + +.. branch: logging-perf +Speeds up the stdlib logging module + +.. branch: operrfmt-NT +Adds a couple convenient format specifiers to operationerrfmt From noreply at buildbot.pypy.org Tue May 28 23:44:58 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:44:58 +0200 (CEST) Subject: [pypy-commit] pypy default: add a %R format to operationerrfmt Message-ID: <20130528214458.2E8131C13C1@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64639:16b26a59745a Date: 2013-05-28 14:34 -0700 http://bitbucket.org/pypy/pypy/changeset/16b26a59745a/ Log: add a %R format to operationerrfmt diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -307,7 +307,7 @@ _fmtcache = {} _fmtcache2 = {} -_FMTS = tuple('dsNT') +_FMTS = tuple('NRTds') def decompose_valuefmt(valuefmt): """Returns a tuple of string parts extracted from valuefmt, @@ -354,7 +354,9 @@ for i, fmt, attr in entries: lst[i + i] = self.xstrings[i] value = getattr(self, attr) - if fmt in 'NT': + if fmt == 'R': + result = space.str_w(space.repr(value)) + elif fmt in 'NT': if fmt == 'T': value = space.type(value) result = value.getname(space) @@ -383,6 +385,7 @@ Supports the standard %s and %d formats, plus the following: %N - The result of w_arg.getname(space) + %R - The result of space.str_w(space.repr(w_arg)) %T - The result of space.type(w_arg).getname(space) """ diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -61,8 +61,14 @@ space.wrap('foo'), 'foo') assert operr._compute_value(space) == "'?' object has no attribute 'foo'" -def test_operationerrfmt_empty(): - py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") +def test_operationerrfmt_R(space): + operr = operationerrfmt(space.w_ValueError, "illegal newline value: %R", + space.wrap('foo')) + assert operr._compute_value(space) == "illegal newline value: 'foo'" + operr = operationerrfmt(space.w_ValueError, "illegal newline value: %R", + space.wrap("'PyLadies'")) + expected = "illegal newline value: \"'PyLadies'\"" + assert operr._compute_value(space) == expected def test_errorstr(space): operr = OperationError(space.w_ValueError, space.wrap("message")) diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -52,13 +52,11 @@ space.w_unicode)): if decode: msg = ("decoding error handler must return " - "(unicode, int) tuple, not %s") + "(unicode, int) tuple, not %R") else: msg = ("encoding error handler must return " - "(unicode, int) tuple, not %s") - raise operationerrfmt( - space.w_TypeError, msg, - space.str_w(space.repr(w_res))) + "(unicode, int) tuple, not %R") + raise operationerrfmt(space.w_TypeError, msg, w_res) w_replace, w_newpos = space.fixedview(w_res, 2) newpos = space.int_w(w_newpos) if newpos < 0: diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -42,9 +42,7 @@ if not (space.isinstance_w(w_file, space.w_basestring) or space.isinstance_w(w_file, space.w_int) or space.isinstance_w(w_file, space.w_long)): - raise operationerrfmt(space.w_TypeError, - "invalid file: %s", space.str_w(space.repr(w_file)) - ) + raise operationerrfmt(space.w_TypeError, "invalid file: %R", w_file) reading = writing = appending = updating = text = binary = universal = False From noreply at buildbot.pypy.org Tue May 28 23:44:59 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:44:59 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130528214459.7AB531C00BD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64640:187c60b13262 Date: 2013-05-28 13:24 -0700 http://bitbucket.org/pypy/pypy/changeset/187c60b13262/ Log: merge default diff too long, truncating to 2000 out of 2600 lines diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -88,12 +88,9 @@ args_w = space.fixedview(w_stararg) except OperationError, e: if e.match(space, space.w_TypeError): - w_type = space.type(w_stararg) - typename = w_type.getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap("argument after * must be " - "a sequence, not %s" % (typename,))) + "argument after * must be a sequence, not %T", w_stararg) raise self.arguments_w = self.arguments_w + args_w @@ -118,12 +115,10 @@ w_keys = space.call_method(w_starstararg, "keys") except OperationError, e: if e.match(space, space.w_AttributeError): - w_type = space.type(w_starstararg) - typename = w_type.getname(space) - raise OperationError( + raise operationerrfmt( space.w_TypeError, - space.wrap("argument after ** must be " - "a mapping, not %s" % (typename,))) + "argument after ** must be a mapping, not %T", + w_starstararg) raise keys_w = space.unpackiterable(w_keys) keywords_w = [None] * len(keys_w) diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py --- a/pypy/interpreter/astcompiler/ast.py +++ b/pypy/interpreter/astcompiler/ast.py @@ -2872,8 +2872,7 @@ def Module_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2914,8 +2913,7 @@ def Interactive_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -2960,8 +2958,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Expression_set_body(space, w_self, w_new_value): @@ -3004,8 +3001,7 @@ def Suite_get_body(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3050,8 +3046,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def stmt_set_lineno(space, w_self, w_new_value): @@ -3072,8 +3067,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def stmt_set_col_offset(space, w_self, w_new_value): @@ -3103,8 +3097,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') if w_self.name is None: return space.w_None return space.wrap(w_self.name.decode('utf-8')) @@ -3127,8 +3120,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') return space.wrap(w_self.args) def FunctionDef_set_args(space, w_self, w_new_value): @@ -3145,8 +3137,7 @@ def FunctionDef_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3162,8 +3153,7 @@ def FunctionDef_get_decorator_list(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'decorator_list') if w_self.w_decorator_list is None: if w_self.decorator_list is None: list_w = [] @@ -3183,8 +3173,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 64: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'returns') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'returns') return space.wrap(w_self.returns) def FunctionDef_set_returns(space, w_self, w_new_value): @@ -3237,8 +3226,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') if w_self.name is None: return space.w_None return space.wrap(w_self.name.decode('utf-8')) @@ -3257,8 +3245,7 @@ def ClassDef_get_bases(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'bases') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'bases') if w_self.w_bases is None: if w_self.bases is None: list_w = [] @@ -3274,8 +3261,7 @@ def ClassDef_get_keywords(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keywords') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'keywords') if w_self.w_keywords is None: if w_self.keywords is None: list_w = [] @@ -3295,8 +3281,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'starargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'starargs') return space.wrap(w_self.starargs) def ClassDef_set_starargs(space, w_self, w_new_value): @@ -3319,8 +3304,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 64: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwargs') return space.wrap(w_self.kwargs) def ClassDef_set_kwargs(space, w_self, w_new_value): @@ -3339,8 +3323,7 @@ def ClassDef_get_body(space, w_self): if not w_self.initialization_state & 128: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3356,8 +3339,7 @@ def ClassDef_get_decorator_list(space, w_self): if not w_self.initialization_state & 256: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'decorator_list') if w_self.w_decorator_list is None: if w_self.decorator_list is None: list_w = [] @@ -3411,8 +3393,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Return_set_value(space, w_self, w_new_value): @@ -3455,8 +3436,7 @@ def Delete_get_targets(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'targets') if w_self.w_targets is None: if w_self.targets is None: list_w = [] @@ -3497,8 +3477,7 @@ def Assign_get_targets(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'targets') if w_self.w_targets is None: if w_self.targets is None: list_w = [] @@ -3518,8 +3497,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Assign_set_value(space, w_self, w_new_value): @@ -3568,8 +3546,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def AugAssign_set_target(space, w_self, w_new_value): @@ -3592,8 +3569,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return operator_to_class[w_self.op - 1]() def AugAssign_set_op(space, w_self, w_new_value): @@ -3616,8 +3592,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def AugAssign_set_value(space, w_self, w_new_value): @@ -3666,8 +3641,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def For_set_target(space, w_self, w_new_value): @@ -3690,8 +3664,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'iter') return space.wrap(w_self.iter) def For_set_iter(space, w_self, w_new_value): @@ -3710,8 +3683,7 @@ def For_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3727,8 +3699,7 @@ def For_get_orelse(space, w_self): if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3777,8 +3748,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def While_set_test(space, w_self, w_new_value): @@ -3797,8 +3767,7 @@ def While_get_body(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3814,8 +3783,7 @@ def While_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3863,8 +3831,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def If_set_test(space, w_self, w_new_value): @@ -3883,8 +3850,7 @@ def If_get_body(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -3900,8 +3866,7 @@ def If_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -3949,8 +3914,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'context_expr') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'context_expr') return space.wrap(w_self.context_expr) def With_set_context_expr(space, w_self, w_new_value): @@ -3973,8 +3937,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'optional_vars') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'optional_vars') return space.wrap(w_self.optional_vars) def With_set_optional_vars(space, w_self, w_new_value): @@ -3993,8 +3956,7 @@ def With_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -4041,8 +4003,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'exc') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'exc') return space.wrap(w_self.exc) def Raise_set_exc(space, w_self, w_new_value): @@ -4065,8 +4026,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'cause') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'cause') return space.wrap(w_self.cause) def Raise_set_cause(space, w_self, w_new_value): @@ -4110,8 +4070,7 @@ def TryExcept_get_body(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -4127,8 +4086,7 @@ def TryExcept_get_handlers(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'handlers') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'handlers') if w_self.w_handlers is None: if w_self.handlers is None: list_w = [] @@ -4144,8 +4102,7 @@ def TryExcept_get_orelse(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') if w_self.w_orelse is None: if w_self.orelse is None: list_w = [] @@ -4190,8 +4147,7 @@ def TryFinally_get_body(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -4207,8 +4163,7 @@ def TryFinally_get_finalbody(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'finalbody') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'finalbody') if w_self.w_finalbody is None: if w_self.finalbody is None: list_w = [] @@ -4255,8 +4210,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def Assert_set_test(space, w_self, w_new_value): @@ -4279,8 +4233,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'msg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'msg') return space.wrap(w_self.msg) def Assert_set_msg(space, w_self, w_new_value): @@ -4324,8 +4277,7 @@ def Import_get_names(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4370,8 +4322,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'module') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'module') if w_self.module is None: return space.w_None return space.wrap(w_self.module.decode('utf-8')) @@ -4393,8 +4344,7 @@ def ImportFrom_get_names(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4414,8 +4364,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'level') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'level') return space.wrap(w_self.level) def ImportFrom_set_level(space, w_self, w_new_value): @@ -4459,8 +4408,7 @@ def Global_get_names(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4501,8 +4449,7 @@ def Nonlocal_get_names(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'names') if w_self.w_names is None: if w_self.names is None: list_w = [] @@ -4547,8 +4494,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Expr_set_value(space, w_self, w_new_value): @@ -4646,8 +4592,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def expr_set_lineno(space, w_self, w_new_value): @@ -4668,8 +4613,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def expr_set_col_offset(space, w_self, w_new_value): @@ -4699,8 +4643,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return boolop_to_class[w_self.op - 1]() def BoolOp_set_op(space, w_self, w_new_value): @@ -4719,8 +4662,7 @@ def BoolOp_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -4766,8 +4708,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'left') return space.wrap(w_self.left) def BinOp_set_left(space, w_self, w_new_value): @@ -4790,8 +4731,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return operator_to_class[w_self.op - 1]() def BinOp_set_op(space, w_self, w_new_value): @@ -4814,8 +4754,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'right') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'right') return space.wrap(w_self.right) def BinOp_set_right(space, w_self, w_new_value): @@ -4864,8 +4803,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'op') return unaryop_to_class[w_self.op - 1]() def UnaryOp_set_op(space, w_self, w_new_value): @@ -4888,8 +4826,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'operand') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'operand') return space.wrap(w_self.operand) def UnaryOp_set_operand(space, w_self, w_new_value): @@ -4937,8 +4874,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') return space.wrap(w_self.args) def Lambda_set_args(space, w_self, w_new_value): @@ -4959,8 +4895,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def Lambda_set_body(space, w_self, w_new_value): @@ -5008,8 +4943,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'test') return space.wrap(w_self.test) def IfExp_set_test(space, w_self, w_new_value): @@ -5032,8 +4966,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') return space.wrap(w_self.body) def IfExp_set_body(space, w_self, w_new_value): @@ -5056,8 +4989,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'orelse') return space.wrap(w_self.orelse) def IfExp_set_orelse(space, w_self, w_new_value): @@ -5102,8 +5034,7 @@ def Dict_get_keys(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keys') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'keys') if w_self.w_keys is None: if w_self.keys is None: list_w = [] @@ -5119,8 +5050,7 @@ def Dict_get_values(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'values') if w_self.w_values is None: if w_self.values is None: list_w = [] @@ -5163,8 +5093,7 @@ def Set_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -5209,8 +5138,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def ListComp_set_elt(space, w_self, w_new_value): @@ -5229,8 +5157,7 @@ def ListComp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5276,8 +5203,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def SetComp_set_elt(space, w_self, w_new_value): @@ -5296,8 +5222,7 @@ def SetComp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5343,8 +5268,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'key') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'key') return space.wrap(w_self.key) def DictComp_set_key(space, w_self, w_new_value): @@ -5367,8 +5291,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def DictComp_set_value(space, w_self, w_new_value): @@ -5387,8 +5310,7 @@ def DictComp_get_generators(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5435,8 +5357,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elt') return space.wrap(w_self.elt) def GeneratorExp_set_elt(space, w_self, w_new_value): @@ -5455,8 +5376,7 @@ def GeneratorExp_get_generators(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'generators') if w_self.w_generators is None: if w_self.generators is None: list_w = [] @@ -5502,8 +5422,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Yield_set_value(space, w_self, w_new_value): @@ -5550,8 +5469,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'left') return space.wrap(w_self.left) def Compare_set_left(space, w_self, w_new_value): @@ -5570,8 +5488,7 @@ def Compare_get_ops(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ops') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ops') if w_self.w_ops is None: if w_self.ops is None: list_w = [] @@ -5587,8 +5504,7 @@ def Compare_get_comparators(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'comparators') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'comparators') if w_self.w_comparators is None: if w_self.comparators is None: list_w = [] @@ -5636,8 +5552,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'func') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'func') return space.wrap(w_self.func) def Call_set_func(space, w_self, w_new_value): @@ -5656,8 +5571,7 @@ def Call_get_args(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') if w_self.w_args is None: if w_self.args is None: list_w = [] @@ -5673,8 +5587,7 @@ def Call_get_keywords(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keywords') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'keywords') if w_self.w_keywords is None: if w_self.keywords is None: list_w = [] @@ -5694,8 +5607,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'starargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'starargs') return space.wrap(w_self.starargs) def Call_set_starargs(space, w_self, w_new_value): @@ -5718,8 +5630,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 64: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwargs') return space.wrap(w_self.kwargs) def Call_set_kwargs(space, w_self, w_new_value): @@ -5772,8 +5683,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'n') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'n') return w_self.n def Num_set_n(space, w_self, w_new_value): @@ -5818,8 +5728,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 's') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 's') return w_self.s def Str_set_s(space, w_self, w_new_value): @@ -5864,8 +5773,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 's') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 's') return w_self.s def Bytes_set_s(space, w_self, w_new_value): @@ -5927,8 +5835,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Attribute_set_value(space, w_self, w_new_value): @@ -5951,8 +5858,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'attr') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'attr') if w_self.attr is None: return space.w_None return space.wrap(w_self.attr.decode('utf-8')) @@ -5975,8 +5881,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Attribute_set_ctx(space, w_self, w_new_value): @@ -6025,8 +5930,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Subscript_set_value(space, w_self, w_new_value): @@ -6049,8 +5953,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'slice') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'slice') return space.wrap(w_self.slice) def Subscript_set_slice(space, w_self, w_new_value): @@ -6073,8 +5976,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Subscript_set_ctx(space, w_self, w_new_value): @@ -6123,8 +6025,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Starred_set_value(space, w_self, w_new_value): @@ -6147,8 +6048,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Starred_set_ctx(space, w_self, w_new_value): @@ -6196,8 +6096,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'id') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'id') if w_self.id is None: return space.w_None return space.wrap(w_self.id.decode('utf-8')) @@ -6220,8 +6119,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Name_set_ctx(space, w_self, w_new_value): @@ -6265,8 +6163,7 @@ def List_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -6286,8 +6183,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def List_set_ctx(space, w_self, w_new_value): @@ -6332,8 +6228,7 @@ def Tuple_get_elts(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'elts') if w_self.w_elts is None: if w_self.elts is None: list_w = [] @@ -6353,8 +6248,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ctx') return expr_context_to_class[w_self.ctx - 1]() def Tuple_set_ctx(space, w_self, w_new_value): @@ -6403,8 +6297,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return w_self.value def Const_set_value(space, w_self, w_new_value): @@ -6505,8 +6398,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lower') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lower') return space.wrap(w_self.lower) def Slice_set_lower(space, w_self, w_new_value): @@ -6529,8 +6421,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'upper') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'upper') return space.wrap(w_self.upper) def Slice_set_upper(space, w_self, w_new_value): @@ -6553,8 +6444,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'step') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'step') return space.wrap(w_self.step) def Slice_set_step(space, w_self, w_new_value): @@ -6599,8 +6489,7 @@ def ExtSlice_get_dims(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dims') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'dims') if w_self.w_dims is None: if w_self.dims is None: list_w = [] @@ -6645,8 +6534,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def Index_set_value(space, w_self, w_new_value): @@ -6917,8 +6805,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'target') return space.wrap(w_self.target) def comprehension_set_target(space, w_self, w_new_value): @@ -6941,8 +6828,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'iter') return space.wrap(w_self.iter) def comprehension_set_iter(space, w_self, w_new_value): @@ -6961,8 +6847,7 @@ def comprehension_get_ifs(space, w_self): if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ifs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'ifs') if w_self.w_ifs is None: if w_self.ifs is None: list_w = [] @@ -7009,8 +6894,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'lineno') return space.wrap(w_self.lineno) def excepthandler_set_lineno(space, w_self, w_new_value): @@ -7031,8 +6915,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'col_offset') return space.wrap(w_self.col_offset) def excepthandler_set_col_offset(space, w_self, w_new_value): @@ -7062,8 +6945,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'type') return space.wrap(w_self.type) def ExceptHandler_set_type(space, w_self, w_new_value): @@ -7086,8 +6968,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') if w_self.name is None: return space.w_None return space.wrap(w_self.name.decode('utf-8')) @@ -7109,8 +6990,7 @@ def ExceptHandler_get_body(space, w_self): if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'body') if w_self.w_body is None: if w_self.body is None: list_w = [] @@ -7153,8 +7033,7 @@ def arguments_get_args(space, w_self): if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'args') if w_self.w_args is None: if w_self.args is None: list_w = [] @@ -7174,8 +7053,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'vararg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'vararg') if w_self.vararg is None: return space.w_None return space.wrap(w_self.vararg.decode('utf-8')) @@ -7201,8 +7079,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 4: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'varargannotation') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'varargannotation') return space.wrap(w_self.varargannotation) def arguments_set_varargannotation(space, w_self, w_new_value): @@ -7221,8 +7098,7 @@ def arguments_get_kwonlyargs(space, w_self): if not w_self.initialization_state & 8: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwonlyargs') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwonlyargs') if w_self.w_kwonlyargs is None: if w_self.kwonlyargs is None: list_w = [] @@ -7242,8 +7118,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 16: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwarg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwarg') if w_self.kwarg is None: return space.w_None return space.wrap(w_self.kwarg.decode('utf-8')) @@ -7269,8 +7144,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 32: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargannotation') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kwargannotation') return space.wrap(w_self.kwargannotation) def arguments_set_kwargannotation(space, w_self, w_new_value): @@ -7289,8 +7163,7 @@ def arguments_get_defaults(space, w_self): if not w_self.initialization_state & 64: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'defaults') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'defaults') if w_self.w_defaults is None: if w_self.defaults is None: list_w = [] @@ -7306,8 +7179,7 @@ def arguments_get_kw_defaults(space, w_self): if not w_self.initialization_state & 128: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kw_defaults') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'kw_defaults') if w_self.w_kw_defaults is None: if w_self.kw_defaults is None: list_w = [] @@ -7362,8 +7234,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'arg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'arg') if w_self.arg is None: return space.w_None return space.wrap(w_self.arg.decode('utf-8')) @@ -7386,8 +7257,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'annotation') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'annotation') return space.wrap(w_self.annotation) def arg_set_annotation(space, w_self, w_new_value): @@ -7435,8 +7305,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'arg') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'arg') if w_self.arg is None: return space.w_None return space.wrap(w_self.arg.decode('utf-8')) @@ -7459,8 +7328,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'value') return space.wrap(w_self.value) def keyword_set_value(space, w_self, w_new_value): @@ -7508,8 +7376,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 1: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'name') if w_self.name is None: return space.w_None return space.wrap(w_self.name.decode('utf-8')) @@ -7532,8 +7399,7 @@ if w_obj is not None: return w_obj if not w_self.initialization_state & 2: - typename = space.type(w_self).getname(space) - raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'asname') + raise operationerrfmt(space.w_AttributeError, "'%T' object has no attribute '%s'", w_self, 'asname') if w_self.asname is None: return space.w_None return space.wrap(w_self.asname.decode('utf-8')) diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py --- a/pypy/interpreter/astcompiler/tools/asdl_py.py +++ b/pypy/interpreter/astcompiler/tools/asdl_py.py @@ -416,8 +416,7 @@ self.emit(" if w_obj is not None:", 1) self.emit(" return w_obj", 1) self.emit("if not w_self.initialization_state & %s:" % (flag,), 1) - self.emit("typename = space.type(w_self).getname(space)", 2) - self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%s' object has no attribute '%%s'\", typename, '%s')" % + self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%T' object has no attribute '%%s'\", w_self, '%s')" % (field.name,), 2) if field.seq: self.emit("if w_self.w_%s is None:" % (field.name,), 1) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -12,7 +12,7 @@ from pypy.interpreter.executioncontext import (ExecutionContext, ActionFlag, UserDelAction, FrameTraceAction) from pypy.interpreter.error import (OperationError, operationerrfmt, - new_exception_class, typed_unwrap_error_msg) + new_exception_class) from pypy.interpreter.argument import Arguments from pypy.interpreter.miscutils import ThreadLocals @@ -61,10 +61,9 @@ return False def setdict(self, space, w_dict): - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "attribute '__dict__' of %s objects " - "is not writable", typename) + "attribute '__dict__' of %T objects " + "is not writable", self) # to be used directly only by space.type implementations def getclass(self, space): @@ -124,9 +123,8 @@ classname = '?' else: classname = wrappable_class_name(RequiredClass) - msg = "'%s' object expected, got '%s' instead" - raise operationerrfmt(space.w_TypeError, msg, - classname, self.getclass(space).getname(space)) + msg = "'%s' object expected, got '%T' instead" + raise operationerrfmt(space.w_TypeError, msg, classname, self) # used by _weakref implemenation @@ -134,9 +132,8 @@ return None def setweakref(self, space, weakreflifeline): - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "cannot create weak reference to '%s' object", typename) + "cannot create weak reference to '%T' object", self) def delweakref(self): pass @@ -200,47 +197,41 @@ return None def bytes_w(self, space): - w_msg = typed_unwrap_error_msg(space, "bytes", self) - raise OperationError(space.w_TypeError, w_msg) + self._typed_unwrap_error(space, "bytes") def unicode_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "string", self)) + self._typed_unwrap_error(space, "string") def identifier_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "string", self)) + self._typed_unwrap_error(space, "string") def int_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "integer", self)) + self._typed_unwrap_error(space, "integer") def float_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "float", self)) + self._typed_unwrap_error(space, "float") def uint_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "integer", self)) + self._typed_unwrap_error(space, "integer") def bigint_w(self, space): - raise OperationError(space.w_TypeError, - typed_unwrap_error_msg(space, "integer", self)) + self._typed_unwrap_error(space, "integer") + + def _typed_unwrap_error(self, space, expected): + raise operationerrfmt(space.w_TypeError, "expected %s, got %T object", + expected, self) def int(self, space): w_impl = space.lookup(self, '__int__') if w_impl is None: - typename = space.type(self).getname(space) raise operationerrfmt(space.w_TypeError, - "unsupported operand type for int(): '%s'", - typename) + "unsupported operand type for int(): '%T'", self) w_result = space.get_and_call_function(w_impl, self) if space.isinstance_w(w_result, space.w_int): return w_result - typename = space.type(w_result).getname(space) - msg = "__int__ returned non-int (type '%s')" - raise operationerrfmt(space.w_TypeError, msg, typename) + msg = "__int__ returned non-int (type '%T')" + raise operationerrfmt(space.w_TypeError, msg, w_result) def __spacebind__(self, space): return self @@ -763,10 +754,9 @@ if can_be_None and self.is_none(w_obj): return None if not isinstance(w_obj, RequiredClass): # or obj is None - msg = "'%s' object expected, got '%s' instead" + msg = "'%s' object expected, got '%N' instead" raise operationerrfmt(self.w_TypeError, msg, - wrappable_class_name(RequiredClass), - w_obj.getclass(self).getname(self)) + wrappable_class_name(RequiredClass), w_obj.getclass(self)) return w_obj interp_w._annspecialcase_ = 'specialize:arg(1)' @@ -1198,9 +1188,8 @@ except OperationError, err: if objdescr is None or not err.match(self, self.w_TypeError): raise - msg = "%s must be an integer, not %s" - raise operationerrfmt(self.w_TypeError, msg, - objdescr, self.type(w_obj).getname(self)) + msg = "%s must be an integer, not %T" + raise operationerrfmt(self.w_TypeError, msg, objdescr, w_obj) try: index = self.int_w(w_index) except OperationError, err: @@ -1214,9 +1203,8 @@ return sys.maxint else: raise operationerrfmt( - w_exception, - "cannot fit '%s' into an index-sized " - "integer", self.type(w_obj).getname(self)) + w_exception, "cannot fit '%T' into an index-sized integer", + w_obj) else: return index diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -93,7 +93,9 @@ "NOT_RPYTHON: Convenience for tracebacks." s = self._w_value if self.__class__ is not OperationError and s is None: - s = self._compute_value() + space = getattr(self.w_type, 'space') + if space is not None: + s = self._compute_value(space) return '[%s: %s]' % (self.w_type, s) def __repr__(self): @@ -270,9 +272,8 @@ def _exception_getclass(self, space, w_inst, what="exceptions"): w_type = space.exception_getclass(w_inst) if not space.exception_is_valid_class_w(w_type): - typename = w_type.getname(space) - msg = "%s must derive from BaseException, not %s" - raise operationerrfmt(space.w_TypeError, msg, what, typename) + msg = "%s must derive from BaseException, not %N" + raise operationerrfmt(space.w_TypeError, msg, what, w_type) return w_type def write_unraisable(self, space, where, w_object=None, @@ -316,11 +317,11 @@ def get_w_value(self, space): w_value = self._w_value if w_value is None: - value = self._compute_value() + value = self._compute_value(space) self._w_value = w_value = space.wrap(value) return w_value - def _compute_value(self): + def _compute_value(self, space): raise NotImplementedError def get_traceback(self): @@ -354,6 +355,7 @@ _fmtcache = {} _fmtcache2 = {} +_FMTS = tuple('8dsNT') def decompose_valuefmt(valuefmt): """Returns a tuple of string parts extracted from valuefmt, @@ -362,8 +364,7 @@ parts = valuefmt.split('%') i = 1 while i < len(parts): - if (parts[i].startswith('s') or parts[i].startswith('d') or - parts[i].startswith('8')): + if parts[i].startswith(_FMTS): formats.append(parts[i][0]) parts[i] = parts[i][1:] i += 1 @@ -371,7 +372,9 @@ parts[i-1] += '%' + parts[i+1] del parts[i:i+2] else: - raise ValueError("invalid format string (only %s, %d or %8 supported)") + fmts = '%%%s or %%%s' % (', %'.join(_FMTS[:-1]), _FMTS[-1]) + raise ValueError("invalid format string (only %s supported)" % + fmts) assert len(formats) > 0, "unsupported: no % command found" return tuple(parts), tuple(formats) @@ -391,24 +394,29 @@ def __init__(self, w_type, strings, *args): assert len(args) == len(strings) - 1 self.xstrings = strings - for i, fmt, attr in entries: + for i, _, attr in entries: setattr(self, attr, args[i]) assert w_type is not None self.setup(w_type) - def _compute_value(self): + def _compute_value(self, space): lst = [None] * (len(formats) + len(formats) + 1) for i, fmt, attr in entries: - string = self.xstrings[i] + lst[i + i] = self.xstrings[i] value = getattr(self, attr) - lst[i+i] = string if fmt == 'd': - lst[i+i+1] = str(value).decode('ascii') + result = str(value).decode('ascii') elif fmt == '8': - univalue, _ = str_decode_utf_8(value, len(value), 'strict') - lst[i+i+1] = univalue + result, _ = str_decode_utf_8(value, len(value), + 'strict') + elif fmt in 'NT': + if fmt == 'T': + value = space.type(value) + # XXX: + result = value.getname(space).decode('utf-8') else: - lst[i+i+1] = unicode(value) + result = unicode(value) + lst[i + i + 1] = result lst[-1] = self.xstrings[-1] return u''.join(lst) # @@ -426,10 +434,15 @@ def operationerrfmt(w_type, valuefmt, *args): """Equivalent to OperationError(w_type, space.wrap(valuefmt % args)). More efficient in the (common) case where the value is not actually - needed. - Note that: - 1. in the py3k branch the exception message will always be unicode - 2. only %s and %d are supported + needed. Note that in the py3k branch the exception message will + always be unicode. + + Supports the standard %s and %d formats, plus the following: + + %8 - The result of arg.decode('utf-8', 'strict') + %N - The result of w_arg.getname(space) + %T - The result of space.type(w_arg).getname(space) + """ OpErrFmt, strings = get_operationerr_class(valuefmt) return OpErrFmt(w_type, strings, *args) @@ -539,7 +552,3 @@ if module: space.setattr(w_exc, space.wrap("__module__"), space.wrap(module)) return w_exc - -def typed_unwrap_error_msg(space, expected, w_obj): - type_name = space.type(w_obj).getname(space) - return space.wrap("expected %s, got %s object" % (expected, type_name)) diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -902,10 +902,9 @@ w_enter = self.space.lookup(w_manager, "__enter__") w_descr = self.space.lookup(w_manager, "__exit__") if w_enter is None or w_descr is None: - typename = self.space.type(w_manager).getname(self.space) raise operationerrfmt(self.space.w_AttributeError, - "'%s' object is not a context manager" - " (no __enter__/__exit__ method)", typename) + "'%T' object is not a context manager" + " (no __enter__/__exit__ method)", w_manager) w_exit = self.space.get(w_descr, w_manager) self.settopvalue(w_exit) w_result = self.space.get_and_call_function(w_enter, w_manager) diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -14,22 +14,22 @@ assert (decompose_valuefmt("%s%d%%%s") == (("", "", "%", ""), ('s', 'd', 's'))) -def test_get_operrcls2(): +def test_get_operrcls2(space): cls, strings = get_operrcls2('abc %s def %d') assert strings == ("abc ", " def ", "") assert issubclass(cls, OperationError) inst = cls("w_type", strings, "hello", 42) - assert inst._compute_value() == "abc hello def 42" + assert inst._compute_value(space) == "abc hello def 42" cls2, strings2 = get_operrcls2('a %s b %d c') assert cls2 is cls # caching assert strings2 == ("a ", " b ", " c") -def test_operationerrfmt(): +def test_operationerrfmt(space): operr = operationerrfmt("w_type", "abc %s def %d", "foo", 42) assert isinstance(operr, OperationError) assert operr.w_type == "w_type" assert operr._w_value is None - val = operr._compute_value() + val = operr._compute_value(space) assert val == u"abc foo def 42" assert isinstance(val, unicode) operr2 = operationerrfmt("w_type2", "a %s b %d c", "bar", 43) @@ -37,18 +37,46 @@ operr3 = operationerrfmt("w_type2", "a %s b %s c", "bar", "4b") assert operr3.__class__ is not operr.__class__ +def test_operationerrfmt_T(space): + operr = operationerrfmt(space.w_AttributeError, + "'%T' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%T' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + +def test_operationerrfmt_N(space): + operr = operationerrfmt(space.w_AttributeError, + "'%N' object has no attribute '%s'", + space.type(space.wrap('foo')), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%N' object has no attribute '%s'", + space.type(space.wrap('foo')), 'foo') + assert operr._compute_value(space) == "'str' object has no attribute 'foo'" + operr = operationerrfmt(space.w_AttributeError, + "'%N' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'?' object has no attribute 'foo'" + operr = operationerrfmt("w_type", + "'%N' object has no attribute '%s'", + space.wrap('foo'), 'foo') + assert operr._compute_value(space) == "'?' object has no attribute 'foo'" + def test_operationerrfmt_empty(): py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") -def test_operationerrfmt_unicode(): +def test_operationerrfmt_unicode(space): operr = operationerrfmt("w_type", "abc %s", u"àèìòù") - val = operr._compute_value() + val = operr._compute_value(space) assert val == u"abc àèìòù" -def test_operationerrfmt_utf8(): +def test_operationerrfmt_utf8(space): arg = u"àèìòù".encode('utf-8') operr = operationerrfmt("w_type", "abc %8", arg) - val = operr._compute_value() + val = operr._compute_value(space) assert val == u"abc àèìòù" def test_errorstr(space): diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py --- a/pypy/interpreter/typedef.py +++ b/pypy/interpreter/typedef.py @@ -565,12 +565,9 @@ def typecheck(self, space, w_obj): if not space.isinstance_w(w_obj, self.w_cls): - raise operationerrfmt(space.w_TypeError, - "descriptor '%s' for '%s'" - " objects doesn't apply to '%s' object", - self.name, - self.w_cls.name, - space.type(w_obj).getname(space)) + m = "descriptor '%s' for '%s' objects doesn't apply to '%T' object" + raise operationerrfmt(space.w_TypeError, m, + self.name, self.w_cls.name, w_obj) def descr_member_get(self, space, w_obj, w_cls=None): """member.__get__(obj[, type]) -> value @@ -639,10 +636,8 @@ def descr_get_dict(space, w_obj): w_dict = w_obj.getdict(space) if w_dict is None: - typename = space.type(w_obj).getname(space) - raise operationerrfmt(space.w_TypeError, - "descriptor '__dict__' doesn't apply to" - " '%s' objects", typename) + msg = "descriptor '__dict__' doesn't apply to '%T' objects" + raise operationerrfmt(space.w_TypeError, msg, w_obj) return w_dict def descr_set_dict(space, w_obj, w_dict): diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py --- a/pypy/module/_cffi_backend/ccallback.py +++ b/pypy/module/_cffi_backend/ccallback.py @@ -27,8 +27,8 @@ # if not space.is_true(space.callable(w_callable)): raise operationerrfmt(space.w_TypeError, - "expected a callable object, not %s", - space.type(w_callable).getname(space)) + "expected a callable object, not %T", + w_callable) self.w_callable = w_callable # fresult = self.getfunctype().ctitem 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 @@ -54,8 +54,8 @@ else: raise operationerrfmt(space.w_TypeError, "argument %d passed in the variadic part " - "needs to be a cdata object (got %s)", - i + 1, space.type(w_obj).getname(space)) + "needs to be a cdata object (got %T)", + i + 1, w_obj) fvarargs[i] = ct ctypefunc = instantiate(W_CTypeFunc) ctypefunc.space = space 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 @@ -88,8 +88,7 @@ else: return operationerrfmt(space.w_TypeError, "initializer for ctype '%s' must be a %s, " - "not %s", self.name, expected, - space.type(w_got).getname(space)) + "not %T", self.name, expected, w_got) def _cannot_index(self): space = self.space diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -235,9 +235,8 @@ text = u'\ufffd' * size return space.newtuple([space.wrap(text), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def xmlcharrefreplace_errors(space, w_exc): check_exception(space, w_exc) @@ -256,9 +255,8 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def backslashreplace_errors(space, w_exc): check_exception(space, w_exc) @@ -289,9 +287,8 @@ pos += 1 return space.newtuple([space.wrap(builder.build()), w_end]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", w_exc) def surrogatepass_errors(space, w_exc): check_exception(space, w_exc) diff --git a/pypy/module/_io/interp_bytesio.py b/pypy/module/_io/interp_bytesio.py --- a/pypy/module/_io/interp_bytesio.py +++ b/pypy/module/_io/interp_bytesio.py @@ -181,10 +181,8 @@ if space.len_w(w_state) != 3: raise operationerrfmt(space.w_TypeError, - "%s.__setstate__ argument should be 3-tuple, got %s", - space.type(self).getname(space), - space.type(w_state).getname(space) - ) + "%T.__setstate__ argument should be 3-tuple, got %T", + self, w_state) w_content, w_pos, w_dict = space.unpackiterable(w_state, 3) self.truncate(0) self.write_w(space, w_content) diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -196,8 +196,8 @@ if not space.isinstance_w(w_readahead, space.w_str): raise operationerrfmt( space.w_IOError, - "peek() should have returned a bytes object, " - "not '%s'", space.type(w_readahead).getname(space)) + "peek() should have returned a bytes object, not '%T'", + w_readahead) length = space.len_w(w_readahead) if length > 0: n = 0 @@ -222,8 +222,8 @@ if not space.isinstance_w(w_read, space.w_str): raise operationerrfmt( space.w_IOError, - "peek() should have returned a bytes object, " - "not '%s'", space.type(w_read).getname(space)) + "peek() should have returned a bytes object, not '%T'", + w_read) read = space.bytes_w(w_read) if not read: break diff --git a/pypy/module/_io/interp_stringio.py b/pypy/module/_io/interp_stringio.py --- a/pypy/module/_io/interp_stringio.py +++ b/pypy/module/_io/interp_stringio.py @@ -71,10 +71,8 @@ # backwards-compatibility if not space.isinstance_w(w_state, space.w_tuple) or space.len_w(w_state) < 4: raise operationerrfmt(space.w_TypeError, - "%s.__setstate__ argument should be a 4-tuple, got %s", - space.type(self).getname(space), - space.type(w_state).getname(space) - ) + "%T.__setstate__ argument should be a 4-tuple, got %T", + self, w_state) w_initval, w_readnl, w_pos, w_dict = space.unpackiterable(w_state, 4) # Initialize state self.descr_init(space, w_initval, w_readnl) @@ -98,9 +96,8 @@ if not space.is_w(w_dict, space.w_None): if not space.isinstance_w(w_dict, space.w_dict): raise operationerrfmt(space.w_TypeError, - "fourth item of state should be a dict, got a %s", - space.type(w_dict).getname(space) - ) + "fourth item of state should be a dict, got a %T", + w_dict) # Alternatively, we could replace the internal dictionary # completely. However, it seems more practical to just update it. space.call_method(self.w_dict, "update", w_dict) @@ -129,8 +126,8 @@ def write_w(self, space, w_obj): if not space.isinstance_w(w_obj, space.w_unicode): raise operationerrfmt(space.w_TypeError, - "unicode argument expected, got '%s'", - space.type(w_obj).getname(space)) + "unicode argument expected, got '%T'", + w_obj) self._check_closed(space) orig_size = space.len_w(w_obj) 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 @@ -31,9 +31,8 @@ try: name = space.str_w(l_w[0]) except OperationError: - raise OperationError(space.w_TypeError, space.wrap( - "structure field name must be string not %s" % - space.type(l_w[0]).getname(space))) + raise operationerrfmt(space.w_TypeError, + "structure field name must be string not %T", l_w[0]) tp = unpack_shape_with_length(space, l_w[1]) if len_l == 3: diff --git a/pypy/module/cppyy/converter.py b/pypy/module/cppyy/converter.py --- a/pypy/module/cppyy/converter.py +++ b/pypy/module/cppyy/converter.py @@ -1,6 +1,6 @@ import sys -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rarithmetic import r_singlefloat @@ -430,9 +430,8 @@ offset = capi.c_base_offset(space, w_obj.cppclass, self.cppclass, rawobject, 1) obj_address = capi.direct_ptradd(rawobject, offset) return rffi.cast(capi.C_OBJECT, obj_address) - raise OperationError(space.w_TypeError, - space.wrap("cannot pass %s as %s" % - (space.type(w_obj).getname(space, "?"), self.cppclass.name))) + raise operationerrfmt(space.w_TypeError, "cannot pass %T as %s", + w_obj, self.cppclass.name) def convert_argument(self, space, w_obj, address, call_local): x = rffi.cast(rffi.VOIDPP, address) diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -153,8 +153,9 @@ From noreply at buildbot.pypy.org Tue May 28 23:45:00 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:45:00 +0200 (CEST) Subject: [pypy-commit] pypy py3k: utilize %N/%T Message-ID: <20130528214500.7608C1C00BD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64641:1c0f22d3facb Date: 2013-05-28 14:35 -0700 http://bitbucket.org/pypy/pypy/changeset/1c0f22d3facb/ Log: utilize %N/%T diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1428,13 +1428,13 @@ if (not space.is_none(w_globals) and not space.isinstance_w(w_globals, space.w_dict)): raise operationerrfmt(space.w_TypeError, - '%s() arg 2 must be a dict, not %s', - funcname, space.type(w_globals).getname(space)) + '%s() arg 2 must be a dict, not %T', + funcname, w_globals) if (not space.is_none(w_locals) and space.lookup(w_locals, '__getitem__') is None): raise operationerrfmt(space.w_TypeError, - '%s() arg 3 must be a mapping or None, not %s', - funcname, space.type(w_locals).getname(space)) + '%s() arg 3 must be a mapping or None, not %T', + funcname, w_locals) if space.is_none(w_globals): if caller is None: diff --git a/pypy/module/__builtin__/operation.py b/pypy/module/__builtin__/operation.py --- a/pypy/module/__builtin__/operation.py +++ b/pypy/module/__builtin__/operation.py @@ -106,8 +106,8 @@ round = space.lookup(w_number, '__round__') if round is None: raise operationerrfmt(space.w_TypeError, - "type %s doesn't define __round__ method", - space.type(w_number).getname(space)) + "type %T doesn't define __round__ method", + w_number) if w_ndigits is None: return space.get_and_call_function(round, w_number) else: diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -331,9 +331,9 @@ raise OperationError(space.type(w_exc), w_exc) return space.newtuple([space.wrap(unichr(ch)), space.wrap(start + 3)]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %T in error callback", + w_exc) def surrogateescape_errors(space, w_exc): check_exception(space, w_exc) @@ -371,9 +371,9 @@ return space.newtuple([space.wrap(replace), space.wrap(start + consumed)]) else: - typename = space.type(w_exc).getname(space) raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", typename) + "don't know how to handle %s in error callback", + w_exc) def register_builtin_error_handlers(space): "NOT_RPYTHON" diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py --- a/pypy/module/_io/interp_iobase.py +++ b/pypy/module/_io/interp_iobase.py @@ -174,8 +174,7 @@ def getstate_w(self, space): raise operationerrfmt(space.w_TypeError, - "cannot serialize '%s' object", - space.type(self).getname(space)) + "cannot serialize '%T' object", self) # ______________________________________________________________ diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -244,10 +244,9 @@ w_restype = space.type(w_res) # Note there is no check for bool here because the only possible # instances of bool are w_False and w_True, which are checked above. - typename = space.type(w_obj).getname(space) raise operationerrfmt(space.w_TypeError, - "__bool__ should return bool, returned %s", - typename) + "__bool__ should return bool, returned %T", + w_obj) def nonzero(space, w_obj): if space.is_true(w_obj): @@ -479,10 +478,9 @@ def buffer(space, w_obj): w_impl = space.lookup(w_obj, '__buffer__') if w_impl is None: - typename = space.type(w_obj).getname(space) - raise operationerrfmt( - space.w_TypeError, - "'%s' does not support the buffer interface", typename) + raise operationerrfmt(space.w_TypeError, + "'%T' does not support the buffer interface", + w_obj) return space.get_and_call_function(w_impl, w_obj) @@ -601,11 +599,8 @@ return space.not_(space.eq(w_obj1, w_obj2)) # # if we arrived here, they are unorderable - typename1 = space.type(w_obj1).getname(space) - typename2 = space.type(w_obj2).getname(space) - raise operationerrfmt(space.w_TypeError, - "unorderable types: %s %s %s", - typename1, symbol, typename2) + raise operationerrfmt(space.w_TypeError, "unorderable types: %T %s %T", + w_obj1, symbol, w_obj2) return func_with_new_name(comparison_impl, 'comparison_%s_impl'%left.strip('_')) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -257,9 +257,8 @@ except OperationError as e: if e.match(space, space.w_TypeError): msg = ("%s first arg must be bytes or a tuple of bytes, " - "not %s") - typename = space.type(w_suffix).getname(space) - raise operationerrfmt(space.w_TypeError, msg, funcname, typename) + "not %T") + raise operationerrfmt(space.w_TypeError, msg, funcname, w_suffix) def str_startswith__Bytearray_ANY_ANY_ANY(space, w_bytearray, w_prefix, w_start, w_stop): if space.isinstance_w(w_prefix, space.w_tuple): diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -708,9 +708,8 @@ except OperationError as e: if e.match(space, space.w_TypeError): msg = ("%s first arg must be bytes or a tuple of bytes, " - "not %s") - typename = space.type(w_suffix).getname(space) - raise operationerrfmt(space.w_TypeError, msg, funcname, typename) + "not %T") + raise operationerrfmt(space.w_TypeError, msg, funcname, w_suffix) def str_endswith__String_ANY_ANY_ANY(space, w_self, w_suffix, w_start, w_end): (u_self, start, end) = _convert_idx_params(space, w_self, w_start, diff --git a/pypy/objspace/std/stringtype.py b/pypy/objspace/std/stringtype.py --- a/pypy/objspace/std/stringtype.py +++ b/pypy/objspace/std/stringtype.py @@ -287,9 +287,8 @@ if w_bytes_method is not None: w_bytes = space.get_and_call_function(w_bytes_method, w_source) if not space.isinstance_w(w_bytes, space.w_bytes): - msg = "__bytes__ returned non-bytes (type '%s')" - raise operationerrfmt(space.w_TypeError, msg, - space.type(w_bytes).getname(space)) + msg = "__bytes__ returned non-bytes (type '%T')" + raise operationerrfmt(space.w_TypeError, msg, w_bytes) return [c for c in space.bytes_w(w_bytes)] # String-like argument diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -181,9 +181,8 @@ except OperationError, e: if not e.match(space, space.w_TypeError): raise - raise operationerrfmt(space.w_TypeError, - "sequence item %d: expected string, %s " - "found", i, space.type(w_s).getname(space)) + msg = "sequence item %d: expected string, %T found" + raise operationerrfmt(space.w_TypeError, msg, i, w_s) sb = UnicodeBuilder(prealloc_size) for i in range(size): if self and i != 0: @@ -467,10 +466,8 @@ def unicode_startswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_prefixes, w_start, w_end): if not space.isinstance_w(w_prefixes, space.w_tuple): - typename = space.type(w_prefixes).getname(space) - msg = ("startswith first arg must be str or a tuple of str, not %s" % - typename) - raise OperationError(space.w_TypeError, space.wrap(msg)) + msg = "startswith first arg must be str or a tuple of str, not %T" + raise operationerrfmt(space.w_TypeError, msg, w_prefixes) unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) @@ -483,9 +480,8 @@ def unicode_endswith__Unicode_ANY_ANY_ANY(space, w_unistr, w_suffixes, w_start, w_end): if not space.isinstance_w(w_suffixes, space.w_tuple): - typename = space.type(w_suffixes).getname(space) - msg = "endswith first arg must be str or a tuple of str, not %s" % typename - raise OperationError(space.w_TypeError, space.wrap(msg)) + msg = "endswith first arg must be str or a tuple of str, not %T" + raise operationerrfmt(space.w_TypeError, msg, w_suffixes) unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) From noreply at buildbot.pypy.org Tue May 28 23:45:01 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:45:01 +0200 (CEST) Subject: [pypy-commit] pypy py3k: pass through unicode for %N/%T Message-ID: <20130528214501.618C91C00BD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64642:669925f1265e Date: 2013-05-28 14:39 -0700 http://bitbucket.org/pypy/pypy/changeset/669925f1265e/ Log: pass through unicode for %N/%T diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -412,8 +412,15 @@ elif fmt in 'NT': if fmt == 'T': value = space.type(value) - # XXX: - result = value.getname(space).decode('utf-8') + try: + w_name = space.getattr(value, space.wrap('__name__')) + except OperationError as e: + if not (e.match(space, space.w_TypeError) or + e.match(space, space.w_AttributeError)): + raise + result = u'?' + else: + result = space.unicode_w(w_name) else: result = unicode(value) lst[i + i + 1] = result From noreply at buildbot.pypy.org Tue May 28 23:45:02 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:45:02 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130528214502.5509B1C00BD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64643:83978aef9853 Date: 2013-05-28 14:42 -0700 http://bitbucket.org/pypy/pypy/changeset/83978aef9853/ Log: merge default 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 @@ -40,3 +40,9 @@ .. branch: on-abort-resops Added list of resops to the pypyjit on_abort hook. + +.. branch: logging-perf +Speeds up the stdlib logging module + +.. branch: operrfmt-NT +Adds a couple convenient format specifiers to operationerrfmt diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py --- a/pypy/interpreter/error.py +++ b/pypy/interpreter/error.py @@ -355,7 +355,7 @@ _fmtcache = {} _fmtcache2 = {} -_FMTS = tuple('8dsNT') +_FMTS = tuple('8NRTds') def decompose_valuefmt(valuefmt): """Returns a tuple of string parts extracted from valuefmt, @@ -409,6 +409,8 @@ elif fmt == '8': result, _ = str_decode_utf_8(value, len(value), 'strict') + elif fmt == 'R': + result = space.unicode_w(space.repr(value)) elif fmt in 'NT': if fmt == 'T': value = space.type(value) @@ -448,6 +450,7 @@ %8 - The result of arg.decode('utf-8', 'strict') %N - The result of w_arg.getname(space) + %R - The result of space.str_w(space.repr(w_arg)) %T - The result of space.type(w_arg).getname(space) """ diff --git a/pypy/interpreter/test/test_error.py b/pypy/interpreter/test/test_error.py --- a/pypy/interpreter/test/test_error.py +++ b/pypy/interpreter/test/test_error.py @@ -65,8 +65,14 @@ space.wrap('foo'), 'foo') assert operr._compute_value(space) == "'?' object has no attribute 'foo'" -def test_operationerrfmt_empty(): - py.test.raises(AssertionError, operationerrfmt, "w_type", "foobar") +def test_operationerrfmt_R(space): + operr = operationerrfmt(space.w_ValueError, "illegal newline value: %R", + space.wrap('foo')) + assert operr._compute_value(space) == "illegal newline value: 'foo'" + operr = operationerrfmt(space.w_ValueError, "illegal newline value: %R", + space.wrap("'PyLadies'")) + expected = "illegal newline value: \"'PyLadies'\"" + assert operr._compute_value(space) == expected def test_operationerrfmt_unicode(space): operr = operationerrfmt("w_type", "abc %s", u"àèìòù") diff --git a/pypy/module/_io/interp_io.py b/pypy/module/_io/interp_io.py --- a/pypy/module/_io/interp_io.py +++ b/pypy/module/_io/interp_io.py @@ -49,9 +49,7 @@ if not (space.isinstance_w(w_file, space.w_unicode) or space.isinstance_w(w_file, space.w_str) or space.isinstance_w(w_file, space.w_int)): - raise operationerrfmt(space.w_TypeError, - "invalid file: %s", space.str_w(space.repr(w_file)) - ) + raise operationerrfmt(space.w_TypeError, "invalid file: %R", w_file) reading = writing = appending = updating = text = binary = universal = False diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -387,8 +387,8 @@ instance.user_setup(self, w_subtype) else: raise operationerrfmt(self.w_TypeError, - "%s.__new__(%s): only for the type %s", - w_type.name, w_subtype.getname(self), w_type.name) + "%N.__new__(%N): only for the type %N", + w_type, w_subtype, w_type) return instance allocate_instance._annspecialcase_ = "specialize:arg(1)" From noreply at buildbot.pypy.org Tue May 28 23:45:03 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Tue, 28 May 2013 23:45:03 +0200 (CEST) Subject: [pypy-commit] pypy default: merge upstream Message-ID: <20130528214503.39E1B1C00BD@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64644:0289956d46c1 Date: 2013-05-28 14:43 -0700 http://bitbucket.org/pypy/pypy/changeset/0289956d46c1/ Log: merge upstream 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 @@ -830,6 +830,30 @@ out = cbuilder.cmdexec('') assert out.strip() == '789' + def test_llhelper_stored_in_struct(self): + from rpython.rtyper.annlowlevel import llhelper + + def f(x): + return x + 3 + + FUNC_TP = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) + + S = lltype.GcStruct('s', ('f', FUNC_TP)) + + class Glob(object): + pass + + glob = Glob() + + def entry_point(argv): + x = llhelper(FUNC_TP, f) + s = lltype.malloc(S) + s.f = x + glob.s = s # escape + return 0 + + self.compile(entry_point) + # assert did not explode class TestMaemo(TestStandalone): def setup_class(cls): From noreply at buildbot.pypy.org Wed May 29 00:01:37 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 00:01:37 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: A branch to expirement with unrolling Python loops in the JIT. Message-ID: <20130528220137.6741B1C021A@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64645:8255a8d3b52b Date: 2013-05-28 15:00 -0700 http://bitbucket.org/pypy/pypy/changeset/8255a8d3b52b/ Log: A branch to expirement with unrolling Python loops in the JIT. From noreply at buildbot.pypy.org Wed May 29 00:11:51 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 29 May 2013 00:11:51 +0200 (CEST) Subject: [pypy-commit] pypy py3k: replace %8 w/ %R where possible Message-ID: <20130528221151.DA9B21C021A@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64646:dcc9f87e4b91 Date: 2013-05-28 15:00 -0700 http://bitbucket.org/pypy/pypy/changeset/dcc9f87e4b91/ Log: replace %8 w/ %R where possible diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -646,9 +646,8 @@ # fall-back w_value = self._load_global(w_varname) if w_value is None: - message = "name '%8' is not defined" - raise operationerrfmt(self.space.w_NameError, message, - self.space.identifier_w(w_varname)) + message = "name %R is not defined" + raise operationerrfmt(self.space.w_NameError, message, w_varname) self.pushvalue(w_value) def _load_global(self, w_varname): @@ -661,9 +660,8 @@ _load_global._always_inline_ = True def _load_global_failed(self, w_varname): - message = "global name '%8' is not defined" - raise operationerrfmt(self.space.w_NameError, message, - self.space.identifier_w(w_varname)) + message = "global name %R is not defined" + raise operationerrfmt(self.space.w_NameError, message, w_varname) _load_global_failed._dont_inline_ = True def LOAD_GLOBAL(self, nameindex, next_instr): diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py --- a/pypy/objspace/descroperation.py +++ b/pypy/objspace/descroperation.py @@ -52,15 +52,14 @@ def raiseattrerror(space, w_obj, w_name, w_descr=None): # space.repr always returns an encodable string. - name = space.str_w(space.repr(w_name)) if w_descr is None: raise operationerrfmt(space.w_AttributeError, - "'%T' object has no attribute %8", - w_obj, name) + "'%T' object has no attribute %R", + w_obj, w_name) else: raise operationerrfmt(space.w_AttributeError, - "'%T' object attribute %8 is read-only", - w_obj, name) + "'%T' object attribute %R is read-only", + w_obj, w_name) def get_attribute_name(space, w_obj, w_name): try: From noreply at buildbot.pypy.org Wed May 29 00:11:52 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 29 May 2013 00:11:52 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix Message-ID: <20130528221152.CCC741C021A@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64647:af8c6a0e046d Date: 2013-05-28 15:10 -0700 http://bitbucket.org/pypy/pypy/changeset/af8c6a0e046d/ Log: fix diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py --- a/pypy/module/_codecs/interp_codecs.py +++ b/pypy/module/_codecs/interp_codecs.py @@ -372,7 +372,7 @@ space.wrap(start + consumed)]) else: raise operationerrfmt(space.w_TypeError, - "don't know how to handle %s in error callback", + "don't know how to handle %T in error callback", w_exc) def register_builtin_error_handlers(space): From noreply at buildbot.pypy.org Wed May 29 00:17:13 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 00:17:13 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: Expose a class whose job is to explicitly indicate that a loop should be unrolled. Message-ID: <20130528221713.299201C021A@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64648:978ab2b048ae Date: 2013-05-28 15:16 -0700 http://bitbucket.org/pypy/pypy/changeset/978ab2b048ae/ Log: Expose a class whose job is to explicitly indicate that a loop should be unrolled. diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py --- a/pypy/module/__pypy__/__init__.py +++ b/pypy/module/__pypy__/__init__.py @@ -3,6 +3,7 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.imp.importing import get_pyc_magic + class BuildersModule(MixedModule): appleveldefs = {} @@ -11,6 +12,7 @@ "UnicodeBuilder": "interp_builders.W_UnicodeBuilder", } + class TimeModule(MixedModule): appleveldefs = {} interpleveldefs = {} @@ -41,23 +43,30 @@ } interpleveldefs = { - 'internal_repr' : 'interp_magic.internal_repr', - 'bytebuffer' : 'bytebuffer.bytebuffer', - 'identity_dict' : 'interp_identitydict.W_IdentityDict', - 'debug_start' : 'interp_debug.debug_start', - 'debug_print' : 'interp_debug.debug_print', - 'debug_stop' : 'interp_debug.debug_stop', - 'debug_print_once' : 'interp_debug.debug_print_once', - 'builtinify' : 'interp_magic.builtinify', - 'lookup_special' : 'interp_magic.lookup_special', - 'do_what_I_mean' : 'interp_magic.do_what_I_mean', - 'list_strategy' : 'interp_magic.list_strategy', - 'validate_fd' : 'interp_magic.validate_fd', - 'resizelist_hint' : 'interp_magic.resizelist_hint', - 'newlist_hint' : 'interp_magic.newlist_hint', - 'add_memory_pressure' : 'interp_magic.add_memory_pressure', - 'newdict' : 'interp_dict.newdict', - 'dictstrategy' : 'interp_dict.dictstrategy', + 'lookup_special': 'interp_magic.lookup_special', + 'builtinify': 'interp_magic.builtinify', + 'internal_repr': 'interp_magic.internal_repr', + + 'bytebuffer': 'bytebuffer.bytebuffer', + 'identity_dict': 'interp_identitydict.W_IdentityDict', + + 'debug_start': 'interp_debug.debug_start', + 'debug_print': 'interp_debug.debug_print', + 'debug_stop': 'interp_debug.debug_stop', + 'debug_print_once': 'interp_debug.debug_print_once', + + 'add_memory_pressure': 'interp_magic.add_memory_pressure', + 'validate_fd': 'interp_magic.validate_fd', + + 'newlist_hint': 'interp_magic.newlist_hint', + 'resizelist_hint': 'interp_magic.resizelist_hint', + 'list_strategy': 'interp_magic.list_strategy', + 'newdict': 'interp_dict.newdict', + 'dictstrategy': 'interp_dict.dictstrategy', + + 'unroll_loop': 'interp_unroll.W_LoopUnroller', + + 'do_what_I_mean': 'interp_magic.do_what_I_mean', } if sys.platform == 'win32': interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp' diff --git a/pypy/module/__pypy__/interp_unroll.py b/pypy/module/__pypy__/interp_unroll.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/interp_unroll.py @@ -0,0 +1,24 @@ +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.gateway import interp2app +from pypy.interpreter.typedef import TypeDef + + +class W_LoopUnroller(W_Root): + def __init__(self, w_obj): + self.w_obj = w_obj + + def descr__new__(space, w_subtype, w_obj): + return W_LoopUnroller(w_obj) + + def descr__repr__(self, space): + return space.wrap("LoopUnroller(%s)" % space.str_w(space.repr(self.w_obj))) + + def descr__iter__(self, space): + return space.iter(self.w_obj) + + +W_LoopUnroller.typedef = TypeDef("LoopUnroller", + __new__=interp2app(W_LoopUnroller.descr__new__.im_func), + __repr__=interp2app(W_LoopUnroller.descr__repr__), + __iter__=interp2app(W_LoopUnroller.descr__iter__), +) diff --git a/pypy/module/__pypy__/test/test_unroller.py b/pypy/module/__pypy__/test/test_unroller.py new file mode 100644 --- /dev/null +++ b/pypy/module/__pypy__/test/test_unroller.py @@ -0,0 +1,15 @@ +class AppTestUnroller(object): + spaceconfig = {"usemodules": ["__pypy__"]} + + def test_iter(self): + from __pypy__ import unroll_loop + + res = [] + for i in unroll_loop(xrange(3)): + res.append(i) + assert res == [0, 1, 2] + + def test_repr(self): + from __pypy__ import unroll_loop + + assert repr(unroll_loop([1, 2, 3])) == "LoopUnroller(%r)" % [1, 2, 3] From noreply at buildbot.pypy.org Wed May 29 00:31:01 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 00:31:01 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: whack at random stuff, now maybe works? Message-ID: <20130528223101.5E4481C0FF8@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64649:27fd933bbf5e Date: 2013-05-28 15:30 -0700 http://bitbucket.org/pypy/pypy/changeset/27fd933bbf5e/ Log: whack at random stuff, now maybe works? diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -877,7 +877,12 @@ return next_instr def GET_ITER(self, oparg, next_instr): + from pypy.module.__pypy__.interp_unroll import W_LoopUnroller w_iterable = self.popvalue() + if isinstance(w_iterable, W_LoopUnroller): + lastblock = self.lastblock + assert isinstance(lastblock, LoopBlock) + lastblock.should_unroll = True w_iterator = self.space.iter(w_iterable) self.pushvalue(w_iterator) @@ -1240,6 +1245,7 @@ """ raise NotImplementedError + class LoopBlock(FrameBlock): """A loop block. Stores the end-of-loop pointer in case of 'break'.""" @@ -1247,6 +1253,10 @@ _opname = 'SETUP_LOOP' handling_mask = SBreakLoop.kind | SContinueLoop.kind + def __init__(self, frame, handlerposition, previous): + FrameBlock.__init__(self, frame, handlerposition, previous) + self.should_unroll = False + def handle(self, frame, unroller): if isinstance(unroller, SContinueLoop): # re-push the loop block without cleaning up the value stack, diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -77,6 +77,8 @@ return self.popvalue() def jump_absolute(self, jumpto, ec): + from pypy.interpreter.pyopcode import LoopBlock + if we_are_jitted(): # # assume that only threads are using the bytecode counter @@ -89,9 +91,11 @@ ec.bytecode_trace(self, decr_by) jumpto = r_uint(self.last_instr) # - pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto, - pycode=self.getcode(), - is_being_profiled=self.is_being_profiled) + lastblock = self.lastblock + if not (isinstance(lastblock, LoopBlock) and lastblock.should_unroll and we_are_jitted()): + pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto, + pycode=self.getcode(), + is_being_profiled=self.is_being_profiled) return jumpto def _get_adapted_tick_counter(): From noreply at buildbot.pypy.org Wed May 29 00:31:59 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 00:31:59 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: this is no longer totally immutable Message-ID: <20130528223159.B7E921C0FF8@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64650:df2479716baa Date: 2013-05-28 15:31 -0700 http://bitbucket.org/pypy/pypy/changeset/df2479716baa/ Log: this is no longer totally immutable diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -1249,7 +1249,7 @@ class LoopBlock(FrameBlock): """A loop block. Stores the end-of-loop pointer in case of 'break'.""" - _immutable_ = True + _immutable_fields_ = ["handlerposition", "valuestackdepth", "previous"] _opname = 'SETUP_LOOP' handling_mask = SBreakLoop.kind | SContinueLoop.kind From noreply at buildbot.pypy.org Wed May 29 00:39:43 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 00:39:43 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: RPython + handle comprehensions without crashing Message-ID: <20130528223944.00F871C00BD@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64651:8e979a30ce19 Date: 2013-05-28 15:39 -0700 http://bitbucket.org/pypy/pypy/changeset/8e979a30ce19/ Log: RPython + handle comprehensions without crashing diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -881,8 +881,10 @@ w_iterable = self.popvalue() if isinstance(w_iterable, W_LoopUnroller): lastblock = self.lastblock - assert isinstance(lastblock, LoopBlock) - lastblock.should_unroll = True + # This is the case for comprehensions, which don't add a frame + # block, annoying (for now ignore the problem). + if isinstance(lastblock, LoopBlock): + lastblock.should_unroll = True w_iterator = self.space.iter(w_iterable) self.pushvalue(w_iterator) @@ -1209,7 +1211,7 @@ """Abstract base class for frame blocks from the blockstack, used by the SETUP_XXX and POP_BLOCK opcodes.""" - _immutable_ = True + _immutable_fields_ = ["handlerposition", "valuestackdepth", "previous"] def __init__(self, frame, handlerposition, previous): self.handlerposition = handlerposition @@ -1249,7 +1251,6 @@ class LoopBlock(FrameBlock): """A loop block. Stores the end-of-loop pointer in case of 'break'.""" - _immutable_fields_ = ["handlerposition", "valuestackdepth", "previous"] _opname = 'SETUP_LOOP' handling_mask = SBreakLoop.kind | SContinueLoop.kind @@ -1275,7 +1276,6 @@ class ExceptBlock(FrameBlock): """An try:except: block. Stores the position of the exception handler.""" - _immutable_ = True _opname = 'SETUP_EXCEPT' handling_mask = SApplicationException.kind @@ -1299,7 +1299,6 @@ class FinallyBlock(FrameBlock): """A try:finally: block. Stores the position of the exception handler.""" - _immutable_ = True _opname = 'SETUP_FINALLY' handling_mask = -1 # handles every kind of SuspendedUnroller @@ -1314,8 +1313,6 @@ class WithBlock(FinallyBlock): - _immutable_ = True - def handle(self, frame, unroller): if isinstance(unroller, SApplicationException): unroller.operr.normalize_exception(frame.space) From noreply at buildbot.pypy.org Wed May 29 00:51:07 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 00:51:07 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: deadcode + pep8 Message-ID: <20130528225107.3E7001C0FF8@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64652:c4ba4835f87a Date: 2013-05-28 15:50 -0700 http://bitbucket.org/pypy/pypy/changeset/c4ba4835f87a/ Log: deadcode + pep8 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -11,7 +11,6 @@ from pypy.interpreter.astcompiler import optimize # For side effects from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops -from pypy.interpreter.error import OperationError def compile_ast(space, module, info): @@ -21,91 +20,91 @@ name_ops_default = misc.dict_to_switch({ - ast.Load : ops.LOAD_NAME, - ast.Store : ops.STORE_NAME, - ast.Del : ops.DELETE_NAME + ast.Load: ops.LOAD_NAME, + ast.Store: ops.STORE_NAME, + ast.Del: ops.DELETE_NAME }) name_ops_fast = misc.dict_to_switch({ - ast.Load : ops.LOAD_FAST, - ast.Store : ops.STORE_FAST, - ast.Del : ops.DELETE_FAST + ast.Load: ops.LOAD_FAST, + ast.Store: ops.STORE_FAST, + ast.Del: ops.DELETE_FAST }) name_ops_deref = misc.dict_to_switch({ - ast.Load : ops.LOAD_DEREF, - ast.Store : ops.STORE_DEREF, + ast.Load: ops.LOAD_DEREF, + ast.Store: ops.STORE_DEREF, }) name_ops_global = misc.dict_to_switch({ - ast.Load : ops.LOAD_GLOBAL, - ast.Store : ops.STORE_GLOBAL, - ast.Del : ops.DELETE_GLOBAL + ast.Load: ops.LOAD_GLOBAL, + ast.Store: ops.STORE_GLOBAL, + ast.Del: ops.DELETE_GLOBAL }) unary_operations = misc.dict_to_switch({ - ast.Invert : ops.UNARY_INVERT, - ast.Not : ops.UNARY_NOT, - ast.UAdd : ops.UNARY_POSITIVE, - ast.USub : ops.UNARY_NEGATIVE + ast.Invert: ops.UNARY_INVERT, + ast.Not: ops.UNARY_NOT, + ast.UAdd: ops.UNARY_POSITIVE, + ast.USub: ops.UNARY_NEGATIVE }) binary_operations = misc.dict_to_switch({ - ast.Add : ops.BINARY_ADD, - ast.Sub : ops.BINARY_SUBTRACT, - ast.Mult : ops.BINARY_MULTIPLY, - ast.Mod : ops.BINARY_MODULO, - ast.Pow : ops.BINARY_POWER, - ast.LShift : ops.BINARY_LSHIFT, - ast.RShift : ops.BINARY_RSHIFT, - ast.BitOr : ops.BINARY_OR, - ast.BitAnd : ops.BINARY_AND, - ast.BitXor : ops.BINARY_XOR, - ast.FloorDiv : ops.BINARY_FLOOR_DIVIDE + ast.Add: ops.BINARY_ADD, + ast.Sub: ops.BINARY_SUBTRACT, + ast.Mult: ops.BINARY_MULTIPLY, + ast.Mod: ops.BINARY_MODULO, + ast.Pow: ops.BINARY_POWER, + ast.LShift: ops.BINARY_LSHIFT, + ast.RShift: ops.BINARY_RSHIFT, + ast.BitOr: ops.BINARY_OR, + ast.BitAnd: ops.BINARY_AND, + ast.BitXor: ops.BINARY_XOR, + ast.FloorDiv: ops.BINARY_FLOOR_DIVIDE }) inplace_operations = misc.dict_to_switch({ - ast.Add : ops.INPLACE_ADD, - ast.Sub : ops.INPLACE_SUBTRACT, - ast.Mult : ops.INPLACE_MULTIPLY, - ast.Mod : ops.INPLACE_MODULO, - ast.Pow : ops.INPLACE_POWER, - ast.LShift : ops.INPLACE_LSHIFT, - ast.RShift : ops.INPLACE_RSHIFT, - ast.BitOr : ops.INPLACE_OR, - ast.BitAnd : ops.INPLACE_AND, - ast.BitXor : ops.INPLACE_XOR, - ast.FloorDiv : ops.INPLACE_FLOOR_DIVIDE + ast.Add: ops.INPLACE_ADD, + ast.Sub: ops.INPLACE_SUBTRACT, + ast.Mult: ops.INPLACE_MULTIPLY, + ast.Mod: ops.INPLACE_MODULO, + ast.Pow: ops.INPLACE_POWER, + ast.LShift: ops.INPLACE_LSHIFT, + ast.RShift: ops.INPLACE_RSHIFT, + ast.BitOr: ops.INPLACE_OR, + ast.BitAnd: ops.INPLACE_AND, + ast.BitXor: ops.INPLACE_XOR, + ast.FloorDiv: ops.INPLACE_FLOOR_DIVIDE }) compare_operations = misc.dict_to_switch({ - ast.Eq : 2, - ast.NotEq : 3, - ast.Lt : 0, - ast.LtE : 1, - ast.Gt : 4, - ast.GtE : 5, - ast.In : 6, - ast.NotIn : 7, - ast.Is : 8, - ast.IsNot : 9 + ast.Eq: 2, + ast.NotEq: 3, + ast.Lt: 0, + ast.LtE: 1, + ast.Gt: 4, + ast.GtE: 5, + ast.In: 6, + ast.NotIn: 7, + ast.Is: 8, + ast.IsNot: 9 }) subscr_operations = misc.dict_to_switch({ - ast.AugLoad : ops.BINARY_SUBSCR, - ast.Load : ops.BINARY_SUBSCR, - ast.AugStore : ops.STORE_SUBSCR, - ast.Store : ops.STORE_SUBSCR, - ast.Del : ops.DELETE_SUBSCR + ast.AugLoad: ops.BINARY_SUBSCR, + ast.Load: ops.BINARY_SUBSCR, + ast.AugStore: ops.STORE_SUBSCR, + ast.Store: ops.STORE_SUBSCR, + ast.Del: ops.DELETE_SUBSCR }) slice_operations = misc.dict_to_switch({ - ast.AugLoad : ops.SLICE, - ast.Load : ops.SLICE, - ast.AugStore : ops.STORE_SLICE, - ast.Store : ops.STORE_SLICE, - ast.Del : ops.DELETE_SLICE + ast.AugLoad: ops.SLICE, + ast.Load: ops.SLICE, + ast.AugStore: ops.STORE_SLICE, + ast.Store: ops.STORE_SLICE, + ast.Del: ops.DELETE_SLICE }) @@ -475,9 +474,8 @@ self.emit_jump(ops.CONTINUE_LOOP, block, True) break if f_type == F_BLOCK_FINALLY_END: - self.error("'continue' not supported inside 'finally' " \ - "clause", - cont) + self.error("'continue' not supported inside 'finally' " + "clause", cont) else: self.error("'continue' not properly in loop", cont) elif current_block == F_BLOCK_FINALLY_END: @@ -637,7 +635,7 @@ last_line, last_offset = self.compile_info.last_future_import if imp.lineno > last_line or \ imp.lineno == last_line and imp.col_offset > last_offset: - self.error("__future__ statements must appear at beginning " \ + self.error("__future__ statements must appear at beginning " "of file", imp) if star_import: self.error("* not valid in __future__ imports", imp) @@ -816,7 +814,6 @@ def visit_Const(self, const): self.update_position(const.lineno) - space = self.space self.load_const(const.value) def visit_UnaryOp(self, op): @@ -975,7 +972,7 @@ elif call_type == 3: op = ops.CALL_FUNCTION_VAR_KW self.emit_op_arg(op, arg) - + def _call_has_no_star_args(self, call): return not call.starargs and not call.kwargs @@ -1014,12 +1011,9 @@ self.use_next_block() gen.target.walkabout(self) if gen.ifs: - if_count = len(gen.ifs) for if_ in gen.ifs: if_.accept_jump_if(self, False, if_cleanup) self.use_next_block() - else: - if_count = 0 gen_index += 1 if gen_index < len(gens): self._listcomp_generator(gens, gen_index, elt) @@ -1042,7 +1036,6 @@ def _comp_generator(self, node, generators, gen_index): start = self.new_block() - skip = self.new_block() if_cleanup = self.new_block() anchor = self.new_block() gen = generators[gen_index] @@ -1058,12 +1051,9 @@ self.use_next_block() gen.target.walkabout(self) if gen.ifs: - ifs_count = len(gen.ifs) for if_ in gen.ifs: if_.accept_jump_if(self, False, if_cleanup) self.use_next_block() - else: - ifs_count = 0 gen_index += 1 if gen_index < len(generators): self._comp_generator(node, generators, gen_index) @@ -1176,22 +1166,18 @@ def _compile_slice(self, slc, ctx): if isinstance(slc, ast.Index): - kind = "index" if ctx != ast.AugStore: slc.value.walkabout(self) elif isinstance(slc, ast.Ellipsis): - kind = "ellipsis" if ctx != ast.AugStore: self.load_const(self.space.w_Ellipsis) elif isinstance(slc, ast.Slice): - kind = "slice" if not slc.step: self._simple_slice(slc, ctx) return elif ctx != ast.AugStore: self._complex_slice(slc, ctx) elif isinstance(slc, ast.ExtSlice): - kind = "extended slice" if ctx != ast.AugStore: for dim in slc.dims: self._nested_slice(dim, ctx) From noreply at buildbot.pypy.org Wed May 29 01:45:42 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 01:45:42 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: a heuristic, who knows if it works! Message-ID: <20130528234542.2C6431C00BD@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64653:0fe85e59b146 Date: 2013-05-28 16:45 -0700 http://bitbucket.org/pypy/pypy/changeset/0fe85e59b146/ Log: a heuristic, who knows if it works! diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -879,7 +879,8 @@ def GET_ITER(self, oparg, next_instr): from pypy.module.__pypy__.interp_unroll import W_LoopUnroller w_iterable = self.popvalue() - if isinstance(w_iterable, W_LoopUnroller): + length_hint = self.space.length_hint(w_iterable, sys.maxint) + if isinstance(w_iterable, W_LoopUnroller) or jit.isconstant(length_hint) and length_hint < 20: lastblock = self.lastblock # This is the case for comprehensions, which don't add a frame # block, annoying (for now ignore the problem). From noreply at buildbot.pypy.org Wed May 29 01:53:08 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 01:53:08 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: make sure order of operations is correct Message-ID: <20130528235308.9A0821C00BD@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64654:b0325fcc2553 Date: 2013-05-28 16:52 -0700 http://bitbucket.org/pypy/pypy/changeset/b0325fcc2553/ Log: make sure order of operations is correct diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -880,7 +880,7 @@ from pypy.module.__pypy__.interp_unroll import W_LoopUnroller w_iterable = self.popvalue() length_hint = self.space.length_hint(w_iterable, sys.maxint) - if isinstance(w_iterable, W_LoopUnroller) or jit.isconstant(length_hint) and length_hint < 20: + if (jit.isconstant(length_hint) and length_hint < 20) or isinstance(w_iterable, W_LoopUnroller): lastblock = self.lastblock # This is the case for comprehensions, which don't add a frame # block, annoying (for now ignore the problem). From noreply at buildbot.pypy.org Wed May 29 02:34:39 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 02:34:39 +0200 (CEST) Subject: [pypy-commit] pypy default: deadcode + pep8 Message-ID: <20130529003439.8F1D51C00BD@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64655:3777abcff018 Date: 2013-05-28 15:50 -0700 http://bitbucket.org/pypy/pypy/changeset/3777abcff018/ Log: deadcode + pep8 diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -11,7 +11,6 @@ from pypy.interpreter.astcompiler import optimize # For side effects from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops -from pypy.interpreter.error import OperationError def compile_ast(space, module, info): @@ -21,91 +20,91 @@ name_ops_default = misc.dict_to_switch({ - ast.Load : ops.LOAD_NAME, - ast.Store : ops.STORE_NAME, - ast.Del : ops.DELETE_NAME + ast.Load: ops.LOAD_NAME, + ast.Store: ops.STORE_NAME, + ast.Del: ops.DELETE_NAME }) name_ops_fast = misc.dict_to_switch({ - ast.Load : ops.LOAD_FAST, - ast.Store : ops.STORE_FAST, - ast.Del : ops.DELETE_FAST + ast.Load: ops.LOAD_FAST, + ast.Store: ops.STORE_FAST, + ast.Del: ops.DELETE_FAST }) name_ops_deref = misc.dict_to_switch({ - ast.Load : ops.LOAD_DEREF, - ast.Store : ops.STORE_DEREF, + ast.Load: ops.LOAD_DEREF, + ast.Store: ops.STORE_DEREF, }) name_ops_global = misc.dict_to_switch({ - ast.Load : ops.LOAD_GLOBAL, - ast.Store : ops.STORE_GLOBAL, - ast.Del : ops.DELETE_GLOBAL + ast.Load: ops.LOAD_GLOBAL, + ast.Store: ops.STORE_GLOBAL, + ast.Del: ops.DELETE_GLOBAL }) unary_operations = misc.dict_to_switch({ - ast.Invert : ops.UNARY_INVERT, - ast.Not : ops.UNARY_NOT, - ast.UAdd : ops.UNARY_POSITIVE, - ast.USub : ops.UNARY_NEGATIVE + ast.Invert: ops.UNARY_INVERT, + ast.Not: ops.UNARY_NOT, + ast.UAdd: ops.UNARY_POSITIVE, + ast.USub: ops.UNARY_NEGATIVE }) binary_operations = misc.dict_to_switch({ - ast.Add : ops.BINARY_ADD, - ast.Sub : ops.BINARY_SUBTRACT, - ast.Mult : ops.BINARY_MULTIPLY, - ast.Mod : ops.BINARY_MODULO, - ast.Pow : ops.BINARY_POWER, - ast.LShift : ops.BINARY_LSHIFT, - ast.RShift : ops.BINARY_RSHIFT, - ast.BitOr : ops.BINARY_OR, - ast.BitAnd : ops.BINARY_AND, - ast.BitXor : ops.BINARY_XOR, - ast.FloorDiv : ops.BINARY_FLOOR_DIVIDE + ast.Add: ops.BINARY_ADD, + ast.Sub: ops.BINARY_SUBTRACT, + ast.Mult: ops.BINARY_MULTIPLY, + ast.Mod: ops.BINARY_MODULO, + ast.Pow: ops.BINARY_POWER, + ast.LShift: ops.BINARY_LSHIFT, + ast.RShift: ops.BINARY_RSHIFT, + ast.BitOr: ops.BINARY_OR, + ast.BitAnd: ops.BINARY_AND, + ast.BitXor: ops.BINARY_XOR, + ast.FloorDiv: ops.BINARY_FLOOR_DIVIDE }) inplace_operations = misc.dict_to_switch({ - ast.Add : ops.INPLACE_ADD, - ast.Sub : ops.INPLACE_SUBTRACT, - ast.Mult : ops.INPLACE_MULTIPLY, - ast.Mod : ops.INPLACE_MODULO, - ast.Pow : ops.INPLACE_POWER, - ast.LShift : ops.INPLACE_LSHIFT, - ast.RShift : ops.INPLACE_RSHIFT, - ast.BitOr : ops.INPLACE_OR, - ast.BitAnd : ops.INPLACE_AND, - ast.BitXor : ops.INPLACE_XOR, - ast.FloorDiv : ops.INPLACE_FLOOR_DIVIDE + ast.Add: ops.INPLACE_ADD, + ast.Sub: ops.INPLACE_SUBTRACT, + ast.Mult: ops.INPLACE_MULTIPLY, + ast.Mod: ops.INPLACE_MODULO, + ast.Pow: ops.INPLACE_POWER, + ast.LShift: ops.INPLACE_LSHIFT, + ast.RShift: ops.INPLACE_RSHIFT, + ast.BitOr: ops.INPLACE_OR, + ast.BitAnd: ops.INPLACE_AND, + ast.BitXor: ops.INPLACE_XOR, + ast.FloorDiv: ops.INPLACE_FLOOR_DIVIDE }) compare_operations = misc.dict_to_switch({ - ast.Eq : 2, - ast.NotEq : 3, - ast.Lt : 0, - ast.LtE : 1, - ast.Gt : 4, - ast.GtE : 5, - ast.In : 6, - ast.NotIn : 7, - ast.Is : 8, - ast.IsNot : 9 + ast.Eq: 2, + ast.NotEq: 3, + ast.Lt: 0, + ast.LtE: 1, + ast.Gt: 4, + ast.GtE: 5, + ast.In: 6, + ast.NotIn: 7, + ast.Is: 8, + ast.IsNot: 9 }) subscr_operations = misc.dict_to_switch({ - ast.AugLoad : ops.BINARY_SUBSCR, - ast.Load : ops.BINARY_SUBSCR, - ast.AugStore : ops.STORE_SUBSCR, - ast.Store : ops.STORE_SUBSCR, - ast.Del : ops.DELETE_SUBSCR + ast.AugLoad: ops.BINARY_SUBSCR, + ast.Load: ops.BINARY_SUBSCR, + ast.AugStore: ops.STORE_SUBSCR, + ast.Store: ops.STORE_SUBSCR, + ast.Del: ops.DELETE_SUBSCR }) slice_operations = misc.dict_to_switch({ - ast.AugLoad : ops.SLICE, - ast.Load : ops.SLICE, - ast.AugStore : ops.STORE_SLICE, - ast.Store : ops.STORE_SLICE, - ast.Del : ops.DELETE_SLICE + ast.AugLoad: ops.SLICE, + ast.Load: ops.SLICE, + ast.AugStore: ops.STORE_SLICE, + ast.Store: ops.STORE_SLICE, + ast.Del: ops.DELETE_SLICE }) @@ -475,9 +474,8 @@ self.emit_jump(ops.CONTINUE_LOOP, block, True) break if f_type == F_BLOCK_FINALLY_END: - self.error("'continue' not supported inside 'finally' " \ - "clause", - cont) + self.error("'continue' not supported inside 'finally' " + "clause", cont) else: self.error("'continue' not properly in loop", cont) elif current_block == F_BLOCK_FINALLY_END: @@ -637,7 +635,7 @@ last_line, last_offset = self.compile_info.last_future_import if imp.lineno > last_line or \ imp.lineno == last_line and imp.col_offset > last_offset: - self.error("__future__ statements must appear at beginning " \ + self.error("__future__ statements must appear at beginning " "of file", imp) if star_import: self.error("* not valid in __future__ imports", imp) @@ -816,7 +814,6 @@ def visit_Const(self, const): self.update_position(const.lineno) - space = self.space self.load_const(const.value) def visit_UnaryOp(self, op): @@ -975,7 +972,7 @@ elif call_type == 3: op = ops.CALL_FUNCTION_VAR_KW self.emit_op_arg(op, arg) - + def _call_has_no_star_args(self, call): return not call.starargs and not call.kwargs @@ -1014,12 +1011,9 @@ self.use_next_block() gen.target.walkabout(self) if gen.ifs: - if_count = len(gen.ifs) for if_ in gen.ifs: if_.accept_jump_if(self, False, if_cleanup) self.use_next_block() - else: - if_count = 0 gen_index += 1 if gen_index < len(gens): self._listcomp_generator(gens, gen_index, elt) @@ -1042,7 +1036,6 @@ def _comp_generator(self, node, generators, gen_index): start = self.new_block() - skip = self.new_block() if_cleanup = self.new_block() anchor = self.new_block() gen = generators[gen_index] @@ -1058,12 +1051,9 @@ self.use_next_block() gen.target.walkabout(self) if gen.ifs: - ifs_count = len(gen.ifs) for if_ in gen.ifs: if_.accept_jump_if(self, False, if_cleanup) self.use_next_block() - else: - ifs_count = 0 gen_index += 1 if gen_index < len(generators): self._comp_generator(node, generators, gen_index) @@ -1176,22 +1166,18 @@ def _compile_slice(self, slc, ctx): if isinstance(slc, ast.Index): - kind = "index" if ctx != ast.AugStore: slc.value.walkabout(self) elif isinstance(slc, ast.Ellipsis): - kind = "ellipsis" if ctx != ast.AugStore: self.load_const(self.space.w_Ellipsis) elif isinstance(slc, ast.Slice): - kind = "slice" if not slc.step: self._simple_slice(slc, ctx) return elif ctx != ast.AugStore: self._complex_slice(slc, ctx) elif isinstance(slc, ast.ExtSlice): - kind = "extended slice" if ctx != ast.AugStore: for dim in slc.dims: self._nested_slice(dim, ctx) From noreply at buildbot.pypy.org Wed May 29 02:35:45 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Wed, 29 May 2013 02:35:45 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: merged default in Message-ID: <20130529003545.016FA1C00BD@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64656:2027e1ae264f Date: 2013-05-28 17:34 -0700 http://bitbucket.org/pypy/pypy/changeset/2027e1ae264f/ Log: merged default in From noreply at buildbot.pypy.org Wed May 29 03:26:31 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 29 May 2013 03:26:31 +0200 (CEST) Subject: [pypy-commit] pypy default: fix the broken, unused descr_repr Message-ID: <20130529012631.3B9051C13C1@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64658:a6a2200b5fb0 Date: 2013-05-28 18:14 -0700 http://bitbucket.org/pypy/pypy/changeset/a6a2200b5fb0/ Log: fix the broken, unused descr_repr diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -7,7 +7,8 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import ( OperationError, operationerrfmt, wrap_oserror) -from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) from pypy.interpreter.typedef import GetSetProperty, TypeDef READABLE, WRITABLE = range(1, 3) @@ -62,6 +63,14 @@ def writable_get(self, space): return space.newbool(bool(self.flags & WRITABLE)) + def _repr(self, space, handle): + conn_type = ["read-only", "write-only", "read-write"][self.flags - 1] + return space.wrap("<%s %s, handle %d>" % ( + conn_type, space.type(self).getname(space), handle)) + + def descr_repr(self, space): + raise NotImplementedError + def _check_readable(self, space): if not self.flags & READABLE: raise OperationError(space.w_IOError, @@ -178,6 +187,7 @@ W_BaseConnection.typedef = TypeDef( 'BaseConnection', + __repr__ = interpindirect2app(W_BaseConnection.descr_repr), closed = GetSetProperty(W_BaseConnection.closed_get), readable = GetSetProperty(W_BaseConnection.readable_get), writable = GetSetProperty(W_BaseConnection.writable_get), @@ -240,6 +250,9 @@ W_FileConnection.__init__(self, space, fd, flags) return space.wrap(self) + def descr_repr(self, space): + return self._repr(space, self.fd) + def fileno(self, space): return space.wrap(self.fd) @@ -361,10 +374,7 @@ return space.wrap(self) def descr_repr(self, space): - conn_type = ["read-only", "write-only", "read-write"][self.flags] - - return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space), self.do_fileno())) + return self._repr(space, self.handle) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py --- a/pypy/module/_multiprocessing/test/test_connection.py +++ b/pypy/module/_multiprocessing/test/test_connection.py @@ -173,3 +173,11 @@ assert data1 == '\x00\x00\x00\x03abc' data2 = sock.recv(8) assert data2 == '\x00\x00\x00\x04defg' + + def test_repr(self): + import _multiprocessing + c = _multiprocessing.Connection(1) + assert repr(c) == '' + if hasattr(_multiprocessing, 'PipeConnection'): + c = _multiprocessing.PipeConnection(1) + assert repr(c) == '' From noreply at buildbot.pypy.org Wed May 29 03:26:30 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 29 May 2013 03:26:30 +0200 (CEST) Subject: [pypy-commit] pypy default: pep8/cleanup Message-ID: <20130529012630.15BE11C0FF8@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64657:1c11e438a8a4 Date: 2013-05-28 18:12 -0700 http://bitbucket.org/pypy/pypy/changeset/1c11e438a8a4/ Log: pep8/cleanup diff --git a/pypy/module/_multiprocessing/__init__.py b/pypy/module/_multiprocessing/__init__.py --- a/pypy/module/_multiprocessing/__init__.py +++ b/pypy/module/_multiprocessing/__init__.py @@ -1,5 +1,6 @@ +import sys + from pypy.interpreter.mixedmodule import MixedModule -import sys class Module(MixedModule): diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -1,17 +1,16 @@ -from __future__ import with_statement -from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault -from pypy.interpreter.error import ( - OperationError, wrap_oserror, operationerrfmt) -from rpython.rtyper.lltypesystem import rffi, lltype -from rpython.rlib.rarithmetic import intmask -from rpython.rlib import rpoll, rsocket import sys -READABLE = 1 -WRITABLE = 2 +from rpython.rlib import rpoll, rsocket +from rpython.rlib.rarithmetic import intmask +from rpython.rtyper.lltypesystem import lltype, rffi +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.error import ( + OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec +from pypy.interpreter.typedef import GetSetProperty, TypeDef + +READABLE, WRITABLE = range(1, 3) PY_SSIZE_T_MAX = sys.maxint PY_SSIZE_T_MIN = -sys.maxint - 1 @@ -46,10 +45,12 @@ raise NotImplementedError def is_valid(self): return False - def do_send_string(self, space, buffer, offset, size): + def do_send_string(self, space, buf, offset, size): raise NotImplementedError def do_recv_string(self, space, buflength, maxlength): raise NotImplementedError + def do_poll(self, space, timeout): + raise NotImplementedError def close(self): self.do_close() @@ -70,9 +71,9 @@ raise OperationError(space.w_IOError, space.wrap("connection is read-only")) - @unwrap_spec(buffer='bufferstr', offset='index', size='index') - def send_bytes(self, space, buffer, offset=0, size=PY_SSIZE_T_MIN): - length = len(buffer) + @unwrap_spec(buf='bufferstr', offset='index', size='index') + def send_bytes(self, space, buf, offset=0, size=PY_SSIZE_T_MIN): + length = len(buf) self._check_writable(space) if offset < 0: raise OperationError(space.w_ValueError, @@ -90,7 +91,7 @@ raise OperationError(space.w_ValueError, space.wrap("buffer length > offset + size")) - self.do_send_string(space, buffer, offset, size) + self.do_send_string(space, buf, offset, size) @unwrap_spec(maxlength='index') def recv_bytes(self, space, maxlength=PY_SSIZE_T_MAX): @@ -139,8 +140,8 @@ w_pickled = space.call_method( w_picklemodule, "dumps", w_obj, w_protocol) - buffer = space.bufferstr_w(w_pickled) - self.do_send_string(space, buffer, 0, len(buffer)) + buf = space.bufferstr_w(w_pickled) + self.do_send_string(space, buf, 0, len(buf)) def recv(self, space): self._check_readable(space) @@ -226,7 +227,8 @@ def __init__(self, space, fd, flags): if fd == self.INVALID_HANDLE_VALUE or fd < 0: - raise OperationError(space.w_IOError, space.wrap("invalid handle %d" % fd)) + raise OperationError(space.w_IOError, + space.wrap("invalid handle %d" % fd)) W_BaseConnection.__init__(self, flags) self.fd = fd @@ -249,8 +251,8 @@ self.CLOSE() self.fd = self.INVALID_HANDLE_VALUE - def do_send_string(self, space, buffer, offset, size): - # Since str2charp copies the buffer anyway, always combine the + def do_send_string(self, space, buf, offset, size): + # Since str2charp copies the buf anyway, always combine the # "header" and the "body" of the message and send them at once. message = lltype.malloc(rffi.CCHARP.TO, size + 4, flavor='raw') try: @@ -259,7 +261,7 @@ rffi.cast(rffi.UINTP, message)[0] = length i = size - 1 while i >= 0: - message[4 + i] = buffer[offset + i] + message[4 + i] = buf[offset + i] i -= 1 self._sendall(space, message, size + 4) finally: @@ -296,7 +298,7 @@ size -= count message = rffi.ptradd(message, count) - def _recvall(self, space, buffer, length): + def _recvall(self, space, buf, length): length = intmask(length) remaining = length while remaining > 0: @@ -313,9 +315,9 @@ "got end of file during message")) # XXX inefficient for i in range(count): - buffer[i] = data[i] + buf[i] = data[i] remaining -= count - buffer = rffi.ptradd(buffer, count) + buf = rffi.ptradd(buf, count) if sys.platform == 'win32': def _check_fd(self): @@ -330,10 +332,7 @@ "handle out of range in select()")) r, w, e = rpoll.select([self.fd], [], [], timeout) - if r: - return True - else: - return False + return bool(r) W_FileConnection.typedef = TypeDef( 'Connection', W_BaseConnection.typedef, @@ -351,7 +350,8 @@ self.handle = handle @unwrap_spec(readable=bool, writable=bool) - def descr_new_pipe(space, w_subtype, w_handle, readable=True, writable=True): + def descr_new_pipe(space, w_subtype, w_handle, readable=True, + writable=True): from pypy.module._multiprocessing.interp_win32 import handle_w handle = handle_w(space, w_handle) flags = (readable and READABLE) | (writable and WRITABLE) @@ -378,12 +378,12 @@ CloseHandle(self.handle) self.handle = self.INVALID_HANDLE_VALUE - def do_send_string(self, space, buffer, offset, size): + def do_send_string(self, space, buf, offset, size): from pypy.module._multiprocessing.interp_win32 import ( _WriteFile, ERROR_NO_SYSTEM_RESOURCES) from rpython.rlib import rwin32 - charp = rffi.str2charp(buffer) + charp = rffi.str2charp(buf) written_ptr = lltype.malloc(rffi.CArrayPtr(rwin32.DWORD).TO, 1, flavor='raw') try: diff --git a/pypy/module/_multiprocessing/interp_memory.py b/pypy/module/_multiprocessing/interp_memory.py --- a/pypy/module/_multiprocessing/interp_memory.py +++ b/pypy/module/_multiprocessing/interp_memory.py @@ -1,5 +1,6 @@ +from rpython.rtyper.lltypesystem import rffi + from pypy.interpreter.error import OperationError -from rpython.rtyper.lltypesystem import rffi from pypy.module.mmap.interp_mmap import W_MMap def address_of_buffer(space, w_obj): diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -1,23 +1,26 @@ -from __future__ import with_statement +import errno +import os +import sys +import time + +from rpython.rlib import rgc, rthread +from rpython.rlib.rarithmetic import r_uint +from rpython.rtyper.lltypesystem import rffi, lltype +from rpython.rtyper.tool import rffi_platform as platform +from rpython.translator.tool.cbuild import ExternalCompilationInfo + from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import wrap_oserror, OperationError -from rpython.rtyper.lltypesystem import rffi, lltype -from rpython.rlib import rgc -from rpython.rlib.rarithmetic import r_uint -from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rtyper.tool import rffi_platform as platform -from rpython.rlib import rthread +from pypy.interpreter.typedef import GetSetProperty, TypeDef from pypy.module._multiprocessing.interp_connection import w_handle -import sys, os, time, errno RECURSIVE_MUTEX, SEMAPHORE = range(2) if sys.platform == 'win32': from rpython.rlib import rwin32 from pypy.module._multiprocessing.interp_win32 import ( - handle_w, _GetTickCount) + _GetTickCount, handle_w) SEM_VALUE_MAX = sys.maxint @@ -62,7 +65,8 @@ TIMEVALP = rffi.CArrayPtr(TIMEVAL) TIMESPECP = rffi.CArrayPtr(TIMESPEC) SEM_T = rffi.COpaquePtr('sem_t', compilation_info=eci) - SEM_FAILED = config['SEM_FAILED'] # rffi.cast(SEM_T, config['SEM_FAILED']) + # rffi.cast(SEM_T, config['SEM_FAILED']) + SEM_FAILED = config['SEM_FAILED'] SEM_VALUE_MAX = config['SEM_VALUE_MAX'] SEM_TIMED_WAIT = config['SEM_TIMED_WAIT'] SEM_T_SIZE = config['SEM_T_SIZE'] @@ -160,7 +164,8 @@ return -1 if SEM_TIMED_WAIT: - _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], rffi.INT) + _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], + rffi.INT) else: _sem_timedwait = _sem_timedwait_save @@ -185,7 +190,8 @@ res = _gettimeofday(now, None) if res < 0: raise OSError(rposix.get_errno(), "gettimeofday failed") - return rffi.getintfield(now[0], 'c_tv_sec'), rffi.getintfield(now[0], 'c_tv_usec') + return (rffi.getintfield(now[0], 'c_tv_sec'), + rffi.getintfield(now[0], 'c_tv_usec')) finally: lltype.free(now, flavor='raw') @@ -330,8 +336,8 @@ deadline = lltype.malloc(TIMESPECP.TO, 1, flavor='raw') rffi.setintfield(deadline[0], 'c_tv_sec', now_sec + sec) rffi.setintfield(deadline[0], 'c_tv_nsec', now_usec * 1000 + nsec) - val = rffi.getintfield(deadline[0], 'c_tv_sec') + \ - rffi.getintfield(deadline[0], 'c_tv_nsec') / 1000000000 + val = (rffi.getintfield(deadline[0], 'c_tv_sec') + + rffi.getintfield(deadline[0], 'c_tv_nsec') / 1000000000) rffi.setintfield(deadline[0], 'c_tv_sec', val) val = rffi.getintfield(deadline[0], 'c_tv_nsec') % 1000000000 rffi.setintfield(deadline[0], 'c_tv_nsec', val) diff --git a/pypy/module/_multiprocessing/interp_win32.py b/pypy/module/_multiprocessing/interp_win32.py --- a/pypy/module/_multiprocessing/interp_win32.py +++ b/pypy/module/_multiprocessing/interp_win32.py @@ -1,11 +1,12 @@ -from pypy.interpreter.gateway import unwrap_spec, interp2app -from pypy.interpreter.function import StaticMethod -from pypy.interpreter.error import wrap_windowserror, OperationError from rpython.rlib import rwin32 from rpython.rlib.rarithmetic import r_uint -from rpython.rtyper.lltypesystem import rffi, lltype +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.tool import rffi_platform from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rtyper.tool import rffi_platform + +from pypy.interpreter.error import OperationError, wrap_windowserror +from pypy.interpreter.function import StaticMethod +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.module._multiprocessing.interp_connection import w_handle CONSTANTS = """ @@ -130,10 +131,12 @@ if not _ConnectNamedPipe(handle, rffi.NULL): raise wrap_windowserror(space, rwin32.lastWindowsError()) -def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances, w_timeout): +def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances, + w_timeout): handle = handle_w(space, w_handle) state = lltype.malloc(rffi.CArrayPtr(rffi.UINT).TO, 3, flavor='raw') - statep = lltype.malloc(rffi.CArrayPtr(rffi.UINTP).TO, 3, flavor='raw', zero=True) + statep = lltype.malloc(rffi.CArrayPtr(rffi.UINTP).TO, 3, flavor='raw', + zero=True) try: if not space.is_w(w_pipemode, space.w_None): state[0] = space.uint_w(w_pipemode) @@ -144,7 +147,8 @@ if not space.is_w(w_timeout, space.w_None): state[2] = space.uint_w(w_timeout) statep[2] = rffi.ptradd(state, 2) - if not _SetNamedPipeHandleState(handle, statep[0], statep[1], statep[2]): + if not _SetNamedPipeHandleState(handle, statep[0], statep[1], + statep[2]): raise wrap_windowserror(space, rwin32.lastWindowsError()) finally: lltype.free(state, flavor='raw') From noreply at buildbot.pypy.org Wed May 29 03:26:32 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 29 May 2013 03:26:32 +0200 (CEST) Subject: [pypy-commit] pypy default: PipeConnection is win32 only Message-ID: <20130529012632.151611C0FF8@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64659:e4520f56a080 Date: 2013-05-28 18:14 -0700 http://bitbucket.org/pypy/pypy/changeset/e4520f56a080/ Log: PipeConnection is win32 only diff --git a/pypy/module/_multiprocessing/__init__.py b/pypy/module/_multiprocessing/__init__.py --- a/pypy/module/_multiprocessing/__init__.py +++ b/pypy/module/_multiprocessing/__init__.py @@ -6,7 +6,6 @@ interpleveldefs = { 'Connection' : 'interp_connection.W_FileConnection', - 'PipeConnection' : 'interp_connection.W_PipeConnection', 'SemLock' : 'interp_semaphore.W_SemLock', 'address_of_buffer' : 'interp_memory.address_of_buffer', @@ -16,4 +15,6 @@ } if sys.platform == 'win32': + interpleveldefs['PipeConnection'] = \ + 'interp_connection.W_PipeConnection' interpleveldefs['win32'] = 'interp_win32.win32_namespace(space)' From noreply at buildbot.pypy.org Wed May 29 03:26:33 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Wed, 29 May 2013 03:26:33 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130529012633.126441C0FF8@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64660:32e7d1cf273c Date: 2013-05-28 18:24 -0700 http://bitbucket.org/pypy/pypy/changeset/32e7d1cf273c/ Log: merge default diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -12,7 +12,6 @@ from pypy.interpreter.astcompiler import optimize # For side effects from pypy.interpreter.pyparser.error import SyntaxError from pypy.tool import stdlib_opcode as ops -from pypy.interpreter.error import OperationError C_INT_MAX = (2 ** (struct.calcsize('i') * 8)) / 2 - 1 @@ -23,86 +22,86 @@ name_ops_default = misc.dict_to_switch({ - ast.Load : ops.LOAD_NAME, - ast.Store : ops.STORE_NAME, - ast.Del : ops.DELETE_NAME + ast.Load: ops.LOAD_NAME, + ast.Store: ops.STORE_NAME, + ast.Del: ops.DELETE_NAME }) name_ops_fast = misc.dict_to_switch({ - ast.Load : ops.LOAD_FAST, - ast.Store : ops.STORE_FAST, - ast.Del : ops.DELETE_FAST + ast.Load: ops.LOAD_FAST, + ast.Store: ops.STORE_FAST, + ast.Del: ops.DELETE_FAST }) name_ops_deref = misc.dict_to_switch({ - ast.Load : ops.LOAD_DEREF, - ast.Store : ops.STORE_DEREF, - ast.Del : ops.DELETE_DEREF, + ast.Load: ops.LOAD_DEREF, + ast.Store: ops.STORE_DEREF, + ast.Del: ops.DELETE_DEREF, }) name_ops_global = misc.dict_to_switch({ - ast.Load : ops.LOAD_GLOBAL, - ast.Store : ops.STORE_GLOBAL, - ast.Del : ops.DELETE_GLOBAL + ast.Load: ops.LOAD_GLOBAL, + ast.Store: ops.STORE_GLOBAL, + ast.Del: ops.DELETE_GLOBAL }) unary_operations = misc.dict_to_switch({ - ast.Invert : ops.UNARY_INVERT, - ast.Not : ops.UNARY_NOT, - ast.UAdd : ops.UNARY_POSITIVE, - ast.USub : ops.UNARY_NEGATIVE + ast.Invert: ops.UNARY_INVERT, + ast.Not: ops.UNARY_NOT, + ast.UAdd: ops.UNARY_POSITIVE, + ast.USub: ops.UNARY_NEGATIVE }) binary_operations = misc.dict_to_switch({ - ast.Add : ops.BINARY_ADD, - ast.Sub : ops.BINARY_SUBTRACT, - ast.Mult : ops.BINARY_MULTIPLY, - ast.Div : ops.BINARY_TRUE_DIVIDE, - ast.Mod : ops.BINARY_MODULO, - ast.Pow : ops.BINARY_POWER, - ast.LShift : ops.BINARY_LSHIFT, - ast.RShift : ops.BINARY_RSHIFT, - ast.BitOr : ops.BINARY_OR, - ast.BitAnd : ops.BINARY_AND, - ast.BitXor : ops.BINARY_XOR, - ast.FloorDiv : ops.BINARY_FLOOR_DIVIDE + ast.Add: ops.BINARY_ADD, + ast.Sub: ops.BINARY_SUBTRACT, + ast.Mult: ops.BINARY_MULTIPLY, + ast.Div: ops.BINARY_TRUE_DIVIDE, + ast.Mod: ops.BINARY_MODULO, + ast.Pow: ops.BINARY_POWER, + ast.LShift: ops.BINARY_LSHIFT, + ast.RShift: ops.BINARY_RSHIFT, + ast.BitOr: ops.BINARY_OR, + ast.BitAnd: ops.BINARY_AND, + ast.BitXor: ops.BINARY_XOR, + ast.FloorDiv: ops.BINARY_FLOOR_DIVIDE }) inplace_operations = misc.dict_to_switch({ - ast.Add : ops.INPLACE_ADD, - ast.Sub : ops.INPLACE_SUBTRACT, - ast.Mult : ops.INPLACE_MULTIPLY, - ast.Div : ops.INPLACE_TRUE_DIVIDE, - ast.Mod : ops.INPLACE_MODULO, - ast.Pow : ops.INPLACE_POWER, - ast.LShift : ops.INPLACE_LSHIFT, - ast.RShift : ops.INPLACE_RSHIFT, - ast.BitOr : ops.INPLACE_OR, - ast.BitAnd : ops.INPLACE_AND, - ast.BitXor : ops.INPLACE_XOR, - ast.FloorDiv : ops.INPLACE_FLOOR_DIVIDE + ast.Add: ops.INPLACE_ADD, + ast.Sub: ops.INPLACE_SUBTRACT, + ast.Mult: ops.INPLACE_MULTIPLY, + ast.Div: ops.INPLACE_TRUE_DIVIDE, + ast.Mod: ops.INPLACE_MODULO, + ast.Pow: ops.INPLACE_POWER, + ast.LShift: ops.INPLACE_LSHIFT, + ast.RShift: ops.INPLACE_RSHIFT, + ast.BitOr: ops.INPLACE_OR, + ast.BitAnd: ops.INPLACE_AND, + ast.BitXor: ops.INPLACE_XOR, + ast.FloorDiv: ops.INPLACE_FLOOR_DIVIDE }) compare_operations = misc.dict_to_switch({ - ast.Eq : 2, - ast.NotEq : 3, - ast.Lt : 0, - ast.LtE : 1, - ast.Gt : 4, - ast.GtE : 5, - ast.In : 6, - ast.NotIn : 7, - ast.Is : 8, - ast.IsNot : 9 + ast.Eq: 2, + ast.NotEq: 3, + ast.Lt: 0, + ast.LtE: 1, + ast.Gt: 4, + ast.GtE: 5, + ast.In: 6, + ast.NotIn: 7, + ast.Is: 8, + ast.IsNot: 9 }) subscr_operations = misc.dict_to_switch({ - ast.AugLoad : ops.BINARY_SUBSCR, - ast.Load : ops.BINARY_SUBSCR, - ast.AugStore : ops.STORE_SUBSCR, - ast.Store : ops.STORE_SUBSCR, - ast.Del : ops.DELETE_SUBSCR + ast.AugLoad: ops.BINARY_SUBSCR, + ast.Load: ops.BINARY_SUBSCR, + ast.AugStore: ops.STORE_SUBSCR, + ast.Store: ops.STORE_SUBSCR, + ast.Del: ops.DELETE_SUBSCR }) @@ -510,9 +509,8 @@ self.emit_jump(ops.CONTINUE_LOOP, block, True) break if f_type == F_BLOCK_FINALLY_END: - self.error("'continue' not supported inside 'finally' " \ - "clause", - cont) + self.error("'continue' not supported inside 'finally' " + "clause", cont) else: self.error("'continue' not properly in loop", cont) elif current_block == F_BLOCK_FINALLY_END: @@ -708,7 +706,7 @@ last_line, last_offset = self.compile_info.last_future_import if imp.lineno > last_line or \ imp.lineno == last_line and imp.col_offset > last_offset: - self.error("__future__ statements must appear at beginning " \ + self.error("__future__ statements must appear at beginning " "of file", imp) if star_import: self.error("* not valid in __future__ imports", imp) @@ -876,7 +874,6 @@ def visit_Const(self, const): self.update_position(const.lineno) - space = self.space self.load_const(const.value) def visit_Ellipsis(self, e): @@ -1095,7 +1092,6 @@ def _comp_generator(self, node, generators, gen_index): start = self.new_block() - skip = self.new_block() if_cleanup = self.new_block() anchor = self.new_block() gen = generators[gen_index] @@ -1111,12 +1107,9 @@ self.use_next_block() gen.target.walkabout(self) if gen.ifs: - ifs_count = len(gen.ifs) for if_ in gen.ifs: if_.accept_jump_if(self, False, if_cleanup) self.use_next_block() - else: - ifs_count = 0 gen_index += 1 if gen_index < len(generators): self._comp_generator(node, generators, gen_index) @@ -1193,15 +1186,12 @@ def _compile_slice(self, slc, ctx): if isinstance(slc, ast.Index): - kind = "index" if ctx != ast.AugStore: slc.value.walkabout(self) elif isinstance(slc, ast.Slice): - kind = "slice" if ctx != ast.AugStore: self._complex_slice(slc, ctx) elif isinstance(slc, ast.ExtSlice): - kind = "extended slice" if ctx != ast.AugStore: for dim in slc.dims: self._nested_slice(dim, ctx) diff --git a/pypy/module/_multiprocessing/__init__.py b/pypy/module/_multiprocessing/__init__.py --- a/pypy/module/_multiprocessing/__init__.py +++ b/pypy/module/_multiprocessing/__init__.py @@ -1,11 +1,11 @@ +import sys + from pypy.interpreter.mixedmodule import MixedModule -import sys class Module(MixedModule): interpleveldefs = { 'Connection' : 'interp_connection.W_FileConnection', - 'PipeConnection' : 'interp_connection.W_PipeConnection', 'SemLock' : 'interp_semaphore.W_SemLock', 'address_of_buffer' : 'interp_memory.address_of_buffer', @@ -15,4 +15,6 @@ } if sys.platform == 'win32': + interpleveldefs['PipeConnection'] = \ + 'interp_connection.W_PipeConnection' interpleveldefs['win32'] = 'interp_win32.win32_namespace(space)' diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -1,17 +1,17 @@ -from __future__ import with_statement -from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault -from pypy.interpreter.error import ( - OperationError, wrap_oserror, operationerrfmt) -from rpython.rtyper.lltypesystem import rffi, lltype -from rpython.rlib.rarithmetic import intmask -from rpython.rlib import rpoll, rsocket import sys -READABLE = 1 -WRITABLE = 2 +from rpython.rlib import rpoll, rsocket +from rpython.rlib.rarithmetic import intmask +from rpython.rtyper.lltypesystem import lltype, rffi +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.error import ( + OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) +from pypy.interpreter.typedef import GetSetProperty, TypeDef + +READABLE, WRITABLE = range(1, 3) PY_SSIZE_T_MAX = sys.maxint PY_SSIZE_T_MIN = -sys.maxint - 1 @@ -46,10 +46,12 @@ raise NotImplementedError def is_valid(self): return False - def do_send_string(self, space, buffer, offset, size): + def do_send_string(self, space, buf, offset, size): raise NotImplementedError def do_recv_string(self, space, buflength, maxlength): raise NotImplementedError + def do_poll(self, space, timeout): + raise NotImplementedError def close(self): self.do_close() @@ -61,6 +63,14 @@ def writable_get(self, space): return space.newbool(bool(self.flags & WRITABLE)) + def _repr(self, space, handle): + conn_type = ["read-only", "write-only", "read-write"][self.flags - 1] + return space.wrap("<%s %s, handle %d>" % ( + conn_type, space.type(self).getname(space), handle)) + + def descr_repr(self, space): + raise NotImplementedError + def _check_readable(self, space): if not self.flags & READABLE: raise OperationError(space.w_IOError, @@ -70,9 +80,9 @@ raise OperationError(space.w_IOError, space.wrap("connection is read-only")) - @unwrap_spec(buffer='bufferstr', offset='index', size='index') - def send_bytes(self, space, buffer, offset=0, size=PY_SSIZE_T_MIN): - length = len(buffer) + @unwrap_spec(buf='bufferstr', offset='index', size='index') + def send_bytes(self, space, buf, offset=0, size=PY_SSIZE_T_MIN): + length = len(buf) self._check_writable(space) if offset < 0: raise OperationError(space.w_ValueError, @@ -90,7 +100,7 @@ raise OperationError(space.w_ValueError, space.wrap("buffer length > offset + size")) - self.do_send_string(space, buffer, offset, size) + self.do_send_string(space, buf, offset, size) @unwrap_spec(maxlength='index') def recv_bytes(self, space, maxlength=PY_SSIZE_T_MAX): @@ -139,8 +149,8 @@ w_pickled = space.call_method( w_picklemodule, "dumps", w_obj, w_protocol) - buffer = space.bufferstr_w(w_pickled) - self.do_send_string(space, buffer, 0, len(buffer)) + buf = space.bufferstr_w(w_pickled) + self.do_send_string(space, buf, 0, len(buf)) def recv(self, space): self._check_readable(space) @@ -177,6 +187,7 @@ W_BaseConnection.typedef = TypeDef( 'BaseConnection', + __repr__ = interpindirect2app(W_BaseConnection.descr_repr), closed = GetSetProperty(W_BaseConnection.closed_get), readable = GetSetProperty(W_BaseConnection.readable_get), writable = GetSetProperty(W_BaseConnection.writable_get), @@ -226,7 +237,8 @@ def __init__(self, space, fd, flags): if fd == self.INVALID_HANDLE_VALUE or fd < 0: - raise OperationError(space.w_IOError, space.wrap("invalid handle %d" % fd)) + raise OperationError(space.w_IOError, + space.wrap("invalid handle %d" % fd)) W_BaseConnection.__init__(self, flags) self.fd = fd @@ -238,6 +250,9 @@ W_FileConnection.__init__(self, space, fd, flags) return space.wrap(self) + def descr_repr(self, space): + return self._repr(space, self.fd) + def fileno(self, space): return space.wrap(self.fd) @@ -249,8 +264,8 @@ self.CLOSE() self.fd = self.INVALID_HANDLE_VALUE - def do_send_string(self, space, buffer, offset, size): - # Since str2charp copies the buffer anyway, always combine the + def do_send_string(self, space, buf, offset, size): + # Since str2charp copies the buf anyway, always combine the # "header" and the "body" of the message and send them at once. message = lltype.malloc(rffi.CCHARP.TO, size + 4, flavor='raw') try: @@ -259,7 +274,7 @@ rffi.cast(rffi.UINTP, message)[0] = length i = size - 1 while i >= 0: - message[4 + i] = buffer[offset + i] + message[4 + i] = buf[offset + i] i -= 1 self._sendall(space, message, size + 4) finally: @@ -296,7 +311,7 @@ size -= count message = rffi.ptradd(message, count) - def _recvall(self, space, buffer, length): + def _recvall(self, space, buf, length): length = intmask(length) remaining = length while remaining > 0: @@ -313,9 +328,9 @@ "got end of file during message")) # XXX inefficient for i in range(count): - buffer[i] = data[i] + buf[i] = data[i] remaining -= count - buffer = rffi.ptradd(buffer, count) + buf = rffi.ptradd(buf, count) if sys.platform == 'win32': def _check_fd(self): @@ -330,10 +345,7 @@ "handle out of range in select()")) r, w, e = rpoll.select([self.fd], [], [], timeout) - if r: - return True - else: - return False + return bool(r) W_FileConnection.typedef = TypeDef( 'Connection', W_BaseConnection.typedef, @@ -351,7 +363,8 @@ self.handle = handle @unwrap_spec(readable=bool, writable=bool) - def descr_new_pipe(space, w_subtype, w_handle, readable=True, writable=True): + def descr_new_pipe(space, w_subtype, w_handle, readable=True, + writable=True): from pypy.module._multiprocessing.interp_win32 import handle_w handle = handle_w(space, w_handle) flags = (readable and READABLE) | (writable and WRITABLE) @@ -361,10 +374,7 @@ return space.wrap(self) def descr_repr(self, space): - conn_type = ["read-only", "write-only", "read-write"][self.flags] - - return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space), self.do_fileno())) + return self._repr(space, self.handle) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE @@ -378,12 +388,12 @@ CloseHandle(self.handle) self.handle = self.INVALID_HANDLE_VALUE - def do_send_string(self, space, buffer, offset, size): + def do_send_string(self, space, buf, offset, size): from pypy.module._multiprocessing.interp_win32 import ( _WriteFile, ERROR_NO_SYSTEM_RESOURCES) from rpython.rlib import rwin32 - charp = rffi.str2charp(buffer) + charp = rffi.str2charp(buf) written_ptr = lltype.malloc(rffi.CArrayPtr(rwin32.DWORD).TO, 1, flavor='raw') try: diff --git a/pypy/module/_multiprocessing/interp_memory.py b/pypy/module/_multiprocessing/interp_memory.py --- a/pypy/module/_multiprocessing/interp_memory.py +++ b/pypy/module/_multiprocessing/interp_memory.py @@ -1,5 +1,6 @@ +from rpython.rtyper.lltypesystem import rffi + from pypy.interpreter.error import OperationError -from rpython.rtyper.lltypesystem import rffi from pypy.module.mmap.interp_mmap import W_MMap def address_of_buffer(space, w_obj): diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -1,23 +1,26 @@ -from __future__ import with_statement +import errno +import os +import sys +import time + +from rpython.rlib import rgc, rthread +from rpython.rlib.rarithmetic import r_uint +from rpython.rtyper.lltypesystem import rffi, lltype +from rpython.rtyper.tool import rffi_platform as platform +from rpython.translator.tool.cbuild import ExternalCompilationInfo + from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import wrap_oserror, OperationError -from rpython.rtyper.lltypesystem import rffi, lltype -from rpython.rlib import rgc -from rpython.rlib.rarithmetic import r_uint -from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rtyper.tool import rffi_platform as platform -from rpython.rlib import rthread +from pypy.interpreter.typedef import GetSetProperty, TypeDef from pypy.module._multiprocessing.interp_connection import w_handle -import sys, os, time, errno RECURSIVE_MUTEX, SEMAPHORE = range(2) if sys.platform == 'win32': from rpython.rlib import rwin32 from pypy.module._multiprocessing.interp_win32 import ( - handle_w, _GetTickCount) + _GetTickCount, handle_w) SEM_VALUE_MAX = sys.maxint @@ -62,7 +65,8 @@ TIMEVALP = rffi.CArrayPtr(TIMEVAL) TIMESPECP = rffi.CArrayPtr(TIMESPEC) SEM_T = rffi.COpaquePtr('sem_t', compilation_info=eci) - SEM_FAILED = config['SEM_FAILED'] # rffi.cast(SEM_T, config['SEM_FAILED']) + # rffi.cast(SEM_T, config['SEM_FAILED']) + SEM_FAILED = config['SEM_FAILED'] SEM_VALUE_MAX = config['SEM_VALUE_MAX'] SEM_TIMED_WAIT = config['SEM_TIMED_WAIT'] SEM_T_SIZE = config['SEM_T_SIZE'] @@ -160,7 +164,8 @@ return -1 if SEM_TIMED_WAIT: - _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], rffi.INT) + _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], + rffi.INT) else: _sem_timedwait = _sem_timedwait_save @@ -185,7 +190,8 @@ res = _gettimeofday(now, None) if res < 0: raise OSError(rposix.get_errno(), "gettimeofday failed") - return rffi.getintfield(now[0], 'c_tv_sec'), rffi.getintfield(now[0], 'c_tv_usec') + return (rffi.getintfield(now[0], 'c_tv_sec'), + rffi.getintfield(now[0], 'c_tv_usec')) finally: lltype.free(now, flavor='raw') @@ -330,8 +336,8 @@ deadline = lltype.malloc(TIMESPECP.TO, 1, flavor='raw') rffi.setintfield(deadline[0], 'c_tv_sec', now_sec + sec) rffi.setintfield(deadline[0], 'c_tv_nsec', now_usec * 1000 + nsec) - val = rffi.getintfield(deadline[0], 'c_tv_sec') + \ - rffi.getintfield(deadline[0], 'c_tv_nsec') / 1000000000 + val = (rffi.getintfield(deadline[0], 'c_tv_sec') + + rffi.getintfield(deadline[0], 'c_tv_nsec') / 1000000000) rffi.setintfield(deadline[0], 'c_tv_sec', val) val = rffi.getintfield(deadline[0], 'c_tv_nsec') % 1000000000 rffi.setintfield(deadline[0], 'c_tv_nsec', val) diff --git a/pypy/module/_multiprocessing/interp_win32.py b/pypy/module/_multiprocessing/interp_win32.py --- a/pypy/module/_multiprocessing/interp_win32.py +++ b/pypy/module/_multiprocessing/interp_win32.py @@ -1,11 +1,12 @@ -from pypy.interpreter.gateway import unwrap_spec, interp2app -from pypy.interpreter.function import StaticMethod -from pypy.interpreter.error import wrap_windowserror, OperationError from rpython.rlib import rwin32 from rpython.rlib.rarithmetic import r_uint -from rpython.rtyper.lltypesystem import rffi, lltype +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.tool import rffi_platform from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rtyper.tool import rffi_platform + +from pypy.interpreter.error import OperationError, wrap_windowserror +from pypy.interpreter.function import StaticMethod +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.module._multiprocessing.interp_connection import w_handle CONSTANTS = """ @@ -130,10 +131,12 @@ if not _ConnectNamedPipe(handle, rffi.NULL): raise wrap_windowserror(space, rwin32.lastWindowsError()) -def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances, w_timeout): +def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances, + w_timeout): handle = handle_w(space, w_handle) state = lltype.malloc(rffi.CArrayPtr(rffi.UINT).TO, 3, flavor='raw') - statep = lltype.malloc(rffi.CArrayPtr(rffi.UINTP).TO, 3, flavor='raw', zero=True) + statep = lltype.malloc(rffi.CArrayPtr(rffi.UINTP).TO, 3, flavor='raw', + zero=True) try: if not space.is_w(w_pipemode, space.w_None): state[0] = space.uint_w(w_pipemode) @@ -144,7 +147,8 @@ if not space.is_w(w_timeout, space.w_None): state[2] = space.uint_w(w_timeout) statep[2] = rffi.ptradd(state, 2) - if not _SetNamedPipeHandleState(handle, statep[0], statep[1], statep[2]): + if not _SetNamedPipeHandleState(handle, statep[0], statep[1], + statep[2]): raise wrap_windowserror(space, rwin32.lastWindowsError()) finally: lltype.free(state, flavor='raw') diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py --- a/pypy/module/_multiprocessing/test/test_connection.py +++ b/pypy/module/_multiprocessing/test/test_connection.py @@ -172,3 +172,11 @@ assert data1 == b'\x00\x00\x00\x03abc' data2 = sock.recv(8) assert data2 == b'\x00\x00\x00\x04defg' + + def test_repr(self): + import _multiprocessing + c = _multiprocessing.Connection(1) + assert repr(c) == '' + if hasattr(_multiprocessing, 'PipeConnection'): + c = _multiprocessing.PipeConnection(1) + assert repr(c) == '' 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 @@ -830,6 +830,30 @@ out = cbuilder.cmdexec('') assert out.strip() == '789' + def test_llhelper_stored_in_struct(self): + from rpython.rtyper.annlowlevel import llhelper + + def f(x): + return x + 3 + + FUNC_TP = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Signed)) + + S = lltype.GcStruct('s', ('f', FUNC_TP)) + + class Glob(object): + pass + + glob = Glob() + + def entry_point(argv): + x = llhelper(FUNC_TP, f) + s = lltype.malloc(S) + s.f = x + glob.s = s # escape + return 0 + + self.compile(entry_point) + # assert did not explode class TestMaemo(TestStandalone): def setup_class(cls): From noreply at buildbot.pypy.org Wed May 29 09:51:50 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 09:51:50 +0200 (CEST) Subject: [pypy-commit] stmgc default: Next fix Message-ID: <20130529075150.839B21C1397@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r49:672596f7b1b6 Date: 2013-05-29 09:51 +0200 http://bitbucket.org/pypy/stmgc/changeset/672596f7b1b6/ Log: Next fix diff --git a/c3/et.c b/c3/et.c --- a/c3/et.c +++ b/c3/et.c @@ -166,6 +166,9 @@ if (R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE) { + if (gcptrlist_size(&d->stolen_objects) > 0) + stmgc_normalize_stolen_objects(); + wlog_t *entry; gcptr L; G2L_FIND(d->public_to_private, R, entry, goto not_found); @@ -818,6 +821,9 @@ (long)cur_time); revision_t localrev = stm_local_revision; + UpdateProtectedChainHeads(d, cur_time, localrev); + smp_wmb(); + revision_t newrev = -(cur_time + 1); assert(newrev & 1); ACCESS_ONCE(stm_local_revision) = newrev; @@ -825,7 +831,6 @@ assert(d->local_revision_ref = &stm_local_revision); UpdateChainHeads(d, cur_time, localrev); - UpdateProtectedChainHeads(d, cur_time, localrev); stmgc_committed_transaction(d); d->num_commits++; From noreply at buildbot.pypy.org Wed May 29 11:35:33 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 11:35:33 +0200 (CEST) Subject: [pypy-commit] pypy default: Go to some lengths to try to guess the correct paths for ncurses. Message-ID: <20130529093533.EF9811C13A2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64661:f732ef3e187a Date: 2013-05-29 11:34 +0200 http://bitbucket.org/pypy/pypy/changeset/f732ef3e187a/ Log: Go to some lengths to try to guess the correct paths for ncurses. Should fix issue667 and issue1497. diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -11,21 +11,44 @@ from sys import platform import os.path -_CYGWIN = platform == 'cygwin' -_NCURSES_CURSES = os.path.isfile("/usr/include/ncurses/curses.h") +# We cannot trust ncurses5-config, it's broken in various ways in +# various versions. For example it might not list -ltinfo even though +# it's needed, or --cflags might be completely empty. On Ubuntu 10.04 +# it gives -I/usr/include/ncurses, which doesn't exist at all. Crap. -if _CYGWIN or _NCURSES_CURSES: - eci = ExternalCompilationInfo( - includes = ['ncurses/curses.h', 'ncurses/term.h'], - libraries = ['curses'], - ) -else: - eci = ExternalCompilationInfo( - includes = ['curses.h', 'term.h'], - libraries = ['curses'], - ) +def try_cflags(): + yield ExternalCompilationInfo(includes=['curses.h', 'term.h']) + yield ExternalCompilationInfo(includes=['curses.h', 'term.h'], + include_dirs=['/usr/include/ncurses']) + yield ExternalCompilationInfo(includes=['ncurses/curses.h', + 'ncurses/term.h']) -rffi_platform.verify_eci(eci) +def try_ldflags(): + yield ExternalCompilationInfo(libraries=['curses']) + yield ExternalCompilationInfo(libraries=['curses', 'tinfo']) + +def try_eci(): + try: + eci = ExternalCompilationInfo.from_config_tool("ncurses5-configx") + except Exception: + pass + else: + yield eci.merge(ExternalCompilationInfo(includes=['curses.h', + 'term.h'])) + for eci1 in try_cflags(): + for eci2 in try_ldflags(): + yield eci1.merge(eci2) + +def guess_eci(): + for eci in try_eci(): + class CConfig: + _compilation_info_ = eci + HAS = rffi_platform.Has("setupterm") + if rffi_platform.configure(CConfig)['HAS']: + return eci + raise ImportError("failed to guess where ncurses is installed") + +eci = guess_eci() INT = rffi.INT From noreply at buildbot.pypy.org Wed May 29 11:54:36 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 11:54:36 +0200 (CEST) Subject: [pypy-commit] pypy default: More of the same: try "pkg-config ncurses" before trying "ncurses5-config", Message-ID: <20130529095436.9C0E51C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64662:c80297370acf Date: 2013-05-29 11:57 +0200 http://bitbucket.org/pypy/pypy/changeset/c80297370acf/ Log: More of the same: try "pkg-config ncurses" before trying "ncurses5-config", and both can give bogus results, so check the results and continue with hard-coded paths afterwards. diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -27,12 +27,18 @@ yield ExternalCompilationInfo(libraries=['curses']) yield ExternalCompilationInfo(libraries=['curses', 'tinfo']) -def try_eci(): +def try_tools(): try: - eci = ExternalCompilationInfo.from_config_tool("ncurses5-configx") + yield ExternalCompilationInfo.from_pkg_config("ncurses") except Exception: pass - else: + try: + yield ExternalCompilationInfo.from_config_tool("ncurses5-config") + except Exception: + pass + +def try_eci(): + for eci in try_tools(): yield eci.merge(ExternalCompilationInfo(includes=['curses.h', 'term.h'])) for eci1 in try_cflags(): diff --git a/rpython/translator/tool/cbuild.py b/rpython/translator/tool/cbuild.py --- a/rpython/translator/tool/cbuild.py +++ b/rpython/translator/tool/cbuild.py @@ -1,5 +1,5 @@ import py -import sys +import sys, subprocess from rpython.translator.platform import host from rpython.tool.udir import udir @@ -99,6 +99,7 @@ return platform return self._platform + @classmethod def from_compiler_flags(cls, flags): """Returns a new ExternalCompilationInfo instance by parsing the string 'flags', which is in the typical Unix compiler flags @@ -124,8 +125,8 @@ return cls(pre_include_bits=pre_include_bits, include_dirs=include_dirs, compile_extra=compile_extra) - from_compiler_flags = classmethod(from_compiler_flags) + @classmethod def from_linker_flags(cls, flags): """Returns a new ExternalCompilationInfo instance by parsing the string 'flags', which is in the typical Unix linker flags @@ -146,8 +147,8 @@ return cls(libraries=libraries, library_dirs=library_dirs, link_extra=link_extra) - from_linker_flags = classmethod(from_linker_flags) + @classmethod def from_config_tool(cls, execonfigtool): """Returns a new ExternalCompilationInfo instance by executing the 'execonfigtool' with --cflags and --libs arguments.""" @@ -156,12 +157,26 @@ raise ImportError("cannot find %r" % (execonfigtool,)) # we raise ImportError to be nice to the pypy.config.pypyoption # logic of skipping modules depending on non-installed libs - cflags = py.process.cmdexec('"%s" --cflags' % (str(path),)) + return cls._run_config_tool('"%s"' % (str(path),)) + + @classmethod + def from_pkg_config(cls, pkgname): + """Returns a new ExternalCompilationInfo instance by executing + 'pkg-config ' with --cflags and --libs arguments.""" + assert isinstance(pkgname, str) + popen = subprocess.Popen(['pkg-config', pkgname, '--exists']) + result = popen.wait() + if result != 0: + raise ImportError("failed: 'pkg-config %s --exists'" % pkgname) + return cls._run_config_tool('pkg-config "%s"' % pkgname) + + @classmethod + def _run_config_tool(cls, command): + cflags = py.process.cmdexec('%s --cflags' % command) eci1 = cls.from_compiler_flags(cflags) - libs = py.process.cmdexec('"%s" --libs' % (str(path),)) + libs = py.process.cmdexec('%s --libs' % command) eci2 = cls.from_linker_flags(libs) return eci1.merge(eci2) - from_config_tool = classmethod(from_config_tool) def _value(self): return tuple([getattr(self, x) From noreply at buildbot.pypy.org Wed May 29 12:05:47 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 12:05:47 +0200 (CEST) Subject: [pypy-commit] pypy default: Test and fix for from_pkg_config(). Message-ID: <20130529100547.776201C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64663:a66a2e966de1 Date: 2013-05-29 12:09 +0200 http://bitbucket.org/pypy/pypy/changeset/a66a2e966de1/ Log: Test and fix for from_pkg_config(). diff --git a/rpython/translator/tool/cbuild.py b/rpython/translator/tool/cbuild.py --- a/rpython/translator/tool/cbuild.py +++ b/rpython/translator/tool/cbuild.py @@ -164,8 +164,11 @@ """Returns a new ExternalCompilationInfo instance by executing 'pkg-config ' with --cflags and --libs arguments.""" assert isinstance(pkgname, str) - popen = subprocess.Popen(['pkg-config', pkgname, '--exists']) - result = popen.wait() + try: + popen = subprocess.Popen(['pkg-config', pkgname, '--exists']) + result = popen.wait() + except OSError: + result = -1 if result != 0: raise ImportError("failed: 'pkg-config %s --exists'" % pkgname) return cls._run_config_tool('pkg-config "%s"' % pkgname) diff --git a/rpython/translator/tool/test/test_cbuild.py b/rpython/translator/tool/test/test_cbuild.py --- a/rpython/translator/tool/test/test_cbuild.py +++ b/rpython/translator/tool/test/test_cbuild.py @@ -127,6 +127,18 @@ ExternalCompilationInfo.from_config_tool, 'dxowqbncpqympqhe-config') + def test_from_pkg_config(self): + try: + cmd = ['pkg-config', 'ncurses', '--exists'] + popen = Popen(cmd) + result = popen.wait() + except OSError: + result = -1 + if result != 0: + py.test.skip("failed: %r" % (' '.join(cmd),)) + eci = ExternalCompilationInfo.from_pkg_config('ncurses') + assert 'ncurses' in eci.libraries + def test_platforms(self): from rpython.translator.platform import Platform From noreply at buildbot.pypy.org Wed May 29 19:49:03 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 19:49:03 +0200 (CEST) Subject: [pypy-commit] stmgc default: debugging help Message-ID: <20130529174903.6125A1C018D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r50:3aea86a96daf Date: 2013-05-29 18:52 +0200 http://bitbucket.org/pypy/stmgc/changeset/3aea86a96daf/ Log: debugging help diff --git a/c3/test/model.py b/c3/test/model.py --- a/c3/test/model.py +++ b/c3/test/model.py @@ -33,9 +33,17 @@ self.globalstate = globalstate self.previous = globalstate.most_recent_committed_revision self.content = {} # mapping StmObject: [value of fields] or Deleted + print 'MODEL: NEW rev %r' % self self.read_set = set() self.committed = False + def __repr__(self): + if hasattr(self, 'commit_time'): + return '' % (id(self), + self.commit_time) + else: + return '' % (id(self),) + def _reverse_range(self, older_excluded_revision): result = [] while self is not older_excluded_revision: @@ -64,11 +72,15 @@ def _validate(self): gs = self.globalstate - print 'VALIDATE' + print 'MODEL: VALIDATE' self._extend_timestamp(gs.most_recent_committed_revision) def _commit(self, new_previous): self._extend_timestamp(new_previous) + if hasattr(self, 'start_time'): + print 'MODEL: COMMIT: start_time =', self.start_time + #if self.start_time == 82: + # import pdb;pdb.set_trace() self.committed = True del self.read_set for stmobj in self.content: @@ -78,13 +90,13 @@ while stmobj not in past.content: past = past.previous past.content[stmobj] = Deleted - print 'COMMIT: DELETING %r FROM %r' % (stmobj, past) + print 'MODEL: COMMIT: DELETING %r IN %r' % (stmobj, past) def _add_in_read_set(self, stmobj): if stmobj.created_in_revision is self: return # don't record local objects if stmobj not in self.read_set: - print 'ADD IN READ SET:', stmobj + print 'MODEL: ADD IN READ SET:', stmobj self.read_set.add(stmobj) def _try_read(self, stmobj): @@ -107,6 +119,7 @@ if content is Deleted: raise Deleted self.content[stmobj] = content[:] + print 'MODEL: TRY_WRITE: %r' % stmobj self._add_in_read_set(stmobj) return self.content[stmobj] From noreply at buildbot.pypy.org Wed May 29 19:49:04 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 19:49:04 +0200 (CEST) Subject: [pypy-commit] stmgc old1: Send this code to the 'old1' branch. Message-ID: <20130529174904.2AFD21C13AB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: old1 Changeset: r51:36a297442ce0 Date: 2013-05-29 18:53 +0200 http://bitbucket.org/pypy/stmgc/changeset/36a297442ce0/ Log: Send this code to the 'old1' branch. From noreply at buildbot.pypy.org Wed May 29 19:49:04 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 19:49:04 +0200 (CEST) Subject: [pypy-commit] stmgc default: Starting a rewrite of doc-stmgc.txt, very high-level so far, with Message-ID: <20130529174904.EC4C01C13AC@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r52:45987a0fee0b Date: 2013-05-29 19:48 +0200 http://bitbucket.org/pypy/stmgc/changeset/45987a0fee0b/ Log: Starting a rewrite of doc-stmgc.txt, very high-level so far, with changes that describe the new implementation plan. diff --git a/c3/doc-stmgc.txt b/c3/doc-stmgc.txt --- a/c3/doc-stmgc.txt +++ b/c3/doc-stmgc.txt @@ -2,23 +2,98 @@ Details of the interactions between STM and the GC ================================================== -Below, an "object" means really one version of an object, as allocated -in memory. What is from the higher level the "same" object may exist in -several versions (we say "higher level object" to mean this). Usually -these versions are objects in a linked list, chained together with the -h_revision field in the objects' headers. +In this document we say "high-level object" to mean an object from the +point of the user of the library, as opposed to an "object copy", which +occupies the space of one allocated piece of memory. One high-level +object can exist in several copies simultaneously. This concept of +"copy" should not be confused with a "revision", which stands for a +globally consistent copy of all objects. One revision is the result of +one transaction. A program usually has one revision per thread in +progress, plus any number of older committed revisions. The committed +revisions are globally ordered. -Each object is either young or old. All new objects are allocated -young. They become old at the next minor collection. In the common -case, objects are allocated in the nursery, and during the next minor -collection, they are moved outside (if they survive). The nursery -contains only young objects, but a few objects outside might be young -too (e.g. objects too large for the nursery). (In fact we found out in -PyPy that it's a good idea to create objects young even if they are -outside the nursery; otherwise, a program that creates a lot of -medium-sized objects will quickly exhaust the memory and trigger a lot -of major collections.) For the rest of this document we'll ignore young -objects outside the nursery. +The object copies exist in one of three main states: they can be +"private", "protected" or "public". A copy is private when it belongs +to the transaction in progress. When that transaction commits, it +becomes protected, and remains so as long as it is accessed only by the +same thread. A copy becomes public only when another thread requests +access to it (or, more precisely, "steals" access to it). Once public, +a copy is immutable in memory. + +From the point of view of the generational GC, each copy is either young +or old. All new copies are allocated young. They become old at the +next minor collection. In the common case, copies are allocated in the +nursery, and during the next minor collection, if they survive, they are +moved outside. The nursery contains only young copies, but a few copies +outside might be young too (e.g. copies of objects too large for the +nursery). (In fact we found out in PyPy that it's a good idea to create +objects young even if they are outside the nursery; otherwise, a program +that creates a lot of medium-sized objects will quickly exhaust the +memory and trigger a lot of major collections.) For the rest of this +document we'll ignore young copies outside the nursery. + +An object that was never seen by a different thread has got at most two +copies: the first, protected, is the copy at the latest committed +revision; and the other, private, is the current copy. If the +transaction aborts we can forget the private copy and reuse the previous +protected copy. If the transaction commits we forget the previous +protected copy instead; then at this point all private objects become +protected. If the object is modified again in the near future, we reuse +the memory that was occupied by the previous copy to store the next +private copy. As a result, each of these two spaces in memory can be +young or old. When the GC runs, if any one of these two copies is +young, only the other copy is kept. Similarly during major collections, +only one copy is kept. So objects no longer modified will eventually +consume only one space. + +The way to share data between threads goes via prebuilt objects, which +are always public: it is their existence that gives the starting point +for threads to see each other's objects. This involves three different +steps. + +1. A thread tries to write to a public object. This is done by +allocating a fresh private copy of the public object. Then writes go to +the private copy. If the transaction commits, the private copy becomes +protected, and the public object is made to point to it (with +multithread care). From now on, any access to the public object from +the same thread will work on the protected object or its future private +copy. Any access from a different thread will trigger "stealing", as +explained next. + +2. A thread tries to access a public object but finds that another +thread has committed changes to it (hereafter called the "foreign +thread"). Then we "steal" the object. It is a read-only operation +performed by peeking on the foreign thread's data. The operation +involves making a duplicate of the original copy if it was in the +foreign thread's nursery, so that no thread ever reads another thread's +nursery outside of "stealing". The stolen copy, or the original +protected copy if it was not young, is then marked as public. From now +on nobody is allocated to change the content of this copy, and it +becomes the current public copy. + +3. A subtle but important point about making a public copy is about all +references stored in the object: if they point to other protected +objects, then we cannot simply keep them as they are in the public copy. +In that case, we have to replace these references with pointers to +public "stubs". A stub consists of only the header of the object. It +is set up in the same way as in point 1 above: it plays the role of an +"older" public copy of a protected object (although it is not actually +older of course). If "we", the thread that just stole the object, then +try to follow one of the references, we will access one of these stubs, +and go back to point 1: we will need to steal it again. + + + + + + + +------------ + + + + + Independently, each object can be private or non-private (we used to say local or global). The private objects are the ones belonging to the From noreply at buildbot.pypy.org Wed May 29 21:53:48 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 29 May 2013 21:53:48 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added primitives for vmdebugging Message-ID: <20130529195348.72C331C13AE@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r422:2c471ff9ff49 Date: 2013-05-29 21:18 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/2c471ff9ff49/ Log: added primitives for vmdebugging diff --git a/spyvm/plugins/vmdebugging.py b/spyvm/plugins/vmdebugging.py --- a/spyvm/plugins/vmdebugging.py +++ b/spyvm/plugins/vmdebugging.py @@ -28,6 +28,18 @@ raise Exit('Halt is not well defined when translated.') return w_rcvr + at DebuggingPlugin.expose_primitive(unwrap_spec=[object]) +def isRSqueak(interp, s_frame, w_rcvr): + return interp.space.w_true + + at DebuggingPlugin.expose_primitive(unwrap_spec=[object]) +def isVMTranslated(interp, s_frame, w_rcvr): + from rpython.rlib.objectmodel import we_are_translated + if we_are_translated(): + return interp.space.w_true + else: + return interp.space.w_false + @DebuggingPlugin.expose_primitive(unwrap_spec=[object, object]) def debugPrint(interp, s_frame, w_rcvr, w_string): if not isinstance(w_string, model.W_BytesObject): From noreply at buildbot.pypy.org Wed May 29 21:53:46 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 29 May 2013 21:53:46 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added primitiveSetFilePosition to FilePlugin Message-ID: <20130529195346.C8AEC1C13AB@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r420:51993a43b47c Date: 2013-05-29 09:55 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/51993a43b47c/ Log: added primitiveSetFilePosition to FilePlugin diff --git a/spyvm/plugins/fileplugin.py b/spyvm/plugins/fileplugin.py --- a/spyvm/plugins/fileplugin.py +++ b/spyvm/plugins/fileplugin.py @@ -101,6 +101,14 @@ target.setchar(start + i, contents[i]) return space.wrap_int(len_read) + at FilePlugin.expose_primitive(unwrap_spec=[object, int, int]) +def primitiveFileSetPosition(interp, s_frame, w_rcvr, fd, position): + try: + os.lseek(fd, position, os.SEEK_SET) + except OSError: + raise PrimitiveFailedError + return w_rcvr + @FilePlugin.expose_primitive(unwrap_spec=[object, int]) def primitiveFileSize(interp, s_frame, w_rcvr, fd): try: From noreply at buildbot.pypy.org Wed May 29 21:53:47 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 29 May 2013 21:53:47 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed overlow-error in primitive float_times_two_raised Message-ID: <20130529195347.AE2501C13AC@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r421:5b8f06f0ec25 Date: 2013-05-29 21:18 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/5b8f06f0ec25/ Log: fixed overlow-error in primitive float_times_two_raised diff --git a/spyvm/model.py b/spyvm/model.py --- a/spyvm/model.py +++ b/spyvm/model.py @@ -387,6 +387,7 @@ if n0 == 0: return space.wrap_uint(r_uint(intmask(r >> 32))) else: + # bounds-check for primitive access is done in the primitive assert n0 == 1 return space.wrap_uint(r_uint(intmask(r))) diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -296,8 +296,14 @@ @expose_primitive(FLOAT_TIMES_TWO_POWER, unwrap_spec=[float, int]) def func(interp, s_frame, rcvr, arg): - w_res = interp.space.wrap_float(math.ldexp(rcvr, arg)) - return w_res + # http://www.python.org/dev/peps/pep-0754/ + try: + return interp.space.wrap_float(math.ldexp(rcvr, arg)) + except OverflowError: + if rcvr >= 0.0: + return model.W_Float(float('inf')) + else: + return model.W_Float(float('-inf')) @expose_primitive(FLOAT_SQUARE_ROOT, unwrap_spec=[float]) def func(interp, s_frame, f): diff --git a/spyvm/test/test_primitives.py b/spyvm/test/test_primitives.py --- a/spyvm/test/test_primitives.py +++ b/spyvm/test/test_primitives.py @@ -206,6 +206,11 @@ assert prim(primitives.FLOAT_TRUNCATED, [4.5]).value == 4 assert prim(primitives.FLOAT_TRUNCATED, [4.6]).value == 4 +def test_float_times_two_power(): + assert prim(primitives.FLOAT_TIMES_TWO_POWER, [2.0, 10]).value == 2.0 ** 11 + assert prim(primitives.FLOAT_TIMES_TWO_POWER, [-213.0, 1020]).value == float('-inf') + assert prim(primitives.FLOAT_TIMES_TWO_POWER, [213.0, 1020]).value == float('inf') + def test_at(): w_obj = mockclass(space, 0, varsized=True).as_class_get_shadow(space).new(1) foo = wrap("foo") From noreply at buildbot.pypy.org Wed May 29 21:53:49 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Wed, 29 May 2013 21:53:49 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed infinity-retrieval to be RPython-compatible Message-ID: <20130529195349.3A7721C13B0@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r423:78905cdad21d Date: 2013-05-29 21:53 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/78905cdad21d/ Log: fixed infinity-retrieval to be RPython-compatible diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -296,14 +296,15 @@ @expose_primitive(FLOAT_TIMES_TWO_POWER, unwrap_spec=[float, int]) def func(interp, s_frame, rcvr, arg): + from rpython.rlib.rfloat import INFINITY # http://www.python.org/dev/peps/pep-0754/ try: return interp.space.wrap_float(math.ldexp(rcvr, arg)) except OverflowError: if rcvr >= 0.0: - return model.W_Float(float('inf')) + return model.W_Float(INFINITY) else: - return model.W_Float(float('-inf')) + return model.W_Float(-INFINITY) @expose_primitive(FLOAT_SQUARE_ROOT, unwrap_spec=[float]) def func(interp, s_frame, f): From noreply at buildbot.pypy.org Wed May 29 23:48:36 2013 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 29 May 2013 23:48:36 +0200 (CEST) Subject: [pypy-commit] stmgc default: Read/write barriers. Message-ID: <20130529214836.B7D2F1C13AC@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r53:c61ac29e3901 Date: 2013-05-29 23:48 +0200 http://bitbucket.org/pypy/stmgc/changeset/c61ac29e3901/ Log: Read/write barriers. diff --git a/c3/doc-stmgc.txt b/c3/doc-stmgc.txt --- a/c3/doc-stmgc.txt +++ b/c3/doc-stmgc.txt @@ -65,14 +65,17 @@ thread"). Then we "steal" the object. It is a read-only operation performed by peeking on the foreign thread's data. The operation involves making a duplicate of the original copy if it was in the -foreign thread's nursery, so that no thread ever reads another thread's -nursery outside of "stealing". The stolen copy, or the original -protected copy if it was not young, is then marked as public. From now -on nobody is allocated to change the content of this copy, and it -becomes the current public copy. +foreign thread's nursery (so that no thread ever reads another thread's +nursery, outside of "stealing"). The stolen copy, or the original +protected copy if it was not in the nursery, is then marked as public. +From now on nobody is allowed to change the content of this copy, and it +becomes the current public copy. These public copies accumulate: every +time the same object is stolen by a different thread, a new public copy +is made (so that unrelated threads don't have to worry about existing +public copies being written to). 3. A subtle but important point about making a public copy is about all -references stored in the object: if they point to other protected +the references stored in the object: if they point to other protected objects, then we cannot simply keep them as they are in the public copy. In that case, we have to replace these references with pointers to public "stubs". A stub consists of only the header of the object. It @@ -80,9 +83,45 @@ "older" public copy of a protected object (although it is not actually older of course). If "we", the thread that just stole the object, then try to follow one of the references, we will access one of these stubs, -and go back to point 1: we will need to steal it again. +and go back to point 1: we will need to steal the target object's +protected copy. +Implementation +-------------- + +This design is made to optimize the hopefully common case: objects we +handle are mostly private or protected. We can design in consequence +the following three points: + +1. the extra data stored in the objects (GC flags, and one extra word +called `h_revision`). + +2. the other "off-line" data stored in thread-local data. + +3. the read/write barriers. + +Point 3 is essential for performance: we want most importantly a read +barrier that doesn't trigger for the case of reading protected and +private objects, which is supposed to be the most common case. +Moreover, it should also not trigger in the basic case of reading a +never-modified public object. There are basically three cases: + +1. read_barrier(P) = P [if P is directly a non-modified copy] + +2. read_barrier(P) = P->h_revision [a protected copy with a private one] + +3. all other more complex cases, handled by a call. + +It is possible to compress the first two cases into C code that GCC +compiles into two or three assembler instructions, using a conditional +move. (Still, it is unclear so far if case 2 is worth inlining at every +read barrier site, or should be left to the call.) + +The case of the write barrier is similar, but differs in the exact +checks: basically case 1 is only for private objects. This could be +done simply by checking a different GC flags. + From noreply at buildbot.pypy.org Thu May 30 05:37:51 2013 From: noreply at buildbot.pypy.org (mattip) Date: Thu, 30 May 2013 05:37:51 +0200 (CEST) Subject: [pypy-commit] pypy default: start to fix tests Message-ID: <20130530033751.138121C018D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r64664:ee4d83bb5d71 Date: 2013-05-30 06:09 +0300 http://bitbucket.org/pypy/pypy/changeset/ee4d83bb5d71/ Log: start to fix tests diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py --- a/pypy/module/_multiprocessing/test/test_connection.py +++ b/pypy/module/_multiprocessing/test/test_connection.py @@ -68,7 +68,12 @@ assert rhandle.readable class AppTestWinpipeConnection(BaseConnectionTest): - spaceconfig = dict(usemodules=('_multiprocessing', 'thread', 'signal')) + spaceconfig = { + "usemodules": [ + '_multiprocessing', 'thread', 'signal', 'struct', 'array', + 'itertools', '_socket', 'binascii', + ] + } def setup_class(cls): if sys.platform != "win32": @@ -180,4 +185,4 @@ assert repr(c) == '' if hasattr(_multiprocessing, 'PipeConnection'): c = _multiprocessing.PipeConnection(1) - assert repr(c) == '' + assert repr(c) == '' From noreply at buildbot.pypy.org Thu May 30 05:37:52 2013 From: noreply at buildbot.pypy.org (mattip) Date: Thu, 30 May 2013 05:37:52 +0200 (CEST) Subject: [pypy-commit] pypy default: fix one test, translation too Message-ID: <20130530033752.11C5A1C018D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r64665:f1937be96ddf Date: 2013-05-30 06:37 +0300 http://bitbucket.org/pypy/pypy/changeset/f1937be96ddf/ Log: fix one test, translation too diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -374,7 +374,7 @@ return space.wrap(self) def descr_repr(self, space): - return self._repr(space, self.handle) + return self._repr(space, rffi.cast(rffi.INTPTR_T, self.handle)) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE From noreply at buildbot.pypy.org Thu May 30 09:28:08 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 30 May 2013 09:28:08 +0200 (CEST) Subject: [pypy-commit] cffi default: Issue #81 resolved: dir(ffi.verify(...)) Message-ID: <20130530072808.3ADD41C305A@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1256:831a3f4af696 Date: 2013-05-30 09:27 +0200 http://bitbucket.org/cffi/cffi/changeset/831a3f4af696/ Log: Issue #81 resolved: dir(ffi.verify(...)) diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py --- a/cffi/vengine_cpy.py +++ b/cffi/vengine_cpy.py @@ -156,6 +156,9 @@ class FFILibrary(object): _cffi_python_module = module _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) library = FFILibrary() module._cffi_setup(lst, ffiplatform.VerificationError, library) # @@ -701,7 +704,8 @@ return ptr[0] def setter(library, value): ptr[0] = value - setattr(library.__class__, name, property(getter, setter)) + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) # ---------- diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py --- a/cffi/vengine_gen.py +++ b/cffi/vengine_gen.py @@ -74,6 +74,9 @@ class FFILibrary(types.ModuleType): _cffi_generic_module = module _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir library = FFILibrary("") # # finally, call the loaded_gen_xxx() functions. This will set @@ -168,21 +171,22 @@ newfunction = self._load_constant(False, tp, name, module) else: indirections = [] - if any(isinstance(type, model.StructOrUnion) for type in tp.args): + if any(isinstance(typ, model.StructOrUnion) for typ in tp.args): indirect_args = [] - for i, type in enumerate(tp.args): - if isinstance(type, model.StructOrUnion): - type = model.PointerType(type) - indirections.append((i, type)) - indirect_args.append(type) + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) tp = model.FunctionPtrType(tuple(indirect_args), tp.result, tp.ellipsis) BFunc = self.ffi._get_cached_btype(tp) wrappername = '_cffi_f_%s' % name newfunction = module.load_function(BFunc, wrappername) - for i, type in indirections: - newfunction = self._make_struct_wrapper(newfunction, i, type) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ) setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) def _make_struct_wrapper(self, oldfunc, i, tp): backend = self.ffi._backend @@ -390,6 +394,7 @@ is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() value = self._load_constant(is_int, tp, name, module) setattr(library, name, value) + type(library)._cffi_dir.append(name) # ---------- # enums @@ -437,6 +442,7 @@ def _loaded_gen_enum(self, tp, name, module, library): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) # ---------- # macros: for now only for integers @@ -450,6 +456,7 @@ def _loaded_gen_macro(self, tp, name, module, library): value = self._load_constant(True, tp, name, module) setattr(library, name, value) + type(library)._cffi_dir.append(name) # ---------- # global variables @@ -475,6 +482,7 @@ BArray = self.ffi._get_cached_btype(tp) value = self.ffi.cast(BArray, value) setattr(library, name, value) + type(library)._cffi_dir.append(name) return # remove ptr= from the library instance, and replace # it by a property on the class, which reads/writes into ptr[0]. @@ -486,7 +494,8 @@ return ptr[0] def setter(library, value): ptr[0] = value - setattr(library.__class__, name, property(getter, setter)) + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) cffimod_header = r''' #include diff --git a/testing/test_verify.py b/testing/test_verify.py --- a/testing/test_verify.py +++ b/testing/test_verify.py @@ -1619,3 +1619,18 @@ ffi.cdef("int f(void *);") lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }") assert lib.f(b"foobar") == ord(b"f") + +def test_dir(): + ffi = FFI() + ffi.cdef("""void somefunc(void); + extern int somevar, somearray[2]; + static char *const sv2; + enum my_e { AA, BB, ... }; + #define FOO ...""") + lib = ffi.verify("""void somefunc(void) { } + int somevar, somearray[2]; + #define sv2 "text" + enum my_e { AA, BB }; + #define FOO 42""") + assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray', + 'somefunc', 'somevar', 'sv2'] From noreply at buildbot.pypy.org Thu May 30 18:18:14 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 30 May 2013 18:18:14 +0200 (CEST) Subject: [pypy-commit] cffi default: Failing tests for issue #82. Message-ID: <20130530161814.3CE631C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1257:5494afe611a2 Date: 2013-05-30 18:16 +0200 http://bitbucket.org/cffi/cffi/changeset/5494afe611a2/ Log: Failing tests for issue #82. diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py --- a/testing/test_ffi_backend.py +++ b/testing/test_ffi_backend.py @@ -1,4 +1,4 @@ -import py +import py, sys from testing import backend_tests, test_function, test_ownlib from cffi import FFI import _cffi_backend @@ -36,3 +36,52 @@ assert ffi.from_handle(p) is o assert ffi.from_handle(ffi.cast("char *", p)) is o py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) + + +class TestBitfield: + def check(self, source, expected_ofs_y, expected_align, expected_size): + # verify the information with gcc + if sys.platform != "win32": + ffi1 = FFI() + ffi1.cdef("static const int Gofs_y, Galign, Gsize;") + lib = ffi1.verify(""" + struct s1 { %s }; + struct sa { char a; struct s1 b; }; + #define Gofs_y offsetof(struct s1, y) + #define Galign offsetof(struct sa, b) + #define Gsize sizeof(struct s1) + """ % source) + assert lib.Gofs_y == expected_ofs_y + assert lib.Galign == expected_align + assert lib.Gsize == expected_size + # the real test follows + ffi = FFI() + ffi.cdef("struct s1 { %s };" % source) + assert ffi.offsetof("struct s1", "y") == expected_ofs_y + assert ffi.alignof("struct s1") == expected_align + assert ffi.sizeof("struct s1") == expected_size + + def test_bitfield_basic(self): + self.check("int a; int b:9; int c:20; int y;", 8, 4, 12) + self.check("int a; short b:9; short c:7; int y;", 8, 4, 12) + self.check("int a; short b:9; short c:9; int y;", 8, 4, 12) + + def test_bitfield_reuse_if_enough_space(self): + self.check("char a; int b:9; char y;", 3, 4, 4) + self.check("char a; short b:9; char y;", 4, 2, 6) + + def test_bitfield_anonymous_no_align(self): + L = FFI().alignof("long long") + self.check("char x; int z:1; char y;", 2, 4, 4) + self.check("char x; int :1; char y;", 2, 1, 3) + self.check("char x; long long z:48; char y;", 7, L, 8) + self.check("char x; long long :48; char y;", 7, 1, 8) + self.check("char x; long long z:56; char y;", 8, L, 8 + L) + self.check("char x; long long :56; char y;", 8, 1, 9) + self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L) + self.check("char x; long long :57; char y;", L + 8, 1, L + 9) + + def test_bitfield_zero(self): + L = FFI().alignof("long long") + self.check("char x; int :0; char y;", 4, 1, 5) + self.check("char x; long long :0; char y;", L, 1, L + 1) From noreply at buildbot.pypy.org Thu May 30 21:03:16 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 30 May 2013 21:03:16 +0200 (CEST) Subject: [pypy-commit] cffi default: Improve the tests Message-ID: <20130530190316.5EE3E1C07BE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1258:4b188c2ba3f0 Date: 2013-05-30 19:19 +0200 http://bitbucket.org/cffi/cffi/changeset/4b188c2ba3f0/ Log: Improve the tests diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py --- a/testing/test_ffi_backend.py +++ b/testing/test_ffi_backend.py @@ -40,26 +40,63 @@ class TestBitfield: def check(self, source, expected_ofs_y, expected_align, expected_size): + ffi = FFI() + ffi.cdef("struct s1 { %s };" % source) + ctype = ffi.typeof("struct s1") # verify the information with gcc if sys.platform != "win32": ffi1 = FFI() - ffi1.cdef("static const int Gofs_y, Galign, Gsize;") + ffi1.cdef(""" + static const int Gofs_y, Galign, Gsize; + struct s1 *try_with_value(int fieldnum, long long value); + """) + fnames = [name for name, cfield in ctype.fields + if cfield.bitsize > 0] + setters = ['case %d: s.%s = value; break;' % iname + for iname in enumerate(fnames)] lib = ffi1.verify(""" struct s1 { %s }; struct sa { char a; struct s1 b; }; #define Gofs_y offsetof(struct s1, y) #define Galign offsetof(struct sa, b) #define Gsize sizeof(struct s1) - """ % source) + char *try_with_value(int fieldnum, long long value) + { + static struct s1 s; + memset(&s, 0, sizeof(s)); + switch (fieldnum) { %s } + return &s; + } + """ % (source, ' '.join(setters))) assert lib.Gofs_y == expected_ofs_y assert lib.Galign == expected_align assert lib.Gsize == expected_size + else: + lib = None + fnames = None # the real test follows - ffi = FFI() - ffi.cdef("struct s1 { %s };" % source) assert ffi.offsetof("struct s1", "y") == expected_ofs_y assert ffi.alignof("struct s1") == expected_align assert ffi.sizeof("struct s1") == expected_size + # compare the actual storage of the two + for name, cfield in ctype.fields: + if cfield.bitsize < 0: + continue + max_value = (1 << (cfield.bitsize-1)) - 1 + min_value = -(1 << (cfield.bitsize-1)) + self._fieldcheck(ffi, lib, fnames, name, 1) + self._fieldcheck(ffi, lib, fnames, name, min_value) + self._fieldcheck(ffi, lib, fnames, name, max_value) + + def _fieldcheck(self, ffi, lib, fnames, name, value): + s = ffi.new("struct s1 *") + setattr(s, name, value) + assert getattr(s, name) == value + raw1 = bytes(ffi.buffer(s)) + if lib is not None: + t = lib.try_with_value(fnames.index(name), value) + raw2 = bytes(ffi.buffer(t, len(raw1))) + assert raw1 == raw2 def test_bitfield_basic(self): self.check("int a; int b:9; int c:20; int y;", 8, 4, 12) @@ -67,11 +104,17 @@ self.check("int a; short b:9; short c:9; int y;", 8, 4, 12) def test_bitfield_reuse_if_enough_space(self): + self.check("int a:2; char y;", 1, 4, 4) self.check("char a; int b:9; char y;", 3, 4, 4) self.check("char a; short b:9; char y;", 4, 2, 6) + self.check("int a:2; char b:6; char y;", 1, 4, 4) + self.check("int a:2; char b:7; char y;", 2, 4, 4) + self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8) + self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4) def test_bitfield_anonymous_no_align(self): L = FFI().alignof("long long") + self.check("char y; int :1;", 0, 1, 2) self.check("char x; int z:1; char y;", 2, 4, 4) self.check("char x; int :1; char y;", 2, 1, 3) self.check("char x; long long z:48; char y;", 7, L, 8) @@ -83,5 +126,6 @@ def test_bitfield_zero(self): L = FFI().alignof("long long") + self.check("char y; int :0;", 0, 1, 4) self.check("char x; int :0; char y;", 4, 1, 5) self.check("char x; long long :0; char y;", L, 1, L + 1) From noreply at buildbot.pypy.org Thu May 30 21:03:17 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 30 May 2013 21:03:17 +0200 (CEST) Subject: [pypy-commit] cffi default: Fixes to the test Message-ID: <20130530190317.3CC621C10EF@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1259:34d74f06e9ae Date: 2013-05-30 20:37 +0200 http://bitbucket.org/cffi/cffi/changeset/34d74f06e9ae/ Log: Fixes to the test diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py --- a/testing/test_ffi_backend.py +++ b/testing/test_ffi_backend.py @@ -51,7 +51,7 @@ struct s1 *try_with_value(int fieldnum, long long value); """) fnames = [name for name, cfield in ctype.fields - if cfield.bitsize > 0] + if name and cfield.bitsize > 0] setters = ['case %d: s.%s = value; break;' % iname for iname in enumerate(fnames)] lib = ffi1.verify(""" @@ -60,7 +60,7 @@ #define Gofs_y offsetof(struct s1, y) #define Galign offsetof(struct sa, b) #define Gsize sizeof(struct s1) - char *try_with_value(int fieldnum, long long value) + struct s1 *try_with_value(int fieldnum, long long value) { static struct s1 s; memset(&s, 0, sizeof(s)); @@ -80,11 +80,12 @@ assert ffi.sizeof("struct s1") == expected_size # compare the actual storage of the two for name, cfield in ctype.fields: - if cfield.bitsize < 0: + if cfield.bitsize < 0 or not name: continue max_value = (1 << (cfield.bitsize-1)) - 1 min_value = -(1 << (cfield.bitsize-1)) - self._fieldcheck(ffi, lib, fnames, name, 1) + if max_value >= 1: + self._fieldcheck(ffi, lib, fnames, name, 1) self._fieldcheck(ffi, lib, fnames, name, min_value) self._fieldcheck(ffi, lib, fnames, name, max_value) @@ -105,6 +106,8 @@ def test_bitfield_reuse_if_enough_space(self): self.check("int a:2; char y;", 1, 4, 4) + self.check("int a:1; char b ; int c:1; char y;", 3, 4, 4) + self.check("int a:1; char b:8; int c:1; char y;", 3, 4, 4) self.check("char a; int b:9; char y;", 3, 4, 4) self.check("char a; short b:9; char y;", 4, 2, 6) self.check("int a:2; char b:6; char y;", 1, 4, 4) From noreply at buildbot.pypy.org Thu May 30 21:03:18 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 30 May 2013 21:03:18 +0200 (CEST) Subject: [pypy-commit] cffi default: issue #82: implement bitfields in a way that is, as far as I can tell, Message-ID: <20130530190318.292051C3007@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1260:f49f86a66a15 Date: 2013-05-30 21:02 +0200 http://bitbucket.org/cffi/cffi/changeset/f49f86a66a15/ Log: issue #82: implement bitfields in a way that is, as far as I can tell, fully compatible with gcc. diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -3429,10 +3429,10 @@ CTypeDescrObject *ct; PyObject *fields, *interned_fields, *ignored; int is_union, alignment; - Py_ssize_t offset, i, nb_fields, maxsize, prev_bit_position; + Py_ssize_t boffset, i, nb_fields, boffsetmax; Py_ssize_t totalsize = -1; int totalalignment = -1; - CFieldObject **previous, *prev_field; + CFieldObject **previous; if (!PyArg_ParseTuple(args, "O!O!|Oni:complete_struct_or_union", &CTypeDescr_Type, &ct, @@ -3454,22 +3454,20 @@ return NULL; } - maxsize = 0; alignment = 1; - offset = 0; + boffset = 0; /* this number is in *bits*, not bytes! */ + boffsetmax = 0; /* the maximum value of boffset, in bits too */ nb_fields = PyList_GET_SIZE(fields); interned_fields = PyDict_New(); if (interned_fields == NULL) return NULL; previous = (CFieldObject **)&ct->ct_extra; - prev_bit_position = 0; - prev_field = NULL; for (i=0; i 0)) alignment = falign; - /* align this field to its own 'falign' by inserting padding */ - offset = (offset + falign - 1) & ~(falign-1); - - if (foffset >= 0) { - /* a forced field position: ignore the offset just computed, - except to know if we must set CT_CUSTOM_FIELD_POS */ - if (offset != foffset) + if (fbitsize < 0) { + /* not a bitfield: common case */ + int bs_flag; + + if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0) + bs_flag = BS_EMPTY_ARRAY; + else + bs_flag = BS_REGULAR; + + /* align this field to its own 'falign' by inserting padding */ + boffset = (boffset + falign*8-1) & ~(falign*8-1); /* bits! */ + + if (foffset >= 0) { + /* a forced field position: ignore the offset just computed, + except to know if we must set CT_CUSTOM_FIELD_POS */ + if (boffset != foffset * 8) + ct->ct_flags |= CT_CUSTOM_FIELD_POS; + boffset = foffset * 8; + } + + if (PyText_GetSize(fname) == 0 && + ftype->ct_flags & (CT_STRUCT|CT_UNION)) { + /* a nested anonymous struct or union */ + CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra; + for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) { + /* broken complexity in the call to get_field_name(), + but we'll assume you never do that with nested + anonymous structures with thousand of fields */ + *previous = _add_field(interned_fields, + get_field_name(ftype, cfsrc), + cfsrc->cf_type, + boffset / 8 + cfsrc->cf_offset, + cfsrc->cf_bitshift, + cfsrc->cf_bitsize); + if (*previous == NULL) + goto error; + previous = &(*previous)->cf_next; + } + /* always forbid such structures from being passed by value */ ct->ct_flags |= CT_CUSTOM_FIELD_POS; - offset = foffset; - } - - if (fbitsize < 0 || (fbitsize == 8 * ftype->ct_size && - !(ftype->ct_flags & CT_PRIMITIVE_CHAR))) { - fbitsize = -1; - if (ftype->ct_flags & CT_ARRAY && ftype->ct_length == 0) - bitshift = BS_EMPTY_ARRAY; - else - bitshift = BS_REGULAR; - prev_bit_position = 0; - } - else { - if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED | - CT_PRIMITIVE_UNSIGNED | - CT_PRIMITIVE_CHAR)) || -#ifdef HAVE_WCHAR_H - ((ftype->ct_flags & CT_PRIMITIVE_CHAR) - && ftype->ct_size == sizeof(wchar_t)) || -#endif - fbitsize == 0 || - fbitsize > 8 * ftype->ct_size) { - PyErr_Format(PyExc_TypeError, "invalid bit field '%s'", - PyText_AS_UTF8(fname)); - goto error; } - if (prev_bit_position > 0) { - assert(prev_field && prev_field->cf_bitshift >= 0); - if (prev_field->cf_type->ct_size != ftype->ct_size) { - PyErr_SetString(PyExc_NotImplementedError, - "consecutive bit fields should be " - "declared with a same-sized type"); - goto error; - } - else if (prev_bit_position + fbitsize > 8 * ftype->ct_size) { - prev_bit_position = 0; - } - else { - /* we can share the same field as 'prev_field' */ - offset = prev_field->cf_offset; - } - } - bitshift = prev_bit_position; - if (!is_union) - prev_bit_position += fbitsize; - } - - if (PyText_GetSize(fname) == 0 && - ftype->ct_flags & (CT_STRUCT|CT_UNION)) { - /* a nested anonymous struct or union */ - CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra; - for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) { - /* broken complexity in the call to get_field_name(), - but we'll assume you never do that with nested - anonymous structures with thousand of fields */ - *previous = _add_field(interned_fields, - get_field_name(ftype, cfsrc), - cfsrc->cf_type, - offset + cfsrc->cf_offset, - cfsrc->cf_bitshift, - cfsrc->cf_bitsize); + else { + *previous = _add_field(interned_fields, fname, ftype, + boffset / 8, bs_flag, -1); if (*previous == NULL) goto error; previous = &(*previous)->cf_next; } - /* always forbid such structures from being passed by value */ - ct->ct_flags |= CT_CUSTOM_FIELD_POS; - prev_field = NULL; + boffset += ftype->ct_size * 8; } else { - prev_field = _add_field(interned_fields, fname, ftype, - offset, bitshift, fbitsize); - if (prev_field == NULL) + /* this is the case of a bitfield */ + Py_ssize_t field_offset_bytes; + int bits_already_occupied, bitshift; + + if (foffset >= 0) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' is a bitfield, " + "but a fixed offset is specified", + ct->ct_name, PyText_AS_UTF8(fname)); goto error; - *previous = prev_field; - previous = &prev_field->cf_next; + } + + if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED | + CT_PRIMITIVE_CHAR))) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' declared as '%s' cannot be a bit field", + ct->ct_name, PyText_AS_UTF8(fname), + ftype->ct_name); + goto error; + } + if (fbitsize > 8 * ftype->ct_size) { + PyErr_Format(PyExc_TypeError, + "bit field '%s.%s' is declared '%s:%d', which " + "exceeds the width of the type", + ct->ct_name, PyText_AS_UTF8(fname), + ftype->ct_name, fbitsize); + goto error; + } + + /* compute the starting position of the theoretical field + that covers a complete 'ftype', inside of which we will + locate the real bitfield */ + field_offset_bytes = boffset / 8; + field_offset_bytes &= ~(falign - 1); + + if (fbitsize == 0) { + if (PyText_GetSize(fname) > 0) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' is declared with :0", + ct->ct_name, PyText_AS_UTF8(fname)); + } + if (boffset > field_offset_bytes * 8) { + field_offset_bytes += falign; + assert(boffset < field_offset_bytes * 8); + } + boffset = field_offset_bytes * 8; /* the only effect */ + } + else { + /* Can the field start at the offset given by 'boffset'? It + can if it would entirely fit into an aligned ftype field. */ + bits_already_occupied = boffset - (field_offset_bytes * 8); + + if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) { + /* it would not fit, we need to start at the next + allowed position */ + field_offset_bytes += falign; + assert(boffset < field_offset_bytes * 8); + boffset = field_offset_bytes * 8; + bitshift = 0; + } + else + bitshift = bits_already_occupied; + + *previous = _add_field(interned_fields, fname, ftype, + field_offset_bytes, bitshift, fbitsize); + if (*previous == NULL) + goto error; + previous = &(*previous)->cf_next; + boffset += fbitsize; + } } - if (maxsize < ftype->ct_size) - maxsize = ftype->ct_size; - if (!is_union) - offset += ftype->ct_size; + if (boffset > boffsetmax) + boffsetmax = boffset; } *previous = NULL; - if (is_union) { - assert(offset == 0); - offset = maxsize; - } - /* Like C, if the size of this structure would be zero, we compute it as 1 instead. But for ctypes support, we allow the manually- specified totalsize to be zero in this case. */ + boffsetmax = (boffsetmax + 7) / 8; /* bits -> bytes */ if (totalsize < 0) { - offset = (offset + alignment - 1) & ~(alignment-1); - totalsize = (offset == 0 ? 1 : offset); - } - else if (totalsize < offset) { + totalsize = (boffsetmax + alignment - 1) & ~(alignment-1); + if (totalsize == 0) + totalsize = 1; + } + else if (totalsize < boffsetmax) { PyErr_Format(PyExc_TypeError, "%s cannot be of size %zd: there are fields at least " - "up to %zd", ct->ct_name, totalsize, offset); + "up to %zd", ct->ct_name, totalsize, boffsetmax); goto error; } ct->ct_size = totalsize; diff --git a/c/test_c.py b/c/test_c.py --- a/c/test_c.py +++ b/c/test_c.py @@ -2768,6 +2768,35 @@ assert wr() is None py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) +def test_bitfield_as_gcc(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BInt = new_primitive_type("int") + BStruct = new_struct_type("foo1") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('b', BInt, 9), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 3) + assert sizeof(BStruct) == 4 + assert alignof(BStruct) == 4 + # + BStruct = new_struct_type("foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BShort, 9), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + # + BStruct = new_struct_type("foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BInt, 0), + ('', BInt, 0), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + def test_version(): # this test is here mostly for PyPy diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py --- a/testing/test_ffi_backend.py +++ b/testing/test_ffi_backend.py @@ -82,12 +82,16 @@ for name, cfield in ctype.fields: if cfield.bitsize < 0 or not name: continue - max_value = (1 << (cfield.bitsize-1)) - 1 - min_value = -(1 << (cfield.bitsize-1)) - if max_value >= 1: - self._fieldcheck(ffi, lib, fnames, name, 1) - self._fieldcheck(ffi, lib, fnames, name, min_value) - self._fieldcheck(ffi, lib, fnames, name, max_value) + if int(ffi.cast(cfield.type, -1)) == -1: # signed + min_value = -(1 << (cfield.bitsize-1)) + max_value = (1 << (cfield.bitsize-1)) - 1 + else: + min_value = 0 + max_value = (1 << cfield.bitsize) - 1 + for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729, + -1,-2,-4,-8,-16,-128,-2813,-89728,-981729]: + if min_value <= t <= max_value: + self._fieldcheck(ffi, lib, fnames, name, t) def _fieldcheck(self, ffi, lib, fnames, name, value): s = ffi.new("struct s1 *") @@ -132,3 +136,14 @@ self.check("char y; int :0;", 0, 1, 4) self.check("char x; int :0; char y;", 4, 1, 5) self.check("char x; long long :0; char y;", L, 1, L + 1) + self.check("short x, y; int :0; int :0;", 2, 2, 4) + self.check("char x; int :0; short b:1; char y;", 5, 2, 6) + + def test_error_cases(self): + ffi = FFI() + py.test.raises(TypeError, + 'ffi.cdef("struct s1 { float x:1; };"); ffi.new("struct s1 *")') + py.test.raises(TypeError, + 'ffi.cdef("struct s2 { char x:0; };"); ffi.new("struct s2 *")') + py.test.raises(TypeError, + 'ffi.cdef("struct s3 { char x:9; };"); ffi.new("struct s3 *")') From noreply at buildbot.pypy.org Thu May 30 21:29:23 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 30 May 2013 21:29:23 +0200 (CEST) Subject: [pypy-commit] pypy default: Update to cffi/f49f86a66a15. Message-ID: <20130530192923.157261C3017@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64666:5ae00b3c5ed9 Date: 2013-05-30 21:28 +0200 http://bitbucket.org/pypy/pypy/changeset/5ae00b3c5ed9/ Log: Update to cffi/f49f86a66a15. diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -156,6 +156,9 @@ class FFILibrary(object): _cffi_python_module = module _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) library = FFILibrary() module._cffi_setup(lst, ffiplatform.VerificationError, library) # @@ -701,7 +704,8 @@ return ptr[0] def setter(library, value): ptr[0] = value - setattr(library.__class__, name, property(getter, setter)) + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) # ---------- diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -74,6 +74,9 @@ class FFILibrary(types.ModuleType): _cffi_generic_module = module _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir library = FFILibrary("") # # finally, call the loaded_gen_xxx() functions. This will set @@ -168,21 +171,22 @@ newfunction = self._load_constant(False, tp, name, module) else: indirections = [] - if any(isinstance(type, model.StructOrUnion) for type in tp.args): + if any(isinstance(typ, model.StructOrUnion) for typ in tp.args): indirect_args = [] - for i, type in enumerate(tp.args): - if isinstance(type, model.StructOrUnion): - type = model.PointerType(type) - indirections.append((i, type)) - indirect_args.append(type) + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) tp = model.FunctionPtrType(tuple(indirect_args), tp.result, tp.ellipsis) BFunc = self.ffi._get_cached_btype(tp) wrappername = '_cffi_f_%s' % name newfunction = module.load_function(BFunc, wrappername) - for i, type in indirections: - newfunction = self._make_struct_wrapper(newfunction, i, type) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ) setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) def _make_struct_wrapper(self, oldfunc, i, tp): backend = self.ffi._backend @@ -390,6 +394,7 @@ is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() value = self._load_constant(is_int, tp, name, module) setattr(library, name, value) + type(library)._cffi_dir.append(name) # ---------- # enums @@ -437,6 +442,7 @@ def _loaded_gen_enum(self, tp, name, module, library): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) # ---------- # macros: for now only for integers @@ -450,6 +456,7 @@ def _loaded_gen_macro(self, tp, name, module, library): value = self._load_constant(True, tp, name, module) setattr(library, name, value) + type(library)._cffi_dir.append(name) # ---------- # global variables @@ -475,6 +482,7 @@ BArray = self.ffi._get_cached_btype(tp) value = self.ffi.cast(BArray, value) setattr(library, name, value) + type(library)._cffi_dir.append(name) return # remove ptr= from the library instance, and replace # it by a property on the class, which reads/writes into ptr[0]. @@ -486,7 +494,8 @@ return ptr[0] def setter(library, value): ptr[0] = value - setattr(library.__class__, name, property(getter, setter)) + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) cffimod_header = r''' #include diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py --- a/pypy/module/_cffi_backend/newtype.py +++ b/pypy/module/_cffi_backend/newtype.py @@ -131,13 +131,12 @@ " struct or union ctype")) is_union = isinstance(w_ctype, ctypestruct.W_CTypeUnion) - maxsize = 1 alignment = 1 - offset = 0 + boffset = 0 # this number is in *bits*, not bytes! + boffsetmax = 0 # the maximum value of boffset, in bits too fields_w = space.listview(w_fields) fields_list = [] fields_dict = {} - prev_bit_position = 0 custom_field_pos = False for w_field in fields_w: @@ -161,92 +160,129 @@ "field '%s.%s' has ctype '%s' of unknown size", w_ctype.name, fname, ftype.name) # + if is_union: + boffset = 0 # reset each field at offset 0 + # + # update the total alignment requirement, but skip it if the + # field is an anonymous bitfield falign = ftype.alignof() - if alignment < falign: + if alignment < falign and (fbitsize < 0 or fname != ''): alignment = falign # - if foffset < 0: + if fbitsize < 0: + # not a bitfield: common case + + if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length==0: + bs_flag = ctypestruct.W_CField.BS_EMPTY_ARRAY + else: + bs_flag = ctypestruct.W_CField.BS_REGULAR + # align this field to its own 'falign' by inserting padding - offset = (offset + falign - 1) & ~(falign - 1) + boffset = (boffset + falign*8-1) & ~(falign*8-1) + + if foffset >= 0: + # a forced field position: ignore the offset just computed, + # except to know if we must set 'custom_field_pos' + custom_field_pos |= (boffset != foffset * 8) + boffset = foffset * 8 + + if (fname == '' and + isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)): + # a nested anonymous struct or union + srcfield2names = {} + for name, srcfld in ftype.fields_dict.items(): + srcfield2names[srcfld] = name + for srcfld in ftype.fields_list: + fld = srcfld.make_shifted(boffset // 8) + fields_list.append(fld) + try: + fields_dict[srcfield2names[srcfld]] = fld + except KeyError: + pass + # always forbid such structures from being passed by value + custom_field_pos = True + else: + # a regular field + fld = ctypestruct.W_CField(ftype, boffset // 8, bs_flag, -1) + fields_list.append(fld) + fields_dict[fname] = fld + + boffset += ftype.size * 8 + else: - # a forced field position: ignore the offset just computed, - # except to know if we must set 'custom_field_pos' - custom_field_pos |= (offset != foffset) - offset = foffset - # - if fbitsize < 0 or ( - fbitsize == 8 * ftype.size and not - isinstance(ftype, ctypeprim.W_CTypePrimitiveCharOrUniChar)): - fbitsize = -1 - if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length == 0: - bitshift = ctypestruct.W_CField.BS_EMPTY_ARRAY + # this is the case of a bitfield + + if foffset >= 0: + raise operationerrfmt(space.w_TypeError, + "field '%s.%s' is a bitfield, " + "but a fixed offset is specified", + w_ctype.name, fname) + + if not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or + isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or + isinstance(ftype,ctypeprim.W_CTypePrimitiveCharOrUniChar)): + raise operationerrfmt(space.w_TypeError, + "field '%s.%s' declared as '%s' " + "cannot be a bit field", + w_ctype.name, fname, ftype.name) + if fbitsize > 8 * ftype.size: + raise operationerrfmt(space.w_TypeError, + "bit field '%s.%s' is declared '%s:%d'," + " which exceeds the width of the type", + w_ctype.name, fname, + ftype.name, fbitsize) + + # compute the starting position of the theoretical field + # that covers a complete 'ftype', inside of which we will + # locate the real bitfield + field_offset_bytes = boffset // 8 + field_offset_bytes &= ~(falign - 1) + + if fbitsize == 0: + if fname != '': + raise operationerrfmt(space.w_TypeError, + "field '%s.%s' is declared with :0", + w_ctype.name, fname) + if boffset > field_offset_bytes * 8: + field_offset_bytes += falign + assert boffset < field_offset_bytes * 8 + boffset = field_offset_bytes * 8 else: - bitshift = ctypestruct.W_CField.BS_REGULAR - prev_bit_position = 0 - else: - if (not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or - isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or - isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)) or - fbitsize == 0 or - fbitsize > 8 * ftype.size): - raise operationerrfmt(space.w_TypeError, - "invalid bit field '%s'", fname) - if prev_bit_position > 0: - prev_field = fields_list[-1] - assert prev_field.bitshift >= 0 - if prev_field.ctype.size != ftype.size: - raise OperationError(space.w_NotImplementedError, - space.wrap("consecutive bit fields should be " - "declared with a same-sized type")) - if prev_bit_position + fbitsize > 8 * ftype.size: - prev_bit_position = 0 + # Can the field start at the offset given by 'boffset'? It + # can if it would entirely fit into an aligned ftype field. + bits_already_occupied = boffset - (field_offset_bytes * 8) + + if bits_already_occupied + fbitsize > 8 * ftype.size: + # it would not fit, we need to start at the next + # allowed position + field_offset_bytes += falign + assert boffset < field_offset_bytes * 8 + boffset = field_offset_bytes * 8 + bitshift = 0 else: - # we can share the same field as 'prev_field' - offset = prev_field.offset - bitshift = prev_bit_position - if not is_union: - prev_bit_position += fbitsize - # - if (len(fname) == 0 and - isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)): - # a nested anonymous struct or union - srcfield2names = {} - for name, srcfld in ftype.fields_dict.items(): - srcfield2names[srcfld] = name - for srcfld in ftype.fields_list: - fld = srcfld.make_shifted(offset) + bitshift = bits_already_occupied + + fld = ctypestruct.W_CField(ftype, field_offset_bytes, + bitshift, fbitsize) fields_list.append(fld) - try: - fields_dict[srcfield2names[srcfld]] = fld - except KeyError: - pass - # always forbid such structures from being passed by value - custom_field_pos = True - else: - # a regular field - fld = ctypestruct.W_CField(ftype, offset, bitshift, fbitsize) - fields_list.append(fld) - fields_dict[fname] = fld - # - if maxsize < ftype.size: - maxsize = ftype.size - if not is_union: - offset += ftype.size + fields_dict[fname] = fld + + boffset += fbitsize - if is_union: - assert offset == 0 - offset = maxsize + if boffset > boffsetmax: + boffsetmax = boffset # Like C, if the size of this structure would be zero, we compute it # as 1 instead. But for ctypes support, we allow the manually- # specified totalsize to be zero in this case. + got = (boffsetmax + 7) // 8 if totalsize < 0: - offset = (offset + alignment - 1) & ~(alignment - 1) - totalsize = offset or 1 - elif totalsize < offset: + totalsize = (got + alignment - 1) & ~(alignment - 1) + totalsize = totalsize or 1 + elif totalsize < got: raise operationerrfmt(space.w_TypeError, "%s cannot be of size %d: there are fields at least " - "up to %d", w_ctype.name, totalsize, offset) + "up to %d", w_ctype.name, totalsize, got) if totalalignment < 0: totalalignment = alignment 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 @@ -2757,6 +2757,35 @@ assert wr() is None py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) +def test_bitfield_as_gcc(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BInt = new_primitive_type("int") + BStruct = new_struct_type("foo1") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('b', BInt, 9), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 3) + assert sizeof(BStruct) == 4 + assert alignof(BStruct) == 4 + # + BStruct = new_struct_type("foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BShort, 9), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + # + BStruct = new_struct_type("foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BInt, 0), + ('', BInt, 0), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + def test_version(): # this test is here mostly for PyPy diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -1,5 +1,5 @@ # Generated by pypy/tool/import_cffi.py -import py +import py, sys from pypy.module.test_lib_pypy.cffi_tests import backend_tests, test_function, test_ownlib from cffi import FFI import _cffi_backend @@ -37,3 +37,114 @@ assert ffi.from_handle(p) is o assert ffi.from_handle(ffi.cast("char *", p)) is o py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) + + +class TestBitfield: + def check(self, source, expected_ofs_y, expected_align, expected_size): + ffi = FFI() + ffi.cdef("struct s1 { %s };" % source) + ctype = ffi.typeof("struct s1") + # verify the information with gcc + if sys.platform != "win32": + ffi1 = FFI() + ffi1.cdef(""" + static const int Gofs_y, Galign, Gsize; + struct s1 *try_with_value(int fieldnum, long long value); + """) + fnames = [name for name, cfield in ctype.fields + if name and cfield.bitsize > 0] + setters = ['case %d: s.%s = value; break;' % iname + for iname in enumerate(fnames)] + lib = ffi1.verify(""" + struct s1 { %s }; + struct sa { char a; struct s1 b; }; + #define Gofs_y offsetof(struct s1, y) + #define Galign offsetof(struct sa, b) + #define Gsize sizeof(struct s1) + struct s1 *try_with_value(int fieldnum, long long value) + { + static struct s1 s; + memset(&s, 0, sizeof(s)); + switch (fieldnum) { %s } + return &s; + } + """ % (source, ' '.join(setters))) + assert lib.Gofs_y == expected_ofs_y + assert lib.Galign == expected_align + assert lib.Gsize == expected_size + else: + lib = None + fnames = None + # the real test follows + assert ffi.offsetof("struct s1", "y") == expected_ofs_y + assert ffi.alignof("struct s1") == expected_align + assert ffi.sizeof("struct s1") == expected_size + # compare the actual storage of the two + for name, cfield in ctype.fields: + if cfield.bitsize < 0 or not name: + continue + if int(ffi.cast(cfield.type, -1)) == -1: # signed + min_value = -(1 << (cfield.bitsize-1)) + max_value = (1 << (cfield.bitsize-1)) - 1 + else: + min_value = 0 + max_value = (1 << cfield.bitsize) - 1 + for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729, + -1,-2,-4,-8,-16,-128,-2813,-89728,-981729]: + if min_value <= t <= max_value: + self._fieldcheck(ffi, lib, fnames, name, t) + + def _fieldcheck(self, ffi, lib, fnames, name, value): + s = ffi.new("struct s1 *") + setattr(s, name, value) + assert getattr(s, name) == value + raw1 = bytes(ffi.buffer(s)) + if lib is not None: + t = lib.try_with_value(fnames.index(name), value) + raw2 = bytes(ffi.buffer(t, len(raw1))) + assert raw1 == raw2 + + def test_bitfield_basic(self): + self.check("int a; int b:9; int c:20; int y;", 8, 4, 12) + self.check("int a; short b:9; short c:7; int y;", 8, 4, 12) + self.check("int a; short b:9; short c:9; int y;", 8, 4, 12) + + def test_bitfield_reuse_if_enough_space(self): + self.check("int a:2; char y;", 1, 4, 4) + self.check("int a:1; char b ; int c:1; char y;", 3, 4, 4) + self.check("int a:1; char b:8; int c:1; char y;", 3, 4, 4) + self.check("char a; int b:9; char y;", 3, 4, 4) + self.check("char a; short b:9; char y;", 4, 2, 6) + self.check("int a:2; char b:6; char y;", 1, 4, 4) + self.check("int a:2; char b:7; char y;", 2, 4, 4) + self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8) + self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4) + + def test_bitfield_anonymous_no_align(self): + L = FFI().alignof("long long") + self.check("char y; int :1;", 0, 1, 2) + self.check("char x; int z:1; char y;", 2, 4, 4) + self.check("char x; int :1; char y;", 2, 1, 3) + self.check("char x; long long z:48; char y;", 7, L, 8) + self.check("char x; long long :48; char y;", 7, 1, 8) + self.check("char x; long long z:56; char y;", 8, L, 8 + L) + self.check("char x; long long :56; char y;", 8, 1, 9) + self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L) + self.check("char x; long long :57; char y;", L + 8, 1, L + 9) + + def test_bitfield_zero(self): + L = FFI().alignof("long long") + self.check("char y; int :0;", 0, 1, 4) + self.check("char x; int :0; char y;", 4, 1, 5) + self.check("char x; long long :0; char y;", L, 1, L + 1) + self.check("short x, y; int :0; int :0;", 2, 2, 4) + self.check("char x; int :0; short b:1; char y;", 5, 2, 6) + + def test_error_cases(self): + ffi = FFI() + py.test.raises(TypeError, + 'ffi.cdef("struct s1 { float x:1; };"); ffi.new("struct s1 *")') + py.test.raises(TypeError, + 'ffi.cdef("struct s2 { char x:0; };"); ffi.new("struct s2 *")') + py.test.raises(TypeError, + 'ffi.cdef("struct s3 { char x:9; };"); ffi.new("struct s3 *")') diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py @@ -1620,3 +1620,18 @@ ffi.cdef("int f(void *);") lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }") assert lib.f(b"foobar") == ord(b"f") + +def test_dir(): + ffi = FFI() + ffi.cdef("""void somefunc(void); + extern int somevar, somearray[2]; + static char *const sv2; + enum my_e { AA, BB, ... }; + #define FOO ...""") + lib = ffi.verify("""void somefunc(void) { } + int somevar, somearray[2]; + #define sv2 "text" + enum my_e { AA, BB }; + #define FOO 42""") + assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray', + 'somefunc', 'somevar', 'sv2'] From noreply at buildbot.pypy.org Thu May 30 21:34:37 2013 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 30 May 2013 21:34:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Bah. Fix Message-ID: <20130530193437.1D2B31C3017@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64667:ab8e1d8571e9 Date: 2013-05-30 21:33 +0200 http://bitbucket.org/pypy/pypy/changeset/ab8e1d8571e9/ Log: Bah. Fix diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -6,6 +6,11 @@ def test_bug1(): if not sys.platform.startswith('linux'): py.test.skip("linux-only test") + if '__pypy__' not in sys.builtin_module_names: + try: + import cffi + except ImportError, e: + py.test.skip(str(e)) cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] From noreply at buildbot.pypy.org Thu May 30 21:42:04 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 30 May 2013 21:42:04 +0200 (CEST) Subject: [pypy-commit] pypy default: simplify Message-ID: <20130530194204.68C801C0189@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64668:1cb8c9339d1a Date: 2013-05-30 12:31 -0700 http://bitbucket.org/pypy/pypy/changeset/1cb8c9339d1a/ Log: simplify diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py --- a/pypy/objspace/std/stdtypedef.py +++ b/pypy/objspace/std/stdtypedef.py @@ -147,21 +147,12 @@ else: plural = '' return "unsupported operand type%s for %%s: %s" % ( - plural, ', '.join(["'%s'"] * nbargs)) + plural, ', '.join(["'%T'"] * nbargs)) _gettypeerrormsg._annspecialcase_ = 'specialize:memo' -def _gettypenames(space, *args_w): - if args_w: - typename = space.type(args_w[-1]).getname(space) - return _gettypenames(space, *args_w[:-1]) + (typename,) - return () -_gettypenames._always_inline_ = True - def gettypeerror(space, operatorsymbol, *args_w): msg = _gettypeerrormsg(len(args_w)) - type_names = _gettypenames(space, *args_w) - return operationerrfmt(space.w_TypeError, msg, - operatorsymbol, *type_names) + return operationerrfmt(space.w_TypeError, msg, operatorsymbol, *args_w) def make_perform_trampoline(prefix, exprargs, expr, miniglobals, multimethod, selfindex=0, allow_NotImplemented_results=False): From noreply at buildbot.pypy.org Thu May 30 21:42:05 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 30 May 2013 21:42:05 +0200 (CEST) Subject: [pypy-commit] pypy default: pep8/cleanup Message-ID: <20130530194205.663431C0189@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64669:70fa23917d87 Date: 2013-05-30 12:33 -0700 http://bitbucket.org/pypy/pypy/changeset/70fa23917d87/ Log: pep8/cleanup diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -1,24 +1,22 @@ +from rpython.rtyper.lltypesystem import lltype, rffi + from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.argument import Arguments -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.function import ClassMethod, Method, StaticMethod from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import ( - BuiltinFunction, Method, StaticMethod, ClassMethod) -from rpython.rtyper.lltypesystem import rffi, lltype -from pypy.module.cpyext.pyobject import (PyObject, from_ref, make_ref, - make_typedescr, Py_DecRef) +from pypy.interpreter.typedef import ( + GetSetProperty, TypeDef, interp_attrproperty, interp_attrproperty_w) from pypy.module.cpyext.api import ( - generic_cpy_call, cpython_api, PyObject, cpython_struct, METH_KEYWORDS, - METH_O, CONST_STRING, METH_CLASS, METH_STATIC, METH_COEXIST, METH_NOARGS, - METH_VARARGS, build_type_checkers, PyObjectFields, bootstrap_function) -from pypy.module.cpyext.pyerrors import PyErr_Occurred -from rpython.rlib.objectmodel import we_are_translated + CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O, + METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function, + build_type_checkers, cpython_api, cpython_struct, generic_cpy_call) +from pypy.module.cpyext.pyobject import ( + Py_DecRef, from_ref, make_ref, make_typedescr) PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction') PyCFunction = lltype.Ptr(lltype.FuncType([PyObject, PyObject], PyObject)) -PyCFunctionKwArgs = lltype.Ptr(lltype.FuncType([PyObject, PyObject, PyObject], PyObject)) +PyCFunctionKwArgs = lltype.Ptr(lltype.FuncType([PyObject, PyObject, PyObject], + PyObject)) PyMethodDef = cpython_struct( 'PyMethodDef', @@ -89,9 +87,9 @@ self.name + "() takes no arguments")) elif flags & METH_O: if length != 1: - raise OperationError(space.w_TypeError, - space.wrap("%s() takes exactly one argument (%d given)" % ( - self.name, length))) + msg = "%s() takes exactly one argument (%d given)" + raise operationerrfmt(space.w_TypeError, msg, + self.name, length) w_arg = space.getitem(w_args, space.wrap(0)) return generic_cpy_call(space, func, w_self, w_arg) elif flags & METH_VARARGS: @@ -126,9 +124,12 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) + return self.getrepr(self.space, + "built-in method '%s' of '%s' object" % + (self.name, self.w_objclass.getname(self.space))) -PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) +PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers( + "CFunction", W_PyCFunctionObject) class W_PyCClassMethodObject(W_PyCFunctionObject): w_self = None @@ -142,12 +143,14 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) + return self.getrepr(self.space, + "built-in method '%s' of '%s' object" % + (self.name, self.w_objclass.getname(self.space))) class W_PyCWrapperObject(W_Root): - def __init__(self, space, pto, method_name, wrapper_func, wrapper_func_kwds, - doc, func): + def __init__(self, space, pto, method_name, wrapper_func, + wrapper_func_kwds, doc, func): self.space = space self.method_name = method_name self.wrapper_func = wrapper_func @@ -160,7 +163,8 @@ def call(self, space, w_self, w_args, w_kw): if self.wrapper_func is None: assert self.wrapper_func_kwds is not None - return self.wrapper_func_kwds(space, w_self, w_args, self.func, w_kw) + return self.wrapper_func_kwds(space, w_self, w_args, self.func, + w_kw) if space.is_true(w_kw): raise operationerrfmt( space.w_TypeError, @@ -169,8 +173,9 @@ return self.wrapper_func(space, w_self, w_args, self.func) def descr_method_repr(self): - return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space))) + return self.space.wrap("" % + (self.method_name, + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) @@ -243,7 +248,8 @@ __get__ = interp2app(cclassmethod_descr_get), __call__ = interp2app(cmethod_descr_call), __name__ = interp_attrproperty('name', cls=W_PyCClassMethodObject), - __objclass__ = interp_attrproperty_w('w_objclass', cls=W_PyCClassMethodObject), + __objclass__ = interp_attrproperty_w('w_objclass', + cls=W_PyCClassMethodObject), __repr__ = interp2app(W_PyCClassMethodObject.descr_method_repr), ) W_PyCClassMethodObject.typedef.acceptable_as_base_class = False @@ -287,18 +293,19 @@ def PyDescr_NewClassMethod(space, w_type, method): return space.wrap(W_PyCClassMethodObject(space, method, w_type)) -def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, wrapper_func_kwds, - doc, func): +def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, + wrapper_func_kwds, doc, func): # not exactly the API sig return space.wrap(W_PyCWrapperObject(space, pto, method_name, wrapper_func, wrapper_func_kwds, doc, func)) @cpython_api([lltype.Ptr(PyMethodDef), PyObject, CONST_STRING], PyObject) def Py_FindMethod(space, table, w_obj, name_ptr): - """Return a bound method object for an extension type implemented in C. This - can be useful in the implementation of a tp_getattro or - tp_getattr handler that does not use the - PyObject_GenericGetAttr() function.""" + """Return a bound method object for an extension type implemented in + C. This can be useful in the implementation of a tp_getattro or + tp_getattr handler that does not use the PyObject_GenericGetAttr() + function. + """ # XXX handle __doc__ name = rffi.charp2str(name_ptr) @@ -310,10 +317,12 @@ while True: i = i + 1 method = methods[i] - if not method.c_ml_name: break + if not method.c_ml_name: + break if name == "__methods__": - method_list_w.append(space.wrap(rffi.charp2str(method.c_ml_name))) - elif rffi.charp2str(method.c_ml_name) == name: # XXX expensive copying + method_list_w.append( + space.wrap(rffi.charp2str(method.c_ml_name))) + elif rffi.charp2str(method.c_ml_name) == name: # XXX expensive copy return space.wrap(W_PyCFunctionObject(space, method, w_obj)) if name == "__methods__": return space.newlist(method_list_w) From noreply at buildbot.pypy.org Thu May 30 21:42:06 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 30 May 2013 21:42:06 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130530194206.8E0C71C0189@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64670:f76c1466005a Date: 2013-05-30 12:36 -0700 http://bitbucket.org/pypy/pypy/changeset/f76c1466005a/ Log: merge default diff --git a/lib_pypy/cffi/vengine_cpy.py b/lib_pypy/cffi/vengine_cpy.py --- a/lib_pypy/cffi/vengine_cpy.py +++ b/lib_pypy/cffi/vengine_cpy.py @@ -156,6 +156,9 @@ class FFILibrary(object): _cffi_python_module = module _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) library = FFILibrary() module._cffi_setup(lst, ffiplatform.VerificationError, library) # @@ -701,7 +704,8 @@ return ptr[0] def setter(library, value): ptr[0] = value - setattr(library.__class__, name, property(getter, setter)) + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) # ---------- diff --git a/lib_pypy/cffi/vengine_gen.py b/lib_pypy/cffi/vengine_gen.py --- a/lib_pypy/cffi/vengine_gen.py +++ b/lib_pypy/cffi/vengine_gen.py @@ -74,6 +74,9 @@ class FFILibrary(types.ModuleType): _cffi_generic_module = module _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir library = FFILibrary("") # # finally, call the loaded_gen_xxx() functions. This will set @@ -168,21 +171,22 @@ newfunction = self._load_constant(False, tp, name, module) else: indirections = [] - if any(isinstance(type, model.StructOrUnion) for type in tp.args): + if any(isinstance(typ, model.StructOrUnion) for typ in tp.args): indirect_args = [] - for i, type in enumerate(tp.args): - if isinstance(type, model.StructOrUnion): - type = model.PointerType(type) - indirections.append((i, type)) - indirect_args.append(type) + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) tp = model.FunctionPtrType(tuple(indirect_args), tp.result, tp.ellipsis) BFunc = self.ffi._get_cached_btype(tp) wrappername = '_cffi_f_%s' % name newfunction = module.load_function(BFunc, wrappername) - for i, type in indirections: - newfunction = self._make_struct_wrapper(newfunction, i, type) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ) setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) def _make_struct_wrapper(self, oldfunc, i, tp): backend = self.ffi._backend @@ -390,6 +394,7 @@ is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() value = self._load_constant(is_int, tp, name, module) setattr(library, name, value) + type(library)._cffi_dir.append(name) # ---------- # enums @@ -437,6 +442,7 @@ def _loaded_gen_enum(self, tp, name, module, library): for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) # ---------- # macros: for now only for integers @@ -450,6 +456,7 @@ def _loaded_gen_macro(self, tp, name, module, library): value = self._load_constant(True, tp, name, module) setattr(library, name, value) + type(library)._cffi_dir.append(name) # ---------- # global variables @@ -475,6 +482,7 @@ BArray = self.ffi._get_cached_btype(tp) value = self.ffi.cast(BArray, value) setattr(library, name, value) + type(library)._cffi_dir.append(name) return # remove ptr= from the library instance, and replace # it by a property on the class, which reads/writes into ptr[0]. @@ -486,7 +494,8 @@ return ptr[0] def setter(library, value): ptr[0] = value - setattr(library.__class__, name, property(getter, setter)) + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) cffimod_header = r''' #include diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py --- a/pypy/module/_cffi_backend/newtype.py +++ b/pypy/module/_cffi_backend/newtype.py @@ -131,13 +131,12 @@ " struct or union ctype")) is_union = isinstance(w_ctype, ctypestruct.W_CTypeUnion) - maxsize = 1 alignment = 1 - offset = 0 + boffset = 0 # this number is in *bits*, not bytes! + boffsetmax = 0 # the maximum value of boffset, in bits too fields_w = space.listview(w_fields) fields_list = [] fields_dict = {} - prev_bit_position = 0 custom_field_pos = False for w_field in fields_w: @@ -161,92 +160,129 @@ "field '%s.%s' has ctype '%s' of unknown size", w_ctype.name, fname, ftype.name) # + if is_union: + boffset = 0 # reset each field at offset 0 + # + # update the total alignment requirement, but skip it if the + # field is an anonymous bitfield falign = ftype.alignof() - if alignment < falign: + if alignment < falign and (fbitsize < 0 or fname != ''): alignment = falign # - if foffset < 0: + if fbitsize < 0: + # not a bitfield: common case + + if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length==0: + bs_flag = ctypestruct.W_CField.BS_EMPTY_ARRAY + else: + bs_flag = ctypestruct.W_CField.BS_REGULAR + # align this field to its own 'falign' by inserting padding - offset = (offset + falign - 1) & ~(falign - 1) + boffset = (boffset + falign*8-1) & ~(falign*8-1) + + if foffset >= 0: + # a forced field position: ignore the offset just computed, + # except to know if we must set 'custom_field_pos' + custom_field_pos |= (boffset != foffset * 8) + boffset = foffset * 8 + + if (fname == '' and + isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)): + # a nested anonymous struct or union + srcfield2names = {} + for name, srcfld in ftype.fields_dict.items(): + srcfield2names[srcfld] = name + for srcfld in ftype.fields_list: + fld = srcfld.make_shifted(boffset // 8) + fields_list.append(fld) + try: + fields_dict[srcfield2names[srcfld]] = fld + except KeyError: + pass + # always forbid such structures from being passed by value + custom_field_pos = True + else: + # a regular field + fld = ctypestruct.W_CField(ftype, boffset // 8, bs_flag, -1) + fields_list.append(fld) + fields_dict[fname] = fld + + boffset += ftype.size * 8 + else: - # a forced field position: ignore the offset just computed, - # except to know if we must set 'custom_field_pos' - custom_field_pos |= (offset != foffset) - offset = foffset - # - if fbitsize < 0 or ( - fbitsize == 8 * ftype.size and not - isinstance(ftype, ctypeprim.W_CTypePrimitiveCharOrUniChar)): - fbitsize = -1 - if isinstance(ftype, ctypearray.W_CTypeArray) and ftype.length == 0: - bitshift = ctypestruct.W_CField.BS_EMPTY_ARRAY + # this is the case of a bitfield + + if foffset >= 0: + raise operationerrfmt(space.w_TypeError, + "field '%s.%s' is a bitfield, " + "but a fixed offset is specified", + w_ctype.name, fname) + + if not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or + isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or + isinstance(ftype,ctypeprim.W_CTypePrimitiveCharOrUniChar)): + raise operationerrfmt(space.w_TypeError, + "field '%s.%s' declared as '%s' " + "cannot be a bit field", + w_ctype.name, fname, ftype.name) + if fbitsize > 8 * ftype.size: + raise operationerrfmt(space.w_TypeError, + "bit field '%s.%s' is declared '%s:%d'," + " which exceeds the width of the type", + w_ctype.name, fname, + ftype.name, fbitsize) + + # compute the starting position of the theoretical field + # that covers a complete 'ftype', inside of which we will + # locate the real bitfield + field_offset_bytes = boffset // 8 + field_offset_bytes &= ~(falign - 1) + + if fbitsize == 0: + if fname != '': + raise operationerrfmt(space.w_TypeError, + "field '%s.%s' is declared with :0", + w_ctype.name, fname) + if boffset > field_offset_bytes * 8: + field_offset_bytes += falign + assert boffset < field_offset_bytes * 8 + boffset = field_offset_bytes * 8 else: - bitshift = ctypestruct.W_CField.BS_REGULAR - prev_bit_position = 0 - else: - if (not (isinstance(ftype, ctypeprim.W_CTypePrimitiveSigned) or - isinstance(ftype, ctypeprim.W_CTypePrimitiveUnsigned) or - isinstance(ftype, ctypeprim.W_CTypePrimitiveChar)) or - fbitsize == 0 or - fbitsize > 8 * ftype.size): - raise operationerrfmt(space.w_TypeError, - "invalid bit field '%s'", fname) - if prev_bit_position > 0: - prev_field = fields_list[-1] - assert prev_field.bitshift >= 0 - if prev_field.ctype.size != ftype.size: - raise OperationError(space.w_NotImplementedError, - space.wrap("consecutive bit fields should be " - "declared with a same-sized type")) - if prev_bit_position + fbitsize > 8 * ftype.size: - prev_bit_position = 0 + # Can the field start at the offset given by 'boffset'? It + # can if it would entirely fit into an aligned ftype field. + bits_already_occupied = boffset - (field_offset_bytes * 8) + + if bits_already_occupied + fbitsize > 8 * ftype.size: + # it would not fit, we need to start at the next + # allowed position + field_offset_bytes += falign + assert boffset < field_offset_bytes * 8 + boffset = field_offset_bytes * 8 + bitshift = 0 else: - # we can share the same field as 'prev_field' - offset = prev_field.offset - bitshift = prev_bit_position - if not is_union: - prev_bit_position += fbitsize - # - if (len(fname) == 0 and - isinstance(ftype, ctypestruct.W_CTypeStructOrUnion)): - # a nested anonymous struct or union - srcfield2names = {} - for name, srcfld in ftype.fields_dict.items(): - srcfield2names[srcfld] = name - for srcfld in ftype.fields_list: - fld = srcfld.make_shifted(offset) + bitshift = bits_already_occupied + + fld = ctypestruct.W_CField(ftype, field_offset_bytes, + bitshift, fbitsize) fields_list.append(fld) - try: - fields_dict[srcfield2names[srcfld]] = fld - except KeyError: - pass - # always forbid such structures from being passed by value - custom_field_pos = True - else: - # a regular field - fld = ctypestruct.W_CField(ftype, offset, bitshift, fbitsize) - fields_list.append(fld) - fields_dict[fname] = fld - # - if maxsize < ftype.size: - maxsize = ftype.size - if not is_union: - offset += ftype.size + fields_dict[fname] = fld + + boffset += fbitsize - if is_union: - assert offset == 0 - offset = maxsize + if boffset > boffsetmax: + boffsetmax = boffset # Like C, if the size of this structure would be zero, we compute it # as 1 instead. But for ctypes support, we allow the manually- # specified totalsize to be zero in this case. + got = (boffsetmax + 7) // 8 if totalsize < 0: - offset = (offset + alignment - 1) & ~(alignment - 1) - totalsize = offset or 1 - elif totalsize < offset: + totalsize = (got + alignment - 1) & ~(alignment - 1) + totalsize = totalsize or 1 + elif totalsize < got: raise operationerrfmt(space.w_TypeError, "%s cannot be of size %d: there are fields at least " - "up to %d", w_ctype.name, totalsize, offset) + "up to %d", w_ctype.name, totalsize, got) if totalalignment < 0: totalalignment = alignment 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 @@ -2757,6 +2757,35 @@ assert wr() is None py.test.raises(RuntimeError, from_handle, cast(BCharP, 0)) +def test_bitfield_as_gcc(): + BChar = new_primitive_type("char") + BShort = new_primitive_type("short") + BInt = new_primitive_type("int") + BStruct = new_struct_type("foo1") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('b', BInt, 9), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 3) + assert sizeof(BStruct) == 4 + assert alignof(BStruct) == 4 + # + BStruct = new_struct_type("foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BShort, 9), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + # + BStruct = new_struct_type("foo2") + complete_struct_or_union(BStruct, [('a', BChar, -1), + ('', BInt, 0), + ('', BInt, 0), + ('c', BChar, -1)]) + assert typeoffsetof(BStruct, 'c') == (BChar, 4) + assert sizeof(BStruct) == 5 + assert alignof(BStruct) == 1 + def test_version(): # this test is here mostly for PyPy diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -11,21 +11,50 @@ from sys import platform import os.path -_CYGWIN = platform == 'cygwin' -_NCURSES_CURSES = os.path.isfile("/usr/include/ncurses/curses.h") +# We cannot trust ncurses5-config, it's broken in various ways in +# various versions. For example it might not list -ltinfo even though +# it's needed, or --cflags might be completely empty. On Ubuntu 10.04 +# it gives -I/usr/include/ncurses, which doesn't exist at all. Crap. -if _CYGWIN or _NCURSES_CURSES: - eci = ExternalCompilationInfo( - includes = ['ncurses/curses.h', 'ncurses/term.h'], - libraries = ['curses'], - ) -else: - eci = ExternalCompilationInfo( - includes = ['curses.h', 'term.h'], - libraries = ['curses'], - ) +def try_cflags(): + yield ExternalCompilationInfo(includes=['curses.h', 'term.h']) + yield ExternalCompilationInfo(includes=['curses.h', 'term.h'], + include_dirs=['/usr/include/ncurses']) + yield ExternalCompilationInfo(includes=['ncurses/curses.h', + 'ncurses/term.h']) -rffi_platform.verify_eci(eci) +def try_ldflags(): + yield ExternalCompilationInfo(libraries=['curses']) + yield ExternalCompilationInfo(libraries=['curses', 'tinfo']) + +def try_tools(): + try: + yield ExternalCompilationInfo.from_pkg_config("ncurses") + except Exception: + pass + try: + yield ExternalCompilationInfo.from_config_tool("ncurses5-config") + except Exception: + pass + +def try_eci(): + for eci in try_tools(): + yield eci.merge(ExternalCompilationInfo(includes=['curses.h', + 'term.h'])) + for eci1 in try_cflags(): + for eci2 in try_ldflags(): + yield eci1.merge(eci2) + +def guess_eci(): + for eci in try_eci(): + class CConfig: + _compilation_info_ = eci + HAS = rffi_platform.Has("setupterm") + if rffi_platform.configure(CConfig)['HAS']: + return eci + raise ImportError("failed to guess where ncurses is installed") + +eci = guess_eci() INT = rffi.INT diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -374,7 +374,7 @@ return space.wrap(self) def descr_repr(self, space): - return self._repr(space, self.handle) + return self._repr(space, rffi.cast(rffi.INTPTR_T, self.handle)) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py --- a/pypy/module/_multiprocessing/test/test_connection.py +++ b/pypy/module/_multiprocessing/test/test_connection.py @@ -67,7 +67,12 @@ assert rhandle.readable class AppTestWinpipeConnection(BaseConnectionTest): - spaceconfig = dict(usemodules=('_multiprocessing', 'thread', 'signal')) + spaceconfig = { + "usemodules": [ + '_multiprocessing', 'thread', 'signal', 'struct', 'array', + 'itertools', '_socket', 'binascii', + ] + } def setup_class(cls): if sys.platform != "win32": @@ -179,4 +184,4 @@ assert repr(c) == '' if hasattr(_multiprocessing, 'PipeConnection'): c = _multiprocessing.PipeConnection(1) - assert repr(c) == '' + assert repr(c) == '' diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -1,24 +1,22 @@ +from rpython.rtyper.lltypesystem import lltype, rffi + from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.argument import Arguments -from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w +from pypy.interpreter.error import OperationError, operationerrfmt +from pypy.interpreter.function import ClassMethod, Method, StaticMethod from pypy.interpreter.gateway import interp2app -from pypy.interpreter.error import OperationError, operationerrfmt -from pypy.interpreter.function import ( - BuiltinFunction, Method, StaticMethod, ClassMethod) -from rpython.rtyper.lltypesystem import rffi, lltype -from pypy.module.cpyext.pyobject import (PyObject, from_ref, make_ref, - make_typedescr, Py_DecRef) +from pypy.interpreter.typedef import ( + GetSetProperty, TypeDef, interp_attrproperty, interp_attrproperty_w) from pypy.module.cpyext.api import ( - generic_cpy_call, cpython_api, PyObject, cpython_struct, METH_KEYWORDS, - METH_O, CONST_STRING, METH_CLASS, METH_STATIC, METH_COEXIST, METH_NOARGS, - METH_VARARGS, build_type_checkers, PyObjectFields, bootstrap_function) -from pypy.module.cpyext.pyerrors import PyErr_Occurred -from rpython.rlib.objectmodel import we_are_translated + CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O, + METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function, + build_type_checkers, cpython_api, cpython_struct, generic_cpy_call) +from pypy.module.cpyext.pyobject import ( + Py_DecRef, from_ref, make_ref, make_typedescr) PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction') PyCFunction = lltype.Ptr(lltype.FuncType([PyObject, PyObject], PyObject)) -PyCFunctionKwArgs = lltype.Ptr(lltype.FuncType([PyObject, PyObject, PyObject], PyObject)) +PyCFunctionKwArgs = lltype.Ptr(lltype.FuncType([PyObject, PyObject, PyObject], + PyObject)) PyMethodDef = cpython_struct( 'PyMethodDef', @@ -89,9 +87,9 @@ self.name + "() takes no arguments")) elif flags & METH_O: if length != 1: - raise OperationError(space.w_TypeError, - space.wrap("%s() takes exactly one argument (%d given)" % ( - self.name, length))) + msg = "%s() takes exactly one argument (%d given)" + raise operationerrfmt(space.w_TypeError, msg, + self.name, length) w_arg = space.getitem(w_args, space.wrap(0)) return generic_cpy_call(space, func, w_self, w_arg) elif flags & METH_VARARGS: @@ -126,9 +124,12 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) + return self.getrepr(self.space, + "built-in method '%s' of '%s' object" % + (self.name, self.w_objclass.getname(self.space))) -PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject) +PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers( + "CFunction", W_PyCFunctionObject) class W_PyCClassMethodObject(W_PyCFunctionObject): w_self = None @@ -142,12 +143,14 @@ return self.space.unwrap(self.descr_method_repr()) def descr_method_repr(self): - return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space))) + return self.getrepr(self.space, + "built-in method '%s' of '%s' object" % + (self.name, self.w_objclass.getname(self.space))) class W_PyCWrapperObject(W_Root): - def __init__(self, space, pto, method_name, wrapper_func, wrapper_func_kwds, - doc, func): + def __init__(self, space, pto, method_name, wrapper_func, + wrapper_func_kwds, doc, func): self.space = space self.method_name = method_name self.wrapper_func = wrapper_func @@ -160,7 +163,8 @@ def call(self, space, w_self, w_args, w_kw): if self.wrapper_func is None: assert self.wrapper_func_kwds is not None - return self.wrapper_func_kwds(space, w_self, w_args, self.func, w_kw) + return self.wrapper_func_kwds(space, w_self, w_args, self.func, + w_kw) if space.is_true(w_kw): raise operationerrfmt( space.w_TypeError, @@ -169,8 +173,9 @@ return self.wrapper_func(space, w_self, w_args, self.func) def descr_method_repr(self): - return self.space.wrap("" % (self.method_name, - self.w_objclass.getname(self.space))) + return self.space.wrap("" % + (self.method_name, + self.w_objclass.getname(self.space))) def cwrapper_descr_call(space, w_self, __args__): self = space.interp_w(W_PyCWrapperObject, w_self) @@ -240,7 +245,8 @@ __get__ = interp2app(cclassmethod_descr_get), __call__ = interp2app(cmethod_descr_call), __name__ = interp_attrproperty('name', cls=W_PyCClassMethodObject), - __objclass__ = interp_attrproperty_w('w_objclass', cls=W_PyCClassMethodObject), + __objclass__ = interp_attrproperty_w('w_objclass', + cls=W_PyCClassMethodObject), __repr__ = interp2app(W_PyCClassMethodObject.descr_method_repr), ) W_PyCClassMethodObject.typedef.acceptable_as_base_class = False @@ -284,18 +290,19 @@ def PyDescr_NewClassMethod(space, w_type, method): return space.wrap(W_PyCClassMethodObject(space, method, w_type)) -def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, wrapper_func_kwds, - doc, func): +def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, + wrapper_func_kwds, doc, func): # not exactly the API sig return space.wrap(W_PyCWrapperObject(space, pto, method_name, wrapper_func, wrapper_func_kwds, doc, func)) @cpython_api([lltype.Ptr(PyMethodDef), PyObject, CONST_STRING], PyObject) def Py_FindMethod(space, table, w_obj, name_ptr): - """Return a bound method object for an extension type implemented in C. This - can be useful in the implementation of a tp_getattro or - tp_getattr handler that does not use the - PyObject_GenericGetAttr() function.""" + """Return a bound method object for an extension type implemented in + C. This can be useful in the implementation of a tp_getattro or + tp_getattr handler that does not use the PyObject_GenericGetAttr() + function. + """ # XXX handle __doc__ name = rffi.charp2str(name_ptr) @@ -307,10 +314,12 @@ while True: i = i + 1 method = methods[i] - if not method.c_ml_name: break + if not method.c_ml_name: + break if name == "__methods__": - method_list_w.append(space.wrap(rffi.charp2str(method.c_ml_name))) - elif rffi.charp2str(method.c_ml_name) == name: # XXX expensive copying + method_list_w.append( + space.wrap(rffi.charp2str(method.c_ml_name))) + elif rffi.charp2str(method.c_ml_name) == name: # XXX expensive copy return space.wrap(W_PyCFunctionObject(space, method, w_obj)) if name == "__methods__": return space.newlist(method_list_w) diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -1,5 +1,5 @@ # Generated by pypy/tool/import_cffi.py -import py +import py, sys from pypy.module.test_lib_pypy.cffi_tests import backend_tests, test_function, test_ownlib from cffi import FFI import _cffi_backend @@ -37,3 +37,114 @@ assert ffi.from_handle(p) is o assert ffi.from_handle(ffi.cast("char *", p)) is o py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) + + +class TestBitfield: + def check(self, source, expected_ofs_y, expected_align, expected_size): + ffi = FFI() + ffi.cdef("struct s1 { %s };" % source) + ctype = ffi.typeof("struct s1") + # verify the information with gcc + if sys.platform != "win32": + ffi1 = FFI() + ffi1.cdef(""" + static const int Gofs_y, Galign, Gsize; + struct s1 *try_with_value(int fieldnum, long long value); + """) + fnames = [name for name, cfield in ctype.fields + if name and cfield.bitsize > 0] + setters = ['case %d: s.%s = value; break;' % iname + for iname in enumerate(fnames)] + lib = ffi1.verify(""" + struct s1 { %s }; + struct sa { char a; struct s1 b; }; + #define Gofs_y offsetof(struct s1, y) + #define Galign offsetof(struct sa, b) + #define Gsize sizeof(struct s1) + struct s1 *try_with_value(int fieldnum, long long value) + { + static struct s1 s; + memset(&s, 0, sizeof(s)); + switch (fieldnum) { %s } + return &s; + } + """ % (source, ' '.join(setters))) + assert lib.Gofs_y == expected_ofs_y + assert lib.Galign == expected_align + assert lib.Gsize == expected_size + else: + lib = None + fnames = None + # the real test follows + assert ffi.offsetof("struct s1", "y") == expected_ofs_y + assert ffi.alignof("struct s1") == expected_align + assert ffi.sizeof("struct s1") == expected_size + # compare the actual storage of the two + for name, cfield in ctype.fields: + if cfield.bitsize < 0 or not name: + continue + if int(ffi.cast(cfield.type, -1)) == -1: # signed + min_value = -(1 << (cfield.bitsize-1)) + max_value = (1 << (cfield.bitsize-1)) - 1 + else: + min_value = 0 + max_value = (1 << cfield.bitsize) - 1 + for t in [1, 2, 4, 8, 16, 128, 2813, 89728, 981729, + -1,-2,-4,-8,-16,-128,-2813,-89728,-981729]: + if min_value <= t <= max_value: + self._fieldcheck(ffi, lib, fnames, name, t) + + def _fieldcheck(self, ffi, lib, fnames, name, value): + s = ffi.new("struct s1 *") + setattr(s, name, value) + assert getattr(s, name) == value + raw1 = bytes(ffi.buffer(s)) + if lib is not None: + t = lib.try_with_value(fnames.index(name), value) + raw2 = bytes(ffi.buffer(t, len(raw1))) + assert raw1 == raw2 + + def test_bitfield_basic(self): + self.check("int a; int b:9; int c:20; int y;", 8, 4, 12) + self.check("int a; short b:9; short c:7; int y;", 8, 4, 12) + self.check("int a; short b:9; short c:9; int y;", 8, 4, 12) + + def test_bitfield_reuse_if_enough_space(self): + self.check("int a:2; char y;", 1, 4, 4) + self.check("int a:1; char b ; int c:1; char y;", 3, 4, 4) + self.check("int a:1; char b:8; int c:1; char y;", 3, 4, 4) + self.check("char a; int b:9; char y;", 3, 4, 4) + self.check("char a; short b:9; char y;", 4, 2, 6) + self.check("int a:2; char b:6; char y;", 1, 4, 4) + self.check("int a:2; char b:7; char y;", 2, 4, 4) + self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8) + self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4) + + def test_bitfield_anonymous_no_align(self): + L = FFI().alignof("long long") + self.check("char y; int :1;", 0, 1, 2) + self.check("char x; int z:1; char y;", 2, 4, 4) + self.check("char x; int :1; char y;", 2, 1, 3) + self.check("char x; long long z:48; char y;", 7, L, 8) + self.check("char x; long long :48; char y;", 7, 1, 8) + self.check("char x; long long z:56; char y;", 8, L, 8 + L) + self.check("char x; long long :56; char y;", 8, 1, 9) + self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L) + self.check("char x; long long :57; char y;", L + 8, 1, L + 9) + + def test_bitfield_zero(self): + L = FFI().alignof("long long") + self.check("char y; int :0;", 0, 1, 4) + self.check("char x; int :0; char y;", 4, 1, 5) + self.check("char x; long long :0; char y;", L, 1, L + 1) + self.check("short x, y; int :0; int :0;", 2, 2, 4) + self.check("char x; int :0; short b:1; char y;", 5, 2, 6) + + def test_error_cases(self): + ffi = FFI() + py.test.raises(TypeError, + 'ffi.cdef("struct s1 { float x:1; };"); ffi.new("struct s1 *")') + py.test.raises(TypeError, + 'ffi.cdef("struct s2 { char x:0; };"); ffi.new("struct s2 *")') + py.test.raises(TypeError, + 'ffi.cdef("struct s3 { char x:9; };"); ffi.new("struct s3 *")') diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_verify.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_verify.py @@ -1620,3 +1620,18 @@ ffi.cdef("int f(void *);") lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }") assert lib.f(b"foobar") == ord(b"f") + +def test_dir(): + ffi = FFI() + ffi.cdef("""void somefunc(void); + extern int somevar, somearray[2]; + static char *const sv2; + enum my_e { AA, BB, ... }; + #define FOO ...""") + lib = ffi.verify("""void somefunc(void) { } + int somevar, somearray[2]; + #define sv2 "text" + enum my_e { AA, BB }; + #define FOO 42""") + assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray', + 'somefunc', 'somevar', 'sv2'] diff --git a/pypy/objspace/std/stdtypedef.py b/pypy/objspace/std/stdtypedef.py --- a/pypy/objspace/std/stdtypedef.py +++ b/pypy/objspace/std/stdtypedef.py @@ -147,21 +147,12 @@ else: plural = '' return "unsupported operand type%s for %%s: %s" % ( - plural, ', '.join(["'%s'"] * nbargs)) + plural, ', '.join(["'%T'"] * nbargs)) _gettypeerrormsg._annspecialcase_ = 'specialize:memo' -def _gettypenames(space, *args_w): - if args_w: - typename = space.type(args_w[-1]).getname(space) - return _gettypenames(space, *args_w[:-1]) + (typename,) - return () -_gettypenames._always_inline_ = True - def gettypeerror(space, operatorsymbol, *args_w): msg = _gettypeerrormsg(len(args_w)) - type_names = _gettypenames(space, *args_w) - return operationerrfmt(space.w_TypeError, msg, - operatorsymbol, *type_names) + return operationerrfmt(space.w_TypeError, msg, operatorsymbol, *args_w) def make_perform_trampoline(prefix, exprargs, expr, miniglobals, multimethod, selfindex=0, allow_NotImplemented_results=False): diff --git a/rpython/translator/tool/cbuild.py b/rpython/translator/tool/cbuild.py --- a/rpython/translator/tool/cbuild.py +++ b/rpython/translator/tool/cbuild.py @@ -1,5 +1,5 @@ import py -import sys +import sys, subprocess from rpython.translator.platform import host from rpython.tool.udir import udir @@ -99,6 +99,7 @@ return platform return self._platform + @classmethod def from_compiler_flags(cls, flags): """Returns a new ExternalCompilationInfo instance by parsing the string 'flags', which is in the typical Unix compiler flags @@ -124,8 +125,8 @@ return cls(pre_include_bits=pre_include_bits, include_dirs=include_dirs, compile_extra=compile_extra) - from_compiler_flags = classmethod(from_compiler_flags) + @classmethod def from_linker_flags(cls, flags): """Returns a new ExternalCompilationInfo instance by parsing the string 'flags', which is in the typical Unix linker flags @@ -146,8 +147,8 @@ return cls(libraries=libraries, library_dirs=library_dirs, link_extra=link_extra) - from_linker_flags = classmethod(from_linker_flags) + @classmethod def from_config_tool(cls, execonfigtool): """Returns a new ExternalCompilationInfo instance by executing the 'execonfigtool' with --cflags and --libs arguments.""" @@ -156,12 +157,29 @@ raise ImportError("cannot find %r" % (execonfigtool,)) # we raise ImportError to be nice to the pypy.config.pypyoption # logic of skipping modules depending on non-installed libs - cflags = py.process.cmdexec('"%s" --cflags' % (str(path),)) + return cls._run_config_tool('"%s"' % (str(path),)) + + @classmethod + def from_pkg_config(cls, pkgname): + """Returns a new ExternalCompilationInfo instance by executing + 'pkg-config ' with --cflags and --libs arguments.""" + assert isinstance(pkgname, str) + try: + popen = subprocess.Popen(['pkg-config', pkgname, '--exists']) + result = popen.wait() + except OSError: + result = -1 + if result != 0: + raise ImportError("failed: 'pkg-config %s --exists'" % pkgname) + return cls._run_config_tool('pkg-config "%s"' % pkgname) + + @classmethod + def _run_config_tool(cls, command): + cflags = py.process.cmdexec('%s --cflags' % command) eci1 = cls.from_compiler_flags(cflags) - libs = py.process.cmdexec('"%s" --libs' % (str(path),)) + libs = py.process.cmdexec('%s --libs' % command) eci2 = cls.from_linker_flags(libs) return eci1.merge(eci2) - from_config_tool = classmethod(from_config_tool) def _value(self): return tuple([getattr(self, x) diff --git a/rpython/translator/tool/test/test_cbuild.py b/rpython/translator/tool/test/test_cbuild.py --- a/rpython/translator/tool/test/test_cbuild.py +++ b/rpython/translator/tool/test/test_cbuild.py @@ -127,6 +127,18 @@ ExternalCompilationInfo.from_config_tool, 'dxowqbncpqympqhe-config') + def test_from_pkg_config(self): + try: + cmd = ['pkg-config', 'ncurses', '--exists'] + popen = Popen(cmd) + result = popen.wait() + except OSError: + result = -1 + if result != 0: + py.test.skip("failed: %r" % (' '.join(cmd),)) + eci = ExternalCompilationInfo.from_pkg_config('ncurses') + assert 'ncurses' in eci.libraries + def test_platforms(self): from rpython.translator.platform import Platform From noreply at buildbot.pypy.org Thu May 30 21:42:07 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 30 May 2013 21:42:07 +0200 (CEST) Subject: [pypy-commit] pypy default: merge upstream Message-ID: <20130530194207.7BAC71C0189@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: Changeset: r64671:fc8a329d4956 Date: 2013-05-30 12:41 -0700 http://bitbucket.org/pypy/pypy/changeset/fc8a329d4956/ Log: merge upstream diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -6,6 +6,11 @@ def test_bug1(): if not sys.platform.startswith('linux'): py.test.skip("linux-only test") + if '__pypy__' not in sys.builtin_module_names: + try: + import cffi + except ImportError, e: + py.test.skip(str(e)) cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] From noreply at buildbot.pypy.org Thu May 30 22:22:08 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 30 May 2013 22:22:08 +0200 (CEST) Subject: [pypy-commit] pypy py3k: simplify Message-ID: <20130530202208.D4CCD1C0189@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64672:868044c336bd Date: 2013-05-30 13:19 -0700 http://bitbucket.org/pypy/pypy/changeset/868044c336bd/ Log: simplify diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py --- a/pypy/module/__builtin__/functional.py +++ b/pypy/module/__builtin__/functional.py @@ -4,7 +4,7 @@ """ from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.interpreter.typedef import TypeDef from rpython.rlib import jit @@ -442,9 +442,8 @@ return space.sequence_index(self, w_item) if not self._contains_long(space, w_item): - item_repr = space.unicode_w(space.repr(w_item)) - msg = u"%s is not in range" % item_repr - raise OperationError(space.w_ValueError, space.wrap(msg)) + raise operationerrfmt(space.w_ValueError, "%R is not in range", + w_item) w_index = space.sub(w_item, self.w_start) return space.floordiv(w_index, self.w_step) From noreply at buildbot.pypy.org Thu May 30 22:22:09 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Thu, 30 May 2013 22:22:09 +0200 (CEST) Subject: [pypy-commit] pypy py3k: not really necessary Message-ID: <20130530202209.E335D1C07BE@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64673:b59350334937 Date: 2013-05-30 13:20 -0700 http://bitbucket.org/pypy/pypy/changeset/b59350334937/ Log: not really necessary diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py --- a/pypy/interpreter/pyopcode.py +++ b/pypy/interpreter/pyopcode.py @@ -290,9 +290,6 @@ def getconstant_w(self, index): return self.getcode().co_consts_w[index] - def getname_u(self, index): - return self.space.str_w(self.getcode().co_names_w[index]) - def getname_w(self, index): return self.getcode().co_names_w[index] @@ -628,7 +625,7 @@ self.space.delattr(w_obj, w_attributename) def STORE_GLOBAL(self, nameindex, next_instr): - varname = self.getname_u(nameindex) + varname = self.space.str_w(self.getname_w(nameindex)) w_newvalue = self.popvalue() self.space.setitem_str(self.w_globals, varname, w_newvalue) From noreply at buildbot.pypy.org Fri May 31 08:10:54 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 08:10:54 +0200 (CEST) Subject: [pypy-commit] pypy default: Add an egg-info for greenlet, like cffi. Message-ID: <20130531061054.F38FC1C00F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64674:cff6d893bf16 Date: 2013-05-31 08:10 +0200 http://bitbucket.org/pypy/pypy/changeset/cff6d893bf16/ Log: Add an egg-info for greenlet, like cffi. diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info new file mode 100644 --- /dev/null +++ b/lib_pypy/greenlet.egg-info @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: greenlet +Version: 0.4.0 +Summary: Lightweight in-process concurrent programming +Home-page: https://github.com/python-greenlet/greenlet +Author: Ralf Schmitt (for CPython), PyPy team +Author-email: pypy-dev at python.org +License: MIT License +Description: UNKNOWN +Platform: UNKNOWN From noreply at buildbot.pypy.org Fri May 31 10:22:00 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 10:22:00 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix issue #1492. Message-ID: <20130531082200.E6B671C00F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64675:d439d104a605 Date: 2013-05-31 10:21 +0200 http://bitbucket.org/pypy/pypy/changeset/d439d104a605/ Log: Fix issue #1492. Manual revert in socket.py. This re-introduces the change done in 2006 in 9db062bb60e3 (anders, implementing explicit refcounting on the underlying _socket.socket objects). It reverts a later change where, I think for goals of being more Python3-like, the refcounter was moved to the class socket._socketobject. However this later change is less compatible with CPython 2.x, as shown by eventlet. diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -96,6 +96,7 @@ _realsocket = socket +_type = type # WSA error codes if sys.platform.lower().startswith("win"): @@ -173,12 +174,18 @@ __doc__ = _realsocket.__doc__ + __slots__ = ["_sock", "__weakref__"] + def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None): if _sock is None: _sock = _realsocket(family, type, proto) + elif _type(_sock) is _realsocket: + _sock._reuse() + # PyPy note about refcounting: implemented with _reuse()/_drop() + # on the class '_socket.socket'. Python 3 did it differently + # with a reference counter on this class 'socket._socketobject' + # instead, but it is a less compatible change (breaks eventlet). self._sock = _sock - self._io_refs = 0 - self._closed = False def send(self, data, flags=0): return self._sock.send(data, flags=flags) @@ -208,7 +215,9 @@ sendto.__doc__ = _realsocket.sendto.__doc__ def close(self): - # This function should not reference any globals. See issue #808164. + s = self._sock + if type(s) is _realsocket: + s._drop() self._sock = _closedsocket() close.__doc__ = _realsocket.close.__doc__ @@ -228,24 +237,7 @@ Return a regular file object corresponding to the socket. The mode and bufsize arguments are as for the built-in open() function.""" - self._io_refs += 1 - return _fileobject(self, mode, bufsize) - - def _decref_socketios(self): - if self._io_refs > 0: - self._io_refs -= 1 - if self._closed: - self.close() - - def _real_close(self): - # This function should not reference any globals. See issue #808164. - self._sock.close() - - def close(self): - # This function should not reference any globals. See issue #808164. - self._closed = True - if self._io_refs <= 0: - self._real_close() + return _fileobject(self._sock, mode, bufsize) family = property(lambda self: self._sock.family, doc="the socket family") type = property(lambda self: self._sock.type, doc="the socket type") @@ -286,6 +278,8 @@ "_close"] def __init__(self, sock, mode='rb', bufsize=-1, close=False): + if type(sock) is _realsocket: + sock._reuse() self._sock = sock self.mode = mode # Not actually used in this version if bufsize < 0: @@ -320,16 +314,11 @@ if self._sock: self.flush() finally: - if self._sock: - if self._close: - self._sock.close() - else: - try: - self._sock._decref_socketios() - except AttributeError: - pass # bah, someone built a _fileobject manually - # with some unexpected replacement of the - # _socketobject class + s = self._sock + if type(s) is _realsocket: + s._drop() + if self._close: + self._sock.close() self._sock = None def __del__(self): From noreply at buildbot.pypy.org Fri May 31 11:55:00 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 31 May 2013 11:55:00 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added clone method to W_CompiledMethod to avoid falling back onto W_Object (NotImplemented) Implementation. Message-ID: <20130531095500.3D0B81C00F4@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r424:6d0d72844d3e Date: 2013-05-29 23:23 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/6d0d72844d3e/ Log: added clone method to W_CompiledMethod to avoid falling back onto W_Object (NotImplemented) Implementation. diff --git a/spyvm/model.py b/spyvm/model.py --- a/spyvm/model.py +++ b/spyvm/model.py @@ -1006,6 +1006,12 @@ W_AbstractObjectWithIdentityHash._become(self, w_other) return True + def clone(self, space): + copy = W_CompiledMethod(0, self.getheader()) + copy.bytes = list(self.bytes) + copy.literals = list(self.literals) + return copy + def getclass(self, space): return space.w_CompiledMethod From noreply at buildbot.pypy.org Fri May 31 11:55:01 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 31 May 2013 11:55:01 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: added size-check for varsized object creation Message-ID: <20130531095501.17D341C10EF@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r425:2126b202547a Date: 2013-05-30 15:34 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/2126b202547a/ Log: added size-check for varsized object creation diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -457,7 +457,10 @@ s_class = w_cls.as_class_get_shadow(interp.space) if not s_class.isvariable(): raise PrimitiveFailedError() - return s_class.new(size) + try: + return s_class.new(size) + except MemoryError: + raise PrimitiveFailedError @expose_primitive(ARRAY_BECOME_ONE_WAY, unwrap_spec=[object, object]) def func(interp, s_frame, w_obj1, w_obj2): From noreply at buildbot.pypy.org Fri May 31 11:55:01 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 31 May 2013 11:55:01 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: fixed #perform:withArgs:-primitive: The problem was that simply pushing the arguments might overflow the stack. Therefore, do what ContextPartShadow._sendSelector would do, except for argument-retrieval Message-ID: <20130531095501.D9BE11C00F4@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r426:870c8de33664 Date: 2013-05-30 15:36 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/870c8de33664/ Log: fixed #perform:withArgs:-primitive: The problem was that simply pushing the arguments might overflow the stack. Therefore, do what ContextPartShadow._sendSelector would do, except for argument- retrieval diff --git a/spyvm/primitives.py b/spyvm/primitives.py --- a/spyvm/primitives.py +++ b/spyvm/primitives.py @@ -1249,12 +1249,27 @@ unwrap_spec=[object, object, list], no_result=True, clean_stack=False) def func(interp, s_frame, w_rcvr, w_selector, args_w): + from spyvm.shadow import MethodNotFound argcount = len(args_w) - s_frame.pop_n(2) # removing our arguments to be substituted with args_w - # pushing the args to be popped by _sendSelector - s_frame.push_all(args_w) - s_frame._sendSelector(w_selector, argcount, interp, - w_rcvr, w_rcvr.shadow_of_my_class(interp.space)) + s_frame.pop_n(2) # removing our arguments + + assert isinstance(w_selector, model.W_BytesObject) + + try: + s_method = w_rcvr.shadow_of_my_class(interp.space).lookup(w_selector) + except MethodNotFound: + return s_frame._doesNotUnderstand(w_selector, argcount, interp, w_rcvr) + + code = s_method.primitive() + if code: + s_frame.push_all(args_w) + try: + return s_frame._call_primitive(code, interp, argcount, s_method, w_selector) + except PrimitiveFailedError: + pass # ignore this error and fall back to the Smalltalk version + s_new_frame = s_method.create_frame(interp.space, w_rcvr, args_w, s_frame) + s_frame.pop() + return interp.stack_frame(s_new_frame) @expose_primitive(SIGNAL, unwrap_spec=[object], clean_stack=False, no_result=True) def func(interp, s_frame, w_rcvr): diff --git a/spyvm/wrapper.py b/spyvm/wrapper.py --- a/spyvm/wrapper.py +++ b/spyvm/wrapper.py @@ -257,7 +257,7 @@ def tempsize(self): # We ignore the number of temps a block has, because the first # bytecodes of the block will initialize them for us. We will only - # use this information for decinding where the stack pointer should be + # use this information for deciding where the stack pointer should be # initialy. # For a finding the correct number, see BlockClosure>#numTemps in an Image. return self.size() + self.numArgs() diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -52,7 +52,6 @@ return 0 return -1 - def _run_image(interp): ap = wrapper.ProcessWrapper(space, wrapper.scheduler(space).active_process()) w_ctx = ap.suspended_context() From noreply at buildbot.pypy.org Fri May 31 11:55:02 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 31 May 2013 11:55:02 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: changed the ui-process handling in case of an explicit message send: Message-ID: <20130531095502.AC72F1C00F4@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r427:d3122742615c Date: 2013-05-30 16:31 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/d3122742615c/ Log: changed the ui-process handling in case of an explicit message send: added another primitive to vmdebugging which indicates whether the ui process should stop the VM now has to ensure that it does indeed stop when asked to diff --git a/spyvm/plugins/vmdebugging.py b/spyvm/plugins/vmdebugging.py --- a/spyvm/plugins/vmdebugging.py +++ b/spyvm/plugins/vmdebugging.py @@ -4,6 +4,9 @@ DebuggingPlugin = Plugin() +DebuggingPlugin.userdata['stop_ui'] = False +def stop_ui_process(): + DebuggingPlugin.userdata['stop_ui'] = True @DebuggingPlugin.expose_primitive(unwrap_spec=[object]) def trace(interp, s_frame, w_rcvr): @@ -46,3 +49,10 @@ raise error.PrimitiveFailedError() print w_string.as_string().replace('\r', '\n') return w_rcvr + + at DebuggingPlugin.expose_primitive(unwrap_spec=[object]) +def stopUIProcess(interp, s_frame, w_rcvr): + if DebuggingPlugin.userdata.get('stop_ui', False): + return interp.space.w_true + else: + return interp.space.w_false diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py --- a/targetimageloadingsmalltalk.py +++ b/targetimageloadingsmalltalk.py @@ -10,8 +10,11 @@ def _run_benchmark(interp, number, benchmark): + from spyvm.plugins.vmdebugging import stop_ui_process + stop_ui_process() + scheduler = wrapper.scheduler(interp.space) - w_hpp = scheduler.highest_priority_process() + w_hpp = scheduler.active_process() if space.unwrap_int(scheduler.active_process().fetch(space, 2)) > space.unwrap_int(w_hpp.fetch(space, 2)): w_hpp = scheduler.active_process() assert isinstance(w_hpp, model.W_PointersObject) @@ -36,7 +39,7 @@ # third variable is priority priority = space.unwrap_int(w_hpp.fetch(space, 2)) / 2 + 1 # Priorities below 10 are not allowed in newer versions of Squeak. - priority = max(41, priority) + priority = max(11, priority) w_benchmark_proc.store(space, 2, space.wrap_int(priority)) # make process eligible for scheduling From noreply at buildbot.pypy.org Fri May 31 11:55:03 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 31 May 2013 11:55:03 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: moved the print statement, because when halting live, that statement is always the first typed Message-ID: <20130531095503.660081C00F4@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r428:a36b18faa5c5 Date: 2013-05-30 16:32 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/a36b18faa5c5/ Log: moved the print statement, because when halting live, that statement is always the first typed diff --git a/spyvm/plugins/vmdebugging.py b/spyvm/plugins/vmdebugging.py --- a/spyvm/plugins/vmdebugging.py +++ b/spyvm/plugins/vmdebugging.py @@ -23,10 +23,10 @@ from rpython.rlib.objectmodel import we_are_translated from spyvm.error import Exit + print s_frame.print_stack() if not we_are_translated(): import pdb; pdb.set_trace() else: - print s_frame.print_stack() print s_frame raise Exit('Halt is not well defined when translated.') return w_rcvr From noreply at buildbot.pypy.org Fri May 31 11:55:04 2013 From: noreply at buildbot.pypy.org (lwassermann) Date: Fri, 31 May 2013 11:55:04 +0200 (CEST) Subject: [pypy-commit] lang-smalltalk default: committed Squeak changes for testing, etc. Message-ID: <20130531095504.2F9851C00F4@cobra.cs.uni-duesseldorf.de> Author: Lars Wassermann Branch: Changeset: r429:6952fbe9d073 Date: 2013-05-31 10:29 +0200 http://bitbucket.org/pypy/lang-smalltalk/changeset/6952fbe9d073/ Log: committed Squeak changes for testing, etc. diff --git a/SPy-Benchmarks.package/Integer.extension/instance/runTests.st b/SPy-Benchmarks.package/Integer.extension/instance/runTests.st new file mode 100644 --- /dev/null +++ b/SPy-Benchmarks.package/Integer.extension/instance/runTests.st @@ -0,0 +1,3 @@ +*SPy-Benchmarks +runTests + ^SPyRunner runKernelTests \ No newline at end of file diff --git a/SPy-Benchmarks.package/Integer.extension/methodProperties.json b/SPy-Benchmarks.package/Integer.extension/methodProperties.json --- a/SPy-Benchmarks.package/Integer.extension/methodProperties.json +++ b/SPy-Benchmarks.package/Integer.extension/methodProperties.json @@ -2,4 +2,5 @@ "class" : { }, "instance" : { - "runSPyBenchmarks" : "lw 4/29/2013 13:20" } } + "runSPyBenchmarks" : "lw 4/29/2013 13:20", + "runTests" : "lw 5/30/2013 18:02" } } diff --git a/SPy-Benchmarks.package/SPyRunner.class/class/runKernelTests.st b/SPy-Benchmarks.package/SPyRunner.class/class/runKernelTests.st new file mode 100644 --- /dev/null +++ b/SPy-Benchmarks.package/SPyRunner.class/class/runKernelTests.st @@ -0,0 +1,15 @@ +benchmarks +runKernelTests + "self runTests" + | result suite | + suite := TestSuite named: 'RSqueakVM-Tests'. + "To add later: MethodPragmaTest . WeakMessageSendTest" + {IntegerTest . InstructionClientTest . FractionTest . DelayTest . CompiledMethodTest . BehaviorTest . StopwatchTest . YearTest . TimeTest . AllocationTest . ProcessTest . ClassDescriptionTest . SmallIntegerTest . MethodContextTest . CompiledMethodComparisonTest . YearMonthWeekTest . TimespanTest . DependentsArrayTest . CategorizerTest . IntegerDigitLogicTest . SemaphoreTest . PromiseTest . DateTest . DateAndTimeEpochTest . InstVarRefLocatorTest . DateAndTimeTest . BasicBehaviorClassMetaclassTest . ExtendedNumberParserTest . TrueTest . UndefinedObjectTest . ComplexTest . ScheduleTest . CompiledMethodTrailerTest . LargePositiveIntegerTest . ScaledDecimalTest . ClassBuilderTest . SqNumberParserTest . ProtoObjectTest . NumberParsingTest . RandomTest . DateAndTimeLeapTest . TimespanDoTest . ClassTest . TimespanDoSpanAYearTest . BlockContextTest . TimeStampTest . GradientFillStyleTest . MethodPropertiesTest . WeekTest . ObjectTest . DurationTest . NumberTest . MonthTest . FalseTest . InstructionPrinterTest . MonitorTest . BooleanTest . BlockClosureTest . FloatTest . ProcessSpecificTest . LargeNegativeIntegerTest} do: [ :each | each addToSuiteFromSelectors: suite]. + suite + tests: (suite tests + reject: [ :eachTestCase | + "Those tests lead to VM-Assertion Errors, etc." + #(testBenchFib testMultiProcessWaitOnSameDelay testBehaviornewnewShouldNotCrash testAllNamedFromTo testChange testAtomicSuspend testWaitTimeoutMSecs testMonitorNotGainingUnwantedSignalsDuringUnwinding testDegreeCosForExceptionalValues testDegreeSinForExceptionalValues testInfinity1 testInfinity2) + includes: eachTestCase selector]). + result := suite run. + ^result asString \ No newline at end of file diff --git a/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json b/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json --- a/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json +++ b/SPy-Benchmarks.package/SPyRunner.class/methodProperties.json @@ -2,6 +2,7 @@ "class" : { "format:" : "lw 4/29/2013 17:13", "run" : "lw 4/29/2013 17:51", + "runKernelTests" : "lw 5/30/2013 18:03", "runShootout" : "lw 5/3/2013 14:43", "runTinyBenchmarks" : "lw 4/29/2013 17:39" }, "instance" : { diff --git a/SPy-Benchmarks.package/TestSuite.extension/instance/run..st b/SPy-Benchmarks.package/TestSuite.extension/instance/run..st new file mode 100644 --- /dev/null +++ b/SPy-Benchmarks.package/TestSuite.extension/instance/run..st @@ -0,0 +1,6 @@ +*SPy-Benchmarks +run: aResult + self tests do: [:each | + self changed: each. + SPyVM print: 'Running Test ', (each asString padded: #right to: 62 with: $ ), String tab, '(', aResult asString, ')'. + each run: aResult]. \ No newline at end of file diff --git a/SPy-Benchmarks.package/TestSuite.extension/instance/tests..st b/SPy-Benchmarks.package/TestSuite.extension/instance/tests..st new file mode 100644 --- /dev/null +++ b/SPy-Benchmarks.package/TestSuite.extension/instance/tests..st @@ -0,0 +1,3 @@ +*SPy-Benchmarks +tests: someTestCaseObjects + tests := someTestCaseObjects \ No newline at end of file diff --git a/SPy-Benchmarks.package/TestSuite.extension/methodProperties.json b/SPy-Benchmarks.package/TestSuite.extension/methodProperties.json new file mode 100644 --- /dev/null +++ b/SPy-Benchmarks.package/TestSuite.extension/methodProperties.json @@ -0,0 +1,6 @@ +{ + "class" : { + }, + "instance" : { + "run:" : "lw 5/30/2013 11:19", + "tests:" : "lw 5/29/2013 20:14" } } diff --git a/SPy-Benchmarks.package/TestSuite.extension/properties.json b/SPy-Benchmarks.package/TestSuite.extension/properties.json new file mode 100644 --- /dev/null +++ b/SPy-Benchmarks.package/TestSuite.extension/properties.json @@ -0,0 +1,2 @@ +{ + "name" : "TestSuite" } diff --git a/SPy-Benchmarks.package/monticello.meta/version b/SPy-Benchmarks.package/monticello.meta/version --- a/SPy-Benchmarks.package/monticello.meta/version +++ b/SPy-Benchmarks.package/monticello.meta/version @@ -1,1 +1,1 @@ -(name 'SPy-Benchmarks-lw.5' message 'added another benchmark' id 'cfe2797f-9dd9-4073-aa6e-86cda0ba3dbf' date '3 May 2013' time '2:43:39.36 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.4' message 'changed the test running and collecting to work with the current spy vm removed two of the shootout tests due to failure on spy' id '9d1c1e0a-0209-45d3-8e0a-220919ab5701' date '29 April 2013' time '6:07:26.686 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.3' message 'added tiny benchmarks' id 'c8214449-4009-4a64-8284-3c58395fe2bc' date '29 April 2013' time '2:15:43.242 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.2' message 'second try for an initial commit with shootout tests' id 'e538d5dc-ff13-4753-a166-bb95af0c7e0b' date '29 April 2013' time '1:41:50.098 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.1' message 'initial commit with existing Shootout tests' id '67ba6a6a-5476-4dc0-892f-de76933491e8' date '29 April 2013' time '1:40:20.34 pm' author 'lw' ancestors () stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ()) \ No newline at end of file +(name 'SPy-Benchmarks-lw.6' message 'added testing messages and modified TestSuite to print stuff' id '72f3d7a3-5e09-43e5-a783-fb7c29117a52' date '31 May 2013' time '9:35:44.102 am' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.5' message 'added another benchmark' id 'cfe2797f-9dd9-4073-aa6e-86cda0ba3dbf' date '3 May 2013' time '2:43:39.36 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.4' message 'changed the test running and collecting to work with the current spy vm removed two of the shootout tests due to failure on spy' id '9d1c1e0a-0209-45d3-8e0a-220919ab5701' date '29 April 2013' time '6:07:26.686 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.3' message 'added tiny benchmarks' id 'c8214449-4009-4a64-8284-3c58395fe2bc' date '29 April 2013' time '2:15:43.242 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.2' message 'second try for an initial commit with shootout tests' id 'e538d5dc-ff13-4753-a166-bb95af0c7e0b' date '29 April 2013' time '1:41:50.098 pm' author 'lw' ancestors ((name 'SPy-Benchmarks-lw.1' message 'initial commit with existing Shootout tests' id '67ba6a6a-5476-4dc0-892f-de76933491e8' date '29 April 2013' time '1:40:20.34 pm' author 'lw' ancestors () stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ())) stepChildren ()) \ No newline at end of file diff --git a/SPy-Debugging.package/AutoStart.extension/class/startUp..st b/SPy-Debugging.package/AutoStart.extension/class/startUp..st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/AutoStart.extension/class/startUp..st @@ -0,0 +1,29 @@ +*SPy-Debugging +startUp: resuming + "The image is either being newly started (resuming is true), or it's just been snapshotted. + If this has just been a snapshot, skip all the startup stuff." + + | startupParameters launchers | + self active ifTrue: [^self]. + self active: true. + resuming ifFalse: [^self]. + HTTPClient determineIfRunningInBrowser. + startupParameters := AbstractLauncher extractParameters. + (startupParameters includesKey: 'apiSupported' asUppercase ) + ifTrue: [ + HTTPClient browserSupportsAPI: ((startupParameters at: 'apiSupported' asUppercase) asUppercase = 'TRUE'). + HTTPClient isRunningInBrowser + ifFalse: [HTTPClient isRunningInBrowser: true]]. + SPyVM stopUIProcess ifTrue: [ + "This is used when executing benchmarks or tests" + SPyVM print: 'Image startup process going to sleep.'. + Processor activeProcess terminate]. + self checkForUpdates + ifTrue: [^self]. + self checkForPluginUpdate. + launchers := self installedLaunchers collect: [:launcher | + launcher new]. + launchers do: [:launcher | + launcher parameters: startupParameters]. + launchers do: [:launcher | + Smalltalk at: #WorldState ifPresent: [ :ws | ws addDeferredUIMessage: [launcher startUp]]] \ No newline at end of file diff --git a/SPy-Debugging.package/AutoStart.extension/methodProperties.json b/SPy-Debugging.package/AutoStart.extension/methodProperties.json new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/AutoStart.extension/methodProperties.json @@ -0,0 +1,5 @@ +{ + "class" : { + "startUp:" : "lw 5/30/2013 15:27" }, + "instance" : { + } } diff --git a/SPy-Debugging.package/AutoStart.extension/properties.json b/SPy-Debugging.package/AutoStart.extension/properties.json new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/AutoStart.extension/properties.json @@ -0,0 +1,2 @@ +{ + "name" : "AutoStart" } diff --git a/SPy-Debugging.package/SPyVM.class/class/isRunning.st b/SPy-Debugging.package/SPyVM.class/class/isRunning.st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/class/isRunning.st @@ -0,0 +1,4 @@ +as yet unclassified +isRunning + + ^false \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/class/isTranslated.st b/SPy-Debugging.package/SPyVM.class/class/isTranslated.st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/class/isTranslated.st @@ -0,0 +1,4 @@ +as yet unclassified +isTranslated + + ^true \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/class/print..st b/SPy-Debugging.package/SPyVM.class/class/print..st --- a/SPy-Debugging.package/SPyVM.class/class/print..st +++ b/SPy-Debugging.package/SPyVM.class/class/print..st @@ -1,3 +1,4 @@ as yet unclassified print: aString - \ No newline at end of file + + Transcript show: aString; cr \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/class/stopUIProcess.st b/SPy-Debugging.package/SPyVM.class/class/stopUIProcess.st new file mode 100644 --- /dev/null +++ b/SPy-Debugging.package/SPyVM.class/class/stopUIProcess.st @@ -0,0 +1,4 @@ +as yet unclassified +stopUIProcess + + ^false \ No newline at end of file diff --git a/SPy-Debugging.package/SPyVM.class/methodProperties.json b/SPy-Debugging.package/SPyVM.class/methodProperties.json --- a/SPy-Debugging.package/SPyVM.class/methodProperties.json +++ b/SPy-Debugging.package/SPyVM.class/methodProperties.json @@ -1,7 +1,10 @@ { "class" : { "halt" : "lw 4/30/2013 12:44", - "print:" : "lw 5/21/2013 11:00", + "isRunning" : "lw 5/29/2013 18:21", + "isTranslated" : "lw 5/29/2013 18:21", + "print:" : "lw 5/29/2013 20:08", + "stopUIProcess" : "lw 5/30/2013 15:27", "trace" : "lw 4/30/2013 12:44", "untrace" : "lw 4/30/2013 12:44" }, "instance" : { diff --git a/SPy-Debugging.package/monticello.meta/version b/SPy-Debugging.package/monticello.meta/version --- a/SPy-Debugging.package/monticello.meta/version +++ b/SPy-Debugging.package/monticello.meta/version @@ -1,1 +1,1 @@ -(name 'SPy-Debugging-lw.2' message 'added printing' id '26ffba4f-b747-480c-b7de-2517367fad07' date '21 May 2013' time '4:12:24.874 pm' author 'lw' ancestors ((name 'SPy-Debugging-lw.1' message 'added class for starting vm-tracing, etc.' id 'e6eeab78-6e5c-43bf-9dbc-dfdad29756bd' date '30 April 2013' time '3:54:48.262 pm' author 'lw' ancestors () stepChildren ())) stepChildren ()) \ No newline at end of file +(name 'SPy-Debugging-lw.3' message 'added some new primitives as understood by the VM' id '0ce41f18-522d-4600-84f3-66119c403f3b' date '31 May 2013' time '9:36:10.166 am' author 'lw' ancestors ((name 'SPy-Debugging-lw.2' message 'added printing' id '26ffba4f-b747-480c-b7de-2517367fad07' date '21 May 2013' time '4:12:24.874 pm' author 'lw' ancestors ((name 'SPy-Debugging-lw.1' message 'added class for starting vm-tracing, etc.' id 'e6eeab78-6e5c-43bf-9dbc-dfdad29756bd' date '30 April 2013' time '3:54:48.262 pm' author 'lw' ancestors () stepChildren ())) stepChildren ())) stepChildren ()) \ No newline at end of file From noreply at buildbot.pypy.org Fri May 31 14:54:03 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 14:54:03 +0200 (CEST) Subject: [pypy-commit] pypy default: uh? no clue Message-ID: <20130531125403.4610B1C101E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64676:d7764985be92 Date: 2013-05-31 14:53 +0200 http://bitbucket.org/pypy/pypy/changeset/d7764985be92/ Log: uh? no clue diff --git a/rpython/rlib/test/test_rlocale.py b/rpython/rlib/test/test_rlocale.py --- a/rpython/rlib/test/test_rlocale.py +++ b/rpython/rlib/test/test_rlocale.py @@ -20,8 +20,8 @@ def test_setlocale_worked(self): assert u"Ą".isupper() - raises(LocaleError, setlocale, LC_ALL, "bla bla bla") - raises(LocaleError, setlocale, 1234455, None) + py.test.raises(LocaleError, setlocale, LC_ALL, "bla bla bla") + py.test.raises(LocaleError, setlocale, 1234455, None) def test_lower_upper(self): assert isupper(ord("A")) From noreply at buildbot.pypy.org Fri May 31 15:09:46 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 15:09:46 +0200 (CEST) Subject: [pypy-commit] pypy default: Revert the changes done to cpyext which broke it. Too bad for the "nicer" Message-ID: <20130531130946.D65431C101E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64677:911bc036c3f2 Date: 2013-05-31 15:13 +0200 http://bitbucket.org/pypy/pypy/changeset/911bc036c3f2/ Log: Revert the changes done to cpyext which broke it. Too bad for the "nicer" version, but to choose, I prefer a working cpyext rather than having to look at what's wrong forever. diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,11 +32,10 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", - "thread", "itertools", "pyexpat", "_ssl", "array", + "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_ffi", - "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"] -# disabled until problems are fixed + "_continuation", "_cffi_backend", "_csv", "cppyy"] )) translation_modules = default_modules.copy() diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -26,7 +26,7 @@ from pypy.module.__builtin__.descriptor import W_Property from pypy.module.__builtin__.interp_classobj import W_ClassObject from pypy.module.__builtin__.interp_memoryview import W_MemoryView -from rpython.rlib.entrypoint import entrypoint +from rpython.rlib.entrypoint import entrypoint_lowlevel from rpython.rlib.rposix import is_valid_fd, validate_fd from rpython.rlib.unroll import unrolling_iterable from rpython.rlib.objectmodel import specialize @@ -544,38 +544,37 @@ def make_wrapper(space, callable): "NOT_RPYTHON" names = callable.api_func.argnames - argtypes = callable.api_func.argtypes - is_wrapped_list = [name.startswith("w_") for name in names] + argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes, + [name.startswith("w_") for name in names]))) fatal_value = callable.api_func.restype._defl() - lines = [] - for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)): - if is_PyObject(argtype) and is_wrapped: - new_lines = [ - 'if %(arg)s:', - ' %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))', - 'else:', - ' %(arg)s = None', - ] - for j in range(len(new_lines)): - new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i} - lines += new_lines - middle = '\n '.join(lines) - arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))]) - - source = py.code.Source(""" - def wrapper(%(args)s): + @specialize.ll() + def wrapper(*args): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference + # we hope that malloc removal removes the newtuple() that is + # inserted exactly here by the varargs specializer + rffi.stackcounter.stacks_counter += 1 + llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py retval = fatal_value boxed_args = () try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, + assert len(args) == len(callable.api_func.argtypes) + for i, (typ, is_wrapped) in argtypes_enum_ui: + arg = args[i] + if is_PyObject(typ) and is_wrapped: + if arg: + arg_conv = from_ref(space, rffi.cast(PyObject, arg)) + else: + arg_conv = None + else: + arg_conv = arg + boxed_args += (arg_conv, ) state = space.fromcache(State) - %(middle)s try: - result = callable(space, %(args)s) + result = callable(space, *boxed_args) if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, " DONE" except OperationError, e: @@ -597,8 +596,8 @@ if failed: error_value = callable.api_func.error_value if error_value is CANNOT_FAIL: - raise SystemError("The function '%%s' was not supposed to fail" - %% (callable.__name__,)) + raise SystemError("The function '%s' was not supposed to fail" + % (callable.__name__,)) retval = error_value elif is_PyObject(callable.api_func.restype): @@ -625,13 +624,8 @@ else: print str(e) pypy_debug_catch_fatal_exception() + rffi.stackcounter.stacks_counter -= 1 return retval - """ % {"middle": middle, "args": arg_spec}) - d = {} - d.update(locals()) - d.update(globals()) - exec source.compile() in d - wrapper = d['wrapper'] callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -1029,7 +1023,7 @@ export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): - deco = entrypoint("cpyext", func.argtypes, name) + deco = entrypoint_lowlevel("cpyext", func.argtypes, name, relax=True) deco(func.get_wrapper(space)) setup_init_functions(eci, translating=True) 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 @@ -342,7 +342,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=False) + error=-1, external=True) # XXX should not be exported @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py --- a/rpython/annotator/description.py +++ b/rpython/annotator/description.py @@ -215,8 +215,9 @@ if len(self._cache) != 1: raise NoStandardGraph(self) [graph] = self._cache.values() + relax_sig_check = getattr(self.pyobj, "relax_sig_check", False) if (graph.signature != self.signature or - graph.defaults != self.defaults): + graph.defaults != self.defaults) and not relax_sig_check: raise NoStandardGraph(self) return graph diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -3542,6 +3542,16 @@ s = a.build_types(f, [int]) assert s.knowntype is int + def test_relax(self): + def f(*args): + return args[0] + args[1] + f.relax_sig_check = True + def g(x): + return f(x, x - x) + a = self.RPythonAnnotator() + s = a.build_types(g, [int]) + assert a.bookkeeper.getdesc(f).getuniquegraph() + def test_cannot_raise_ll_exception(self): from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr # diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -5,13 +5,33 @@ from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import we_are_translated + +def entrypoint_lowlevel(key, argtypes, c_name=None, relax=False): + """ Note: entrypoint should call llop.gc_stack_bottom on it's own. + That's necessary for making it work with asmgcc and hence JIT + + If in doubt, use entrypoint(). + + if key == 'main' than it's included by default + """ + from rpython.translator.tool.cbuild import ExternalCompilationInfo + + def deco(func): + secondary_entrypoints.setdefault(key, []).append((func, argtypes)) + if c_name is not None: + func.c_name = c_name + if relax: + func.relax_sig_check = True + func._compilation_info = ExternalCompilationInfo( + export_symbols=[c_name or func.func_name]) + return func + return deco + + pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) def entrypoint(key, argtypes, c_name=None): - """ Note: entrypoint should call llop.gc_stack_bottom on it's own. - That's necessary for making it work with asmgcc and hence JIT - - if key == 'main' than it's included by default + """if key == 'main' than it's included by default """ from rpython.translator.tool.cbuild import ExternalCompilationInfo diff --git a/rpython/translator/c/test/test_genc.py b/rpython/translator/c/test/test_genc.py --- a/rpython/translator/c/test/test_genc.py +++ b/rpython/translator/c/test/test_genc.py @@ -522,8 +522,9 @@ f = getattr(self, "_f", None) if f is not None: return f - f = lambda arg: self.func(arg) + f = lambda *args: self.func(*args) f.c_name = self.name + f.relax_sig_check = True f.__name__ = "WRAP%s" % (self.name, ) self._f = f return f From noreply at buildbot.pypy.org Fri May 31 15:13:49 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 15:13:49 +0200 (CEST) Subject: [pypy-commit] pypy default: Finally found and fixed the bug in the tests of _ffi. Message-ID: <20130531131349.1E7C11C101E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64678:3ad734b613ec Date: 2013-05-31 13:17 +0000 http://bitbucket.org/pypy/pypy/changeset/3ad734b613ec/ Log: Finally found and fixed the bug in the tests of _ffi. diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py --- a/pypy/module/_ffi/test/test_funcptr.py +++ b/pypy/module/_ffi/test/test_funcptr.py @@ -46,6 +46,7 @@ libm = CDLL(libm_name) pow = libm.getpointer('pow', [], types.void) pow_addr = rffi.cast(rffi.LONG, pow.funcsym) + cls._libm = libm # otherwise it gets unloaded - argh! cls.w_pow_addr = space.wrap(pow_addr) class AppTestFFI(BaseAppTestFFI): From noreply at buildbot.pypy.org Fri May 31 15:19:02 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 15:19:02 +0200 (CEST) Subject: [pypy-commit] pypy default: "py.test.xfail" on a failing micronumpy test. I don't know how it could Message-ID: <20130531131903.008CB1C101E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64679:2463c888ef81 Date: 2013-05-31 15:18 +0200 http://bitbucket.org/pypy/pypy/changeset/2463c888ef81/ Log: "py.test.xfail" on a failing micronumpy test. I don't know how it could have passed in the past. diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py --- a/pypy/module/micronumpy/test/test_scalar.py +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -3,6 +3,10 @@ class AppTestScalar(BaseNumpyAppTest): spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) + def setup_class(cls): + import py + py.test.xfail("FIXME: dtype('int32') == dtype('int32') fails") + def test_pickle(self): from numpypy import dtype, int32, float64, complex128, zeros, sum from numpypy.core.multiarray import scalar From noreply at buildbot.pypy.org Fri May 31 15:20:08 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 15:20:08 +0200 (CEST) Subject: [pypy-commit] pypy default: move the setup_class down, where it will conflict if new tests are added Message-ID: <20130531132008.9223D1C101E@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64680:f095fab6a28e Date: 2013-05-31 15:19 +0200 http://bitbucket.org/pypy/pypy/changeset/f095fab6a28e/ Log: move the setup_class down, where it will conflict if new tests are added diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py --- a/pypy/module/micronumpy/test/test_scalar.py +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -3,10 +3,6 @@ class AppTestScalar(BaseNumpyAppTest): spaceconfig = dict(usemodules=["micronumpy", "binascii", "struct"]) - def setup_class(cls): - import py - py.test.xfail("FIXME: dtype('int32') == dtype('int32') fails") - def test_pickle(self): from numpypy import dtype, int32, float64, complex128, zeros, sum from numpypy.core.multiarray import scalar @@ -25,3 +21,7 @@ a = zeros(3) assert loads(dumps(sum(a))) == sum(a) + + def setup_class(cls): + import py + py.test.xfail("FIXME: dtype('int32') == dtype('int32') fails") From noreply at buildbot.pypy.org Fri May 31 15:25:04 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 15:25:04 +0200 (CEST) Subject: [pypy-commit] cffi default: Oups, fix. Message-ID: <20130531132504.6C9C81C1442@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1261:170d74235eec Date: 2013-05-31 15:24 +0200 http://bitbucket.org/cffi/cffi/changeset/170d74235eec/ Log: Oups, fix. diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py --- a/testing/test_ffi_backend.py +++ b/testing/test_ffi_backend.py @@ -97,10 +97,10 @@ s = ffi.new("struct s1 *") setattr(s, name, value) assert getattr(s, name) == value - raw1 = bytes(ffi.buffer(s)) + raw1 = ffi.buffer(s)[:] if lib is not None: t = lib.try_with_value(fnames.index(name), value) - raw2 = bytes(ffi.buffer(t, len(raw1))) + raw2 = ffi.buffer(t, len(raw1))[:] assert raw1 == raw2 def test_bitfield_basic(self): From noreply at buildbot.pypy.org Fri May 31 15:26:30 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 15:26:30 +0200 (CEST) Subject: [pypy-commit] pypy default: Import cffi/170d74235eec Message-ID: <20130531132630.D5BA71C1442@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64681:405de91d1f2a Date: 2013-05-31 15:25 +0200 http://bitbucket.org/pypy/pypy/changeset/405de91d1f2a/ Log: Import cffi/170d74235eec diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -98,10 +98,10 @@ s = ffi.new("struct s1 *") setattr(s, name, value) assert getattr(s, name) == value - raw1 = bytes(ffi.buffer(s)) + raw1 = ffi.buffer(s)[:] if lib is not None: t = lib.try_with_value(fnames.index(name), value) - raw2 = bytes(ffi.buffer(t, len(raw1))) + raw2 = ffi.buffer(t, len(raw1))[:] assert raw1 == raw2 def test_bitfield_basic(self): From noreply at buildbot.pypy.org Fri May 31 17:34:00 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 17:34:00 +0200 (CEST) Subject: [pypy-commit] pypy default: test_call moves stuff around, but should still pass. Use "guard_not_invalidated?" in general. Message-ID: <20130531153400.832091C331B@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64682:16e45de635c6 Date: 2013-05-31 17:23 +0200 http://bitbucket.org/pypy/pypy/changeset/16e45de635c6/ Log: test_call moves stuff around, but should still pass. Use "guard_not_invalidated?" in general. diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -184,7 +184,7 @@ def match_by_id(self, id, expected_src, **kwds): ops = list(self.ops_by_id(id, **kwds)) - matcher = OpMatcher(ops) + matcher = OpMatcher(ops, id) return matcher.match(expected_src) class PartialTraceWithIds(TraceWithIds): @@ -260,8 +260,9 @@ class OpMatcher(object): - def __init__(self, ops): + def __init__(self, ops, id=None): self.ops = ops + self.id = id self.src = '\n'.join(map(str, ops)) self.alpha_map = {} @@ -495,6 +496,7 @@ print '@' * 40 print "Loops don't match" print "=================" + print 'loop id = %r' % (self.id,) print e.args print e.msg print diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -254,17 +254,22 @@ return c # s = 0 - for i in range(x): + i = 0 + while i < x: l = [i, x, 2] s += g(*l) # ID: g1 s += h(*l) # ID: h1 s += g(i, x, 2) # ID: g2 a = 0 - for i in range(x): + i += 1 + i = 0 + while i < x: l = [x, 2] + g(*l) s += g(i, *l) # ID: g3 s += h(i, *l) # ID: h2 a = 0 + i += 1 return s # log = self.run(main, [1000]) @@ -339,6 +344,7 @@ loop, = log.loops_by_filename(self.filepath) # the int strategy is used here assert loop.match_by_id('append', """ + guard_not_invalidated? i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) # Will be killed by the backend @@ -486,6 +492,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated? i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -585,7 +592,7 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=...) + guard_not_invalidated? i1 = force_token() ''') From noreply at buildbot.pypy.org Fri May 31 17:34:01 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 17:34:01 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix test_pypy_c, at least on tannit64. Message-ID: <20130531153401.A79421C3321@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64683:25b2bcefa539 Date: 2013-05-31 17:37 +0200 http://bitbucket.org/pypy/pypy/changeset/25b2bcefa539/ Log: Fix test_pypy_c, at least on tannit64. diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -13,6 +13,7 @@ a = A() a.x = 1 for s in sys.modules.keys() * 1000: + d.get(s) # force pending setfields etc. inc = a.x # ID: look d[s] = d.get(s, 0) + inc return sum(d.values()) @@ -21,8 +22,7 @@ assert log.result % 1000 == 0 loop, = log.loops_by_filename(self.filepath) ops = loop.ops_by_id('look') - assert log.opnames(ops) == ['setfield_gc', - 'guard_not_invalidated'] + assert log.opnames(ops) == [] def test_identitydict(self): def fn(n): diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -49,17 +49,20 @@ label(..., descr=...) ... label(..., descr=...) + guard_not_invalidated? i17 = int_ge(i11, i7) guard_false(i17, descr=...) p18 = getarrayitem_gc(p5, i11, descr=...) i19 = int_add(i11, 1) setfield_gc(p2, i19, descr=...) - guard_class(p18, ConstClass(W_IntObject), descr=...) + guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...) i20 = getfield_gc_pure(p18, descr=...) i21 = int_gt(i20, i14) guard_true(i21, descr=...) jump(..., descr=...) ''') + # XXX could be "guard_class(p18)" instead; we lost somewhere + # the information that it cannot be null. def test_iter_max(self): def main(): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -177,6 +177,7 @@ assert log.result == 1000 * 999 / 2 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated? i16 = int_ge(i11, i12) guard_false(i16, descr=...) i17 = int_mul(i11, i14) @@ -184,7 +185,7 @@ i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=...) + guard_not_invalidated? i23 = int_lt(i18, 0) guard_false(i23, descr=...) i25 = int_ge(i18, i9) @@ -234,6 +235,7 @@ assert log.result == 1000000 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated? i14 = getfield_gc(p12, descr=) i16 = uint_ge(i12, i14) guard_false(i16, descr=...) @@ -242,7 +244,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) - guard_not_invalidated(descr=...) + guard_not_invalidated? i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -157,7 +157,7 @@ copystrcontent(p9, p21, 0, i25, i10) i33 = int_lt(i30, 23) guard_true(i33, descr=...) - p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=) + p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=) guard_no_exception(descr=...) i37 = strlen(p35) i38 = int_add_ovf(i5, i37) @@ -190,7 +190,7 @@ assert len(loops) == 1 for loop in loops: loop.match_by_id('getattr',''' - guard_not_invalidated(descr=...) + guard_not_invalidated? i32 = strlen(p31) i34 = int_add(5, i32) p35 = newstr(i34) From noreply at buildbot.pypy.org Fri May 31 20:39:37 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 20:39:37 +0200 (CEST) Subject: [pypy-commit] pypy default: Don't pass keyword arguments here. The performance advantage is probably tiny, but it fixes the issue that _dummy() only takes a *args. Message-ID: <20130531183937.ACDF11C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64684:77d8ec314d31 Date: 2013-05-31 20:37 +0200 http://bitbucket.org/pypy/pypy/changeset/77d8ec314d31/ Log: Don't pass keyword arguments here. The performance advantage is probably tiny, but it fixes the issue that _dummy() only takes a *args. diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -188,23 +188,23 @@ self._sock = _sock def send(self, data, flags=0): - return self._sock.send(data, flags=flags) + return self._sock.send(data, flags) send.__doc__ = _realsocket.send.__doc__ def recv(self, buffersize, flags=0): - return self._sock.recv(buffersize, flags=flags) + return self._sock.recv(buffersize, flags) recv.__doc__ = _realsocket.recv.__doc__ def recv_into(self, buffer, nbytes=0, flags=0): - return self._sock.recv_into(buffer, nbytes=nbytes, flags=flags) + return self._sock.recv_into(buffer, nbytes, flags) recv_into.__doc__ = _realsocket.recv_into.__doc__ def recvfrom(self, buffersize, flags=0): - return self._sock.recvfrom(buffersize, flags=flags) + return self._sock.recvfrom(buffersize, flags) recvfrom.__doc__ = _realsocket.recvfrom.__doc__ def recvfrom_into(self, buffer, nbytes=0, flags=0): - return self._sock.recvfrom_into(buffer, nbytes=nbytes, flags=flags) + return self._sock.recvfrom_into(buffer, nbytes, flags) recvfrom_into.__doc__ = _realsocket.recvfrom_into.__doc__ def sendto(self, data, param2, param3=None): From noreply at buildbot.pypy.org Fri May 31 20:39:38 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 20:39:38 +0200 (CEST) Subject: [pypy-commit] pypy default: Fix a "refcount leak" for the socket returned by accept(). Message-ID: <20130531183938.A158D1C1442@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64685:8c7733710208 Date: 2013-05-31 20:42 +0200 http://bitbucket.org/pypy/pypy/changeset/8c7733710208/ Log: Fix a "refcount leak" for the socket returned by accept(). diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -223,7 +223,9 @@ def accept(self): sock, addr = self._sock.accept() - return _socketobject(_sock=sock), addr + sockobj = _socketobject(_sock=sock) + sock._drop() # already a copy in the _socketobject() + return sockobj, addr accept.__doc__ = _realsocket.accept.__doc__ def dup(self): From noreply at buildbot.pypy.org Fri May 31 20:39:39 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 20:39:39 +0200 (CEST) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20130531183939.935A01C153B@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64686:59a8280b8df2 Date: 2013-05-31 20:43 +0200 http://bitbucket.org/pypy/pypy/changeset/59a8280b8df2/ Log: merge heads diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,11 +32,10 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", - "thread", "itertools", "pyexpat", "_ssl", "array", + "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "micronumpy", "_ffi", - "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"] -# disabled until problems are fixed + "_continuation", "_cffi_backend", "_csv", "cppyy"] )) translation_modules = default_modules.copy() diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py --- a/pypy/module/_ffi/test/test_funcptr.py +++ b/pypy/module/_ffi/test/test_funcptr.py @@ -46,6 +46,7 @@ libm = CDLL(libm_name) pow = libm.getpointer('pow', [], types.void) pow_addr = rffi.cast(rffi.LONG, pow.funcsym) + cls._libm = libm # otherwise it gets unloaded - argh! cls.w_pow_addr = space.wrap(pow_addr) class AppTestFFI(BaseAppTestFFI): diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -26,7 +26,7 @@ from pypy.module.__builtin__.descriptor import W_Property from pypy.module.__builtin__.interp_classobj import W_ClassObject from pypy.module.__builtin__.interp_memoryview import W_MemoryView -from rpython.rlib.entrypoint import entrypoint +from rpython.rlib.entrypoint import entrypoint_lowlevel from rpython.rlib.rposix import is_valid_fd, validate_fd from rpython.rlib.unroll import unrolling_iterable from rpython.rlib.objectmodel import specialize @@ -544,38 +544,37 @@ def make_wrapper(space, callable): "NOT_RPYTHON" names = callable.api_func.argnames - argtypes = callable.api_func.argtypes - is_wrapped_list = [name.startswith("w_") for name in names] + argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes, + [name.startswith("w_") for name in names]))) fatal_value = callable.api_func.restype._defl() - lines = [] - for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)): - if is_PyObject(argtype) and is_wrapped: - new_lines = [ - 'if %(arg)s:', - ' %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))', - 'else:', - ' %(arg)s = None', - ] - for j in range(len(new_lines)): - new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i} - lines += new_lines - middle = '\n '.join(lines) - arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))]) - - source = py.code.Source(""" - def wrapper(%(args)s): + @specialize.ll() + def wrapper(*args): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference + # we hope that malloc removal removes the newtuple() that is + # inserted exactly here by the varargs specializer + rffi.stackcounter.stacks_counter += 1 + llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py retval = fatal_value boxed_args = () try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, + assert len(args) == len(callable.api_func.argtypes) + for i, (typ, is_wrapped) in argtypes_enum_ui: + arg = args[i] + if is_PyObject(typ) and is_wrapped: + if arg: + arg_conv = from_ref(space, rffi.cast(PyObject, arg)) + else: + arg_conv = None + else: + arg_conv = arg + boxed_args += (arg_conv, ) state = space.fromcache(State) - %(middle)s try: - result = callable(space, %(args)s) + result = callable(space, *boxed_args) if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, " DONE" except OperationError, e: @@ -597,8 +596,8 @@ if failed: error_value = callable.api_func.error_value if error_value is CANNOT_FAIL: - raise SystemError("The function '%%s' was not supposed to fail" - %% (callable.__name__,)) + raise SystemError("The function '%s' was not supposed to fail" + % (callable.__name__,)) retval = error_value elif is_PyObject(callable.api_func.restype): @@ -625,13 +624,8 @@ else: print str(e) pypy_debug_catch_fatal_exception() + rffi.stackcounter.stacks_counter -= 1 return retval - """ % {"middle": middle, "args": arg_spec}) - d = {} - d.update(locals()) - d.update(globals()) - exec source.compile() in d - wrapper = d['wrapper'] callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -1029,7 +1023,7 @@ export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): - deco = entrypoint("cpyext", func.argtypes, name) + deco = entrypoint_lowlevel("cpyext", func.argtypes, name, relax=True) deco(func.get_wrapper(space)) setup_init_functions(eci, translating=True) 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 @@ -342,7 +342,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=False) + error=-1, external=True) # XXX should not be exported @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py --- a/pypy/module/micronumpy/test/test_scalar.py +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -21,3 +21,7 @@ a = zeros(3) assert loads(dumps(sum(a))) == sum(a) + + def setup_class(cls): + import py + py.test.xfail("FIXME: dtype('int32') == dtype('int32') fails") diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -184,7 +184,7 @@ def match_by_id(self, id, expected_src, **kwds): ops = list(self.ops_by_id(id, **kwds)) - matcher = OpMatcher(ops) + matcher = OpMatcher(ops, id) return matcher.match(expected_src) class PartialTraceWithIds(TraceWithIds): @@ -260,8 +260,9 @@ class OpMatcher(object): - def __init__(self, ops): + def __init__(self, ops, id=None): self.ops = ops + self.id = id self.src = '\n'.join(map(str, ops)) self.alpha_map = {} @@ -495,6 +496,7 @@ print '@' * 40 print "Loops don't match" print "=================" + print 'loop id = %r' % (self.id,) print e.args print e.msg print diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -254,17 +254,22 @@ return c # s = 0 - for i in range(x): + i = 0 + while i < x: l = [i, x, 2] s += g(*l) # ID: g1 s += h(*l) # ID: h1 s += g(i, x, 2) # ID: g2 a = 0 - for i in range(x): + i += 1 + i = 0 + while i < x: l = [x, 2] + g(*l) s += g(i, *l) # ID: g3 s += h(i, *l) # ID: h2 a = 0 + i += 1 return s # log = self.run(main, [1000]) @@ -339,6 +344,7 @@ loop, = log.loops_by_filename(self.filepath) # the int strategy is used here assert loop.match_by_id('append', """ + guard_not_invalidated? i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) # Will be killed by the backend @@ -486,6 +492,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated? i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -585,7 +592,7 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=...) + guard_not_invalidated? i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -13,6 +13,7 @@ a = A() a.x = 1 for s in sys.modules.keys() * 1000: + d.get(s) # force pending setfields etc. inc = a.x # ID: look d[s] = d.get(s, 0) + inc return sum(d.values()) @@ -21,8 +22,7 @@ assert log.result % 1000 == 0 loop, = log.loops_by_filename(self.filepath) ops = loop.ops_by_id('look') - assert log.opnames(ops) == ['setfield_gc', - 'guard_not_invalidated'] + assert log.opnames(ops) == [] def test_identitydict(self): def fn(n): diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -49,17 +49,20 @@ label(..., descr=...) ... label(..., descr=...) + guard_not_invalidated? i17 = int_ge(i11, i7) guard_false(i17, descr=...) p18 = getarrayitem_gc(p5, i11, descr=...) i19 = int_add(i11, 1) setfield_gc(p2, i19, descr=...) - guard_class(p18, ConstClass(W_IntObject), descr=...) + guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...) i20 = getfield_gc_pure(p18, descr=...) i21 = int_gt(i20, i14) guard_true(i21, descr=...) jump(..., descr=...) ''') + # XXX could be "guard_class(p18)" instead; we lost somewhere + # the information that it cannot be null. def test_iter_max(self): def main(): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -177,6 +177,7 @@ assert log.result == 1000 * 999 / 2 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated? i16 = int_ge(i11, i12) guard_false(i16, descr=...) i17 = int_mul(i11, i14) @@ -184,7 +185,7 @@ i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=...) + guard_not_invalidated? i23 = int_lt(i18, 0) guard_false(i23, descr=...) i25 = int_ge(i18, i9) @@ -234,6 +235,7 @@ assert log.result == 1000000 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated? i14 = getfield_gc(p12, descr=) i16 = uint_ge(i12, i14) guard_false(i16, descr=...) @@ -242,7 +244,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) - guard_not_invalidated(descr=...) + guard_not_invalidated? i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -157,7 +157,7 @@ copystrcontent(p9, p21, 0, i25, i10) i33 = int_lt(i30, 23) guard_true(i33, descr=...) - p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=) + p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=) guard_no_exception(descr=...) i37 = strlen(p35) i38 = int_add_ovf(i5, i37) @@ -190,7 +190,7 @@ assert len(loops) == 1 for loop in loops: loop.match_by_id('getattr',''' - guard_not_invalidated(descr=...) + guard_not_invalidated? i32 = strlen(p31) i34 = int_add(5, i32) p35 = newstr(i34) diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -98,10 +98,10 @@ s = ffi.new("struct s1 *") setattr(s, name, value) assert getattr(s, name) == value - raw1 = bytes(ffi.buffer(s)) + raw1 = ffi.buffer(s)[:] if lib is not None: t = lib.try_with_value(fnames.index(name), value) - raw2 = bytes(ffi.buffer(t, len(raw1))) + raw2 = ffi.buffer(t, len(raw1))[:] assert raw1 == raw2 def test_bitfield_basic(self): diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py --- a/rpython/annotator/description.py +++ b/rpython/annotator/description.py @@ -215,8 +215,9 @@ if len(self._cache) != 1: raise NoStandardGraph(self) [graph] = self._cache.values() + relax_sig_check = getattr(self.pyobj, "relax_sig_check", False) if (graph.signature != self.signature or - graph.defaults != self.defaults): + graph.defaults != self.defaults) and not relax_sig_check: raise NoStandardGraph(self) return graph diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -3542,6 +3542,16 @@ s = a.build_types(f, [int]) assert s.knowntype is int + def test_relax(self): + def f(*args): + return args[0] + args[1] + f.relax_sig_check = True + def g(x): + return f(x, x - x) + a = self.RPythonAnnotator() + s = a.build_types(g, [int]) + assert a.bookkeeper.getdesc(f).getuniquegraph() + def test_cannot_raise_ll_exception(self): from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr # diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -5,13 +5,33 @@ from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import we_are_translated + +def entrypoint_lowlevel(key, argtypes, c_name=None, relax=False): + """ Note: entrypoint should call llop.gc_stack_bottom on it's own. + That's necessary for making it work with asmgcc and hence JIT + + If in doubt, use entrypoint(). + + if key == 'main' than it's included by default + """ + from rpython.translator.tool.cbuild import ExternalCompilationInfo + + def deco(func): + secondary_entrypoints.setdefault(key, []).append((func, argtypes)) + if c_name is not None: + func.c_name = c_name + if relax: + func.relax_sig_check = True + func._compilation_info = ExternalCompilationInfo( + export_symbols=[c_name or func.func_name]) + return func + return deco + + pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) def entrypoint(key, argtypes, c_name=None): - """ Note: entrypoint should call llop.gc_stack_bottom on it's own. - That's necessary for making it work with asmgcc and hence JIT - - if key == 'main' than it's included by default + """if key == 'main' than it's included by default """ from rpython.translator.tool.cbuild import ExternalCompilationInfo diff --git a/rpython/rlib/test/test_rlocale.py b/rpython/rlib/test/test_rlocale.py --- a/rpython/rlib/test/test_rlocale.py +++ b/rpython/rlib/test/test_rlocale.py @@ -20,8 +20,8 @@ def test_setlocale_worked(self): assert u"Ą".isupper() - raises(LocaleError, setlocale, LC_ALL, "bla bla bla") - raises(LocaleError, setlocale, 1234455, None) + py.test.raises(LocaleError, setlocale, LC_ALL, "bla bla bla") + py.test.raises(LocaleError, setlocale, 1234455, None) def test_lower_upper(self): assert isupper(ord("A")) diff --git a/rpython/translator/c/test/test_genc.py b/rpython/translator/c/test/test_genc.py --- a/rpython/translator/c/test/test_genc.py +++ b/rpython/translator/c/test/test_genc.py @@ -522,8 +522,9 @@ f = getattr(self, "_f", None) if f is not None: return f - f = lambda arg: self.func(arg) + f = lambda *args: self.func(*args) f.c_name = self.name + f.relax_sig_check = True f.__name__ = "WRAP%s" % (self.name, ) self._f = f return f From noreply at buildbot.pypy.org Fri May 31 20:49:57 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 20:49:57 +0200 (CEST) Subject: [pypy-commit] pypy default: Typo (to test the bitbucket hook) Message-ID: <20130531184957.3C5FA1C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64687:4ad4bedaf5a5 Date: 2013-05-31 20:49 +0200 http://bitbucket.org/pypy/pypy/changeset/4ad4bedaf5a5/ Log: Typo (to test the bitbucket hook) diff --git a/pypy/doc/rffi.rst b/pypy/doc/rffi.rst --- a/pypy/doc/rffi.rst +++ b/pypy/doc/rffi.rst @@ -50,7 +50,7 @@ ------ In rffi_ there are various declared types for C-structures, like CCHARP -(char*), SIZE_T (size_t) and others. refer to file for details. +(char*), SIZE_T (size_t) and others. Refer to file for details. Instances of non-primitive types must be alloced by hand, with call to lltype.malloc, and freed by lltype.free both with keyword argument flavor='raw'. There are several helpers like string -> char* From noreply at buildbot.pypy.org Fri May 31 21:02:03 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 21:02:03 +0200 (CEST) Subject: [pypy-commit] pypy default: testing the bbhook Message-ID: <20130531190203.90DF81C1442@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64688:4d0229ceb4e5 Date: 2013-05-31 21:01 +0200 http://bitbucket.org/pypy/pypy/changeset/4d0229ceb4e5/ Log: testing the bbhook diff --git a/pypy/doc/rffi.rst b/pypy/doc/rffi.rst --- a/pypy/doc/rffi.rst +++ b/pypy/doc/rffi.rst @@ -5,7 +5,7 @@ Purpose ------- -This document describes an FFI for RPython language, concentrating +This document describes an FFI for the RPython language, concentrating on low-level backends like C. It describes how to declare and call low-level (C) functions from RPython level. From noreply at buildbot.pypy.org Fri May 31 21:40:03 2013 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 31 May 2013 21:40:03 +0200 (CEST) Subject: [pypy-commit] pypy default: Minor clean-up of RStringIO.truncate(). This is a no-op from the point Message-ID: <20130531194003.208201C0189@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r64689:140e6c594a81 Date: 2013-05-31 21:39 +0200 http://bitbucket.org/pypy/pypy/changeset/140e6c594a81/ Log: Minor clean-up of RStringIO.truncate(). This is a no-op from the point of view of the whole PyPy: it moves into RStringIO the behavior that was previously done with an explicit call to seek(0, 2). diff --git a/pypy/module/cStringIO/interp_stringio.py b/pypy/module/cStringIO/interp_stringio.py --- a/pypy/module/cStringIO/interp_stringio.py +++ b/pypy/module/cStringIO/interp_stringio.py @@ -159,7 +159,6 @@ if size < 0: raise OperationError(space.w_IOError, space.wrap("negative size")) self.truncate(size) - self.seek(0, 2) @unwrap_spec(buffer='bufferstr') def descr_write(self, buffer): diff --git a/rpython/rlib/rStringIO.py b/rpython/rlib/rStringIO.py --- a/rpython/rlib/rStringIO.py +++ b/rpython/rlib/rStringIO.py @@ -163,6 +163,10 @@ return ''.join(self.__bigbuffer[p:i]) def truncate(self, size): + """Warning, this gets us slightly strange behavior from the + point of view of a traditional Unix file, but consistent with + Python 2.7's cStringIO module: it will not enlarge the file, + and it will always seek to the (new) end of the file.""" assert size >= 0 if self.__bigbuffer is None or size > len(self.__bigbuffer): self.__copy_into_bigbuffer() @@ -174,3 +178,5 @@ del self.__bigbuffer[size:] if len(self.__bigbuffer) == 0: self.__bigbuffer = None + # it always has the effect of seeking at the new end + self.__pos = AT_END diff --git a/rpython/rlib/test/test_rStringIO.py b/rpython/rlib/test/test_rStringIO.py --- a/rpython/rlib/test/test_rStringIO.py +++ b/rpython/rlib/test/test_rStringIO.py @@ -96,7 +96,15 @@ f.truncate(20) assert f.getvalue() == '' assert f.tell() == 0 - f.write('\x00' * 20) + f.write('\x00' * 25) + f.seek(12) + f.truncate(20) + assert f.getvalue() == '\x00' * 20 + assert f.tell() == 20 + f.write('more') + f.truncate(20) + assert f.getvalue() == '\x00' * 20 + assert f.tell() == 20 f.write('hello') f.write(' world') f.truncate(30) From noreply at buildbot.pypy.org Fri May 31 22:20:32 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 31 May 2013 22:20:32 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: reorder condition so the constant foldable part goes first Message-ID: <20130531202032.DB6381C1442@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64690:8269bf49d99c Date: 2013-05-29 09:31 -0700 http://bitbucket.org/pypy/pypy/changeset/8269bf49d99c/ Log: reorder condition so the constant foldable part goes first diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py --- a/pypy/module/pypyjit/interp_jit.py +++ b/pypy/module/pypyjit/interp_jit.py @@ -92,7 +92,7 @@ jumpto = r_uint(self.last_instr) # lastblock = self.lastblock - if not (isinstance(lastblock, LoopBlock) and lastblock.should_unroll and we_are_jitted()): + if not (we_are_jitted() and isinstance(lastblock, LoopBlock) and lastblock.should_unroll): pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto, pycode=self.getcode(), is_being_profiled=self.is_being_profiled) From noreply at buildbot.pypy.org Fri May 31 22:20:34 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 31 May 2013 22:20:34 +0200 (CEST) Subject: [pypy-commit] pypy python-loop-unroll: merged default Message-ID: <20130531202034.351A31C1442@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: python-loop-unroll Changeset: r64691:3743a8d7b24f Date: 2013-05-29 10:14 -0700 http://bitbucket.org/pypy/pypy/changeset/3743a8d7b24f/ Log: merged default diff --git a/pypy/module/_minimal_curses/fficurses.py b/pypy/module/_minimal_curses/fficurses.py --- a/pypy/module/_minimal_curses/fficurses.py +++ b/pypy/module/_minimal_curses/fficurses.py @@ -11,21 +11,50 @@ from sys import platform import os.path -_CYGWIN = platform == 'cygwin' -_NCURSES_CURSES = os.path.isfile("/usr/include/ncurses/curses.h") +# We cannot trust ncurses5-config, it's broken in various ways in +# various versions. For example it might not list -ltinfo even though +# it's needed, or --cflags might be completely empty. On Ubuntu 10.04 +# it gives -I/usr/include/ncurses, which doesn't exist at all. Crap. -if _CYGWIN or _NCURSES_CURSES: - eci = ExternalCompilationInfo( - includes = ['ncurses/curses.h', 'ncurses/term.h'], - libraries = ['curses'], - ) -else: - eci = ExternalCompilationInfo( - includes = ['curses.h', 'term.h'], - libraries = ['curses'], - ) +def try_cflags(): + yield ExternalCompilationInfo(includes=['curses.h', 'term.h']) + yield ExternalCompilationInfo(includes=['curses.h', 'term.h'], + include_dirs=['/usr/include/ncurses']) + yield ExternalCompilationInfo(includes=['ncurses/curses.h', + 'ncurses/term.h']) -rffi_platform.verify_eci(eci) +def try_ldflags(): + yield ExternalCompilationInfo(libraries=['curses']) + yield ExternalCompilationInfo(libraries=['curses', 'tinfo']) + +def try_tools(): + try: + yield ExternalCompilationInfo.from_pkg_config("ncurses") + except Exception: + pass + try: + yield ExternalCompilationInfo.from_config_tool("ncurses5-config") + except Exception: + pass + +def try_eci(): + for eci in try_tools(): + yield eci.merge(ExternalCompilationInfo(includes=['curses.h', + 'term.h'])) + for eci1 in try_cflags(): + for eci2 in try_ldflags(): + yield eci1.merge(eci2) + +def guess_eci(): + for eci in try_eci(): + class CConfig: + _compilation_info_ = eci + HAS = rffi_platform.Has("setupterm") + if rffi_platform.configure(CConfig)['HAS']: + return eci + raise ImportError("failed to guess where ncurses is installed") + +eci = guess_eci() INT = rffi.INT diff --git a/pypy/module/_multiprocessing/__init__.py b/pypy/module/_multiprocessing/__init__.py --- a/pypy/module/_multiprocessing/__init__.py +++ b/pypy/module/_multiprocessing/__init__.py @@ -1,11 +1,11 @@ +import sys + from pypy.interpreter.mixedmodule import MixedModule -import sys class Module(MixedModule): interpleveldefs = { 'Connection' : 'interp_connection.W_FileConnection', - 'PipeConnection' : 'interp_connection.W_PipeConnection', 'SemLock' : 'interp_semaphore.W_SemLock', 'address_of_buffer' : 'interp_memory.address_of_buffer', @@ -15,4 +15,6 @@ } if sys.platform == 'win32': + interpleveldefs['PipeConnection'] = \ + 'interp_connection.W_PipeConnection' interpleveldefs['win32'] = 'interp_win32.win32_namespace(space)' diff --git a/pypy/module/_multiprocessing/interp_connection.py b/pypy/module/_multiprocessing/interp_connection.py --- a/pypy/module/_multiprocessing/interp_connection.py +++ b/pypy/module/_multiprocessing/interp_connection.py @@ -1,17 +1,17 @@ -from __future__ import with_statement -from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault -from pypy.interpreter.error import ( - OperationError, wrap_oserror, operationerrfmt) -from rpython.rtyper.lltypesystem import rffi, lltype -from rpython.rlib.rarithmetic import intmask -from rpython.rlib import rpoll, rsocket import sys -READABLE = 1 -WRITABLE = 2 +from rpython.rlib import rpoll, rsocket +from rpython.rlib.rarithmetic import intmask +from rpython.rtyper.lltypesystem import lltype, rffi +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.error import ( + OperationError, operationerrfmt, wrap_oserror) +from pypy.interpreter.gateway import ( + WrappedDefault, interp2app, interpindirect2app, unwrap_spec) +from pypy.interpreter.typedef import GetSetProperty, TypeDef + +READABLE, WRITABLE = range(1, 3) PY_SSIZE_T_MAX = sys.maxint PY_SSIZE_T_MIN = -sys.maxint - 1 @@ -46,10 +46,12 @@ raise NotImplementedError def is_valid(self): return False - def do_send_string(self, space, buffer, offset, size): + def do_send_string(self, space, buf, offset, size): raise NotImplementedError def do_recv_string(self, space, buflength, maxlength): raise NotImplementedError + def do_poll(self, space, timeout): + raise NotImplementedError def close(self): self.do_close() @@ -61,6 +63,14 @@ def writable_get(self, space): return space.newbool(bool(self.flags & WRITABLE)) + def _repr(self, space, handle): + conn_type = ["read-only", "write-only", "read-write"][self.flags - 1] + return space.wrap("<%s %s, handle %d>" % ( + conn_type, space.type(self).getname(space), handle)) + + def descr_repr(self, space): + raise NotImplementedError + def _check_readable(self, space): if not self.flags & READABLE: raise OperationError(space.w_IOError, @@ -70,9 +80,9 @@ raise OperationError(space.w_IOError, space.wrap("connection is read-only")) - @unwrap_spec(buffer='bufferstr', offset='index', size='index') - def send_bytes(self, space, buffer, offset=0, size=PY_SSIZE_T_MIN): - length = len(buffer) + @unwrap_spec(buf='bufferstr', offset='index', size='index') + def send_bytes(self, space, buf, offset=0, size=PY_SSIZE_T_MIN): + length = len(buf) self._check_writable(space) if offset < 0: raise OperationError(space.w_ValueError, @@ -90,7 +100,7 @@ raise OperationError(space.w_ValueError, space.wrap("buffer length > offset + size")) - self.do_send_string(space, buffer, offset, size) + self.do_send_string(space, buf, offset, size) @unwrap_spec(maxlength='index') def recv_bytes(self, space, maxlength=PY_SSIZE_T_MAX): @@ -139,8 +149,8 @@ w_pickled = space.call_method( w_picklemodule, "dumps", w_obj, w_protocol) - buffer = space.bufferstr_w(w_pickled) - self.do_send_string(space, buffer, 0, len(buffer)) + buf = space.bufferstr_w(w_pickled) + self.do_send_string(space, buf, 0, len(buf)) def recv(self, space): self._check_readable(space) @@ -177,6 +187,7 @@ W_BaseConnection.typedef = TypeDef( 'BaseConnection', + __repr__ = interpindirect2app(W_BaseConnection.descr_repr), closed = GetSetProperty(W_BaseConnection.closed_get), readable = GetSetProperty(W_BaseConnection.readable_get), writable = GetSetProperty(W_BaseConnection.writable_get), @@ -226,7 +237,8 @@ def __init__(self, space, fd, flags): if fd == self.INVALID_HANDLE_VALUE or fd < 0: - raise OperationError(space.w_IOError, space.wrap("invalid handle %d" % fd)) + raise OperationError(space.w_IOError, + space.wrap("invalid handle %d" % fd)) W_BaseConnection.__init__(self, flags) self.fd = fd @@ -238,6 +250,9 @@ W_FileConnection.__init__(self, space, fd, flags) return space.wrap(self) + def descr_repr(self, space): + return self._repr(space, self.fd) + def fileno(self, space): return space.wrap(self.fd) @@ -249,8 +264,8 @@ self.CLOSE() self.fd = self.INVALID_HANDLE_VALUE - def do_send_string(self, space, buffer, offset, size): - # Since str2charp copies the buffer anyway, always combine the + def do_send_string(self, space, buf, offset, size): + # Since str2charp copies the buf anyway, always combine the # "header" and the "body" of the message and send them at once. message = lltype.malloc(rffi.CCHARP.TO, size + 4, flavor='raw') try: @@ -259,7 +274,7 @@ rffi.cast(rffi.UINTP, message)[0] = length i = size - 1 while i >= 0: - message[4 + i] = buffer[offset + i] + message[4 + i] = buf[offset + i] i -= 1 self._sendall(space, message, size + 4) finally: @@ -296,7 +311,7 @@ size -= count message = rffi.ptradd(message, count) - def _recvall(self, space, buffer, length): + def _recvall(self, space, buf, length): length = intmask(length) remaining = length while remaining > 0: @@ -313,9 +328,9 @@ "got end of file during message")) # XXX inefficient for i in range(count): - buffer[i] = data[i] + buf[i] = data[i] remaining -= count - buffer = rffi.ptradd(buffer, count) + buf = rffi.ptradd(buf, count) if sys.platform == 'win32': def _check_fd(self): @@ -330,10 +345,7 @@ "handle out of range in select()")) r, w, e = rpoll.select([self.fd], [], [], timeout) - if r: - return True - else: - return False + return bool(r) W_FileConnection.typedef = TypeDef( 'Connection', W_BaseConnection.typedef, @@ -351,7 +363,8 @@ self.handle = handle @unwrap_spec(readable=bool, writable=bool) - def descr_new_pipe(space, w_subtype, w_handle, readable=True, writable=True): + def descr_new_pipe(space, w_subtype, w_handle, readable=True, + writable=True): from pypy.module._multiprocessing.interp_win32 import handle_w handle = handle_w(space, w_handle) flags = (readable and READABLE) | (writable and WRITABLE) @@ -361,10 +374,7 @@ return space.wrap(self) def descr_repr(self, space): - conn_type = ["read-only", "write-only", "read-write"][self.flags] - - return space.wrap("<%s %s, handle %zd>" % ( - conn_type, space.type(self).getname(space), self.do_fileno())) + return self._repr(space, self.handle) def is_valid(self): return self.handle != self.INVALID_HANDLE_VALUE @@ -378,12 +388,12 @@ CloseHandle(self.handle) self.handle = self.INVALID_HANDLE_VALUE - def do_send_string(self, space, buffer, offset, size): + def do_send_string(self, space, buf, offset, size): from pypy.module._multiprocessing.interp_win32 import ( _WriteFile, ERROR_NO_SYSTEM_RESOURCES) from rpython.rlib import rwin32 - charp = rffi.str2charp(buffer) + charp = rffi.str2charp(buf) written_ptr = lltype.malloc(rffi.CArrayPtr(rwin32.DWORD).TO, 1, flavor='raw') try: diff --git a/pypy/module/_multiprocessing/interp_memory.py b/pypy/module/_multiprocessing/interp_memory.py --- a/pypy/module/_multiprocessing/interp_memory.py +++ b/pypy/module/_multiprocessing/interp_memory.py @@ -1,5 +1,6 @@ +from rpython.rtyper.lltypesystem import rffi + from pypy.interpreter.error import OperationError -from rpython.rtyper.lltypesystem import rffi from pypy.module.mmap.interp_mmap import W_MMap def address_of_buffer(space, w_obj): diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -1,23 +1,26 @@ -from __future__ import with_statement +import errno +import os +import sys +import time + +from rpython.rlib import rgc, rthread +from rpython.rlib.rarithmetic import r_uint +from rpython.rtyper.lltypesystem import rffi, lltype +from rpython.rtyper.tool import rffi_platform as platform +from rpython.translator.tool.cbuild import ExternalCompilationInfo + from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.typedef import TypeDef, GetSetProperty +from pypy.interpreter.error import OperationError, wrap_oserror from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.error import wrap_oserror, OperationError -from rpython.rtyper.lltypesystem import rffi, lltype -from rpython.rlib import rgc -from rpython.rlib.rarithmetic import r_uint -from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rtyper.tool import rffi_platform as platform -from rpython.rlib import rthread +from pypy.interpreter.typedef import GetSetProperty, TypeDef from pypy.module._multiprocessing.interp_connection import w_handle -import sys, os, time, errno RECURSIVE_MUTEX, SEMAPHORE = range(2) if sys.platform == 'win32': from rpython.rlib import rwin32 from pypy.module._multiprocessing.interp_win32 import ( - handle_w, _GetTickCount) + _GetTickCount, handle_w) SEM_VALUE_MAX = sys.maxint @@ -62,7 +65,8 @@ TIMEVALP = rffi.CArrayPtr(TIMEVAL) TIMESPECP = rffi.CArrayPtr(TIMESPEC) SEM_T = rffi.COpaquePtr('sem_t', compilation_info=eci) - SEM_FAILED = config['SEM_FAILED'] # rffi.cast(SEM_T, config['SEM_FAILED']) + # rffi.cast(SEM_T, config['SEM_FAILED']) + SEM_FAILED = config['SEM_FAILED'] SEM_VALUE_MAX = config['SEM_VALUE_MAX'] SEM_TIMED_WAIT = config['SEM_TIMED_WAIT'] SEM_T_SIZE = config['SEM_T_SIZE'] @@ -160,7 +164,8 @@ return -1 if SEM_TIMED_WAIT: - _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], rffi.INT) + _sem_timedwait = external('sem_timedwait', [SEM_T, TIMESPECP], + rffi.INT) else: _sem_timedwait = _sem_timedwait_save @@ -185,7 +190,8 @@ res = _gettimeofday(now, None) if res < 0: raise OSError(rposix.get_errno(), "gettimeofday failed") - return rffi.getintfield(now[0], 'c_tv_sec'), rffi.getintfield(now[0], 'c_tv_usec') + return (rffi.getintfield(now[0], 'c_tv_sec'), + rffi.getintfield(now[0], 'c_tv_usec')) finally: lltype.free(now, flavor='raw') @@ -330,8 +336,8 @@ deadline = lltype.malloc(TIMESPECP.TO, 1, flavor='raw') rffi.setintfield(deadline[0], 'c_tv_sec', now_sec + sec) rffi.setintfield(deadline[0], 'c_tv_nsec', now_usec * 1000 + nsec) - val = rffi.getintfield(deadline[0], 'c_tv_sec') + \ - rffi.getintfield(deadline[0], 'c_tv_nsec') / 1000000000 + val = (rffi.getintfield(deadline[0], 'c_tv_sec') + + rffi.getintfield(deadline[0], 'c_tv_nsec') / 1000000000) rffi.setintfield(deadline[0], 'c_tv_sec', val) val = rffi.getintfield(deadline[0], 'c_tv_nsec') % 1000000000 rffi.setintfield(deadline[0], 'c_tv_nsec', val) diff --git a/pypy/module/_multiprocessing/interp_win32.py b/pypy/module/_multiprocessing/interp_win32.py --- a/pypy/module/_multiprocessing/interp_win32.py +++ b/pypy/module/_multiprocessing/interp_win32.py @@ -1,11 +1,12 @@ -from pypy.interpreter.gateway import unwrap_spec, interp2app -from pypy.interpreter.function import StaticMethod -from pypy.interpreter.error import wrap_windowserror, OperationError from rpython.rlib import rwin32 from rpython.rlib.rarithmetic import r_uint -from rpython.rtyper.lltypesystem import rffi, lltype +from rpython.rtyper.lltypesystem import lltype, rffi +from rpython.rtyper.tool import rffi_platform from rpython.translator.tool.cbuild import ExternalCompilationInfo -from rpython.rtyper.tool import rffi_platform + +from pypy.interpreter.error import OperationError, wrap_windowserror +from pypy.interpreter.function import StaticMethod +from pypy.interpreter.gateway import interp2app, unwrap_spec from pypy.module._multiprocessing.interp_connection import w_handle CONSTANTS = """ @@ -130,10 +131,12 @@ if not _ConnectNamedPipe(handle, rffi.NULL): raise wrap_windowserror(space, rwin32.lastWindowsError()) -def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances, w_timeout): +def SetNamedPipeHandleState(space, w_handle, w_pipemode, w_maxinstances, + w_timeout): handle = handle_w(space, w_handle) state = lltype.malloc(rffi.CArrayPtr(rffi.UINT).TO, 3, flavor='raw') - statep = lltype.malloc(rffi.CArrayPtr(rffi.UINTP).TO, 3, flavor='raw', zero=True) + statep = lltype.malloc(rffi.CArrayPtr(rffi.UINTP).TO, 3, flavor='raw', + zero=True) try: if not space.is_w(w_pipemode, space.w_None): state[0] = space.uint_w(w_pipemode) @@ -144,7 +147,8 @@ if not space.is_w(w_timeout, space.w_None): state[2] = space.uint_w(w_timeout) statep[2] = rffi.ptradd(state, 2) - if not _SetNamedPipeHandleState(handle, statep[0], statep[1], statep[2]): + if not _SetNamedPipeHandleState(handle, statep[0], statep[1], + statep[2]): raise wrap_windowserror(space, rwin32.lastWindowsError()) finally: lltype.free(state, flavor='raw') diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py --- a/pypy/module/_multiprocessing/test/test_connection.py +++ b/pypy/module/_multiprocessing/test/test_connection.py @@ -173,3 +173,11 @@ assert data1 == '\x00\x00\x00\x03abc' data2 = sock.recv(8) assert data2 == '\x00\x00\x00\x04defg' + + def test_repr(self): + import _multiprocessing + c = _multiprocessing.Connection(1) + assert repr(c) == '' + if hasattr(_multiprocessing, 'PipeConnection'): + c = _multiprocessing.PipeConnection(1) + assert repr(c) == '' diff --git a/rpython/translator/tool/cbuild.py b/rpython/translator/tool/cbuild.py --- a/rpython/translator/tool/cbuild.py +++ b/rpython/translator/tool/cbuild.py @@ -1,5 +1,5 @@ import py -import sys +import sys, subprocess from rpython.translator.platform import host from rpython.tool.udir import udir @@ -99,6 +99,7 @@ return platform return self._platform + @classmethod def from_compiler_flags(cls, flags): """Returns a new ExternalCompilationInfo instance by parsing the string 'flags', which is in the typical Unix compiler flags @@ -124,8 +125,8 @@ return cls(pre_include_bits=pre_include_bits, include_dirs=include_dirs, compile_extra=compile_extra) - from_compiler_flags = classmethod(from_compiler_flags) + @classmethod def from_linker_flags(cls, flags): """Returns a new ExternalCompilationInfo instance by parsing the string 'flags', which is in the typical Unix linker flags @@ -146,8 +147,8 @@ return cls(libraries=libraries, library_dirs=library_dirs, link_extra=link_extra) - from_linker_flags = classmethod(from_linker_flags) + @classmethod def from_config_tool(cls, execonfigtool): """Returns a new ExternalCompilationInfo instance by executing the 'execonfigtool' with --cflags and --libs arguments.""" @@ -156,12 +157,29 @@ raise ImportError("cannot find %r" % (execonfigtool,)) # we raise ImportError to be nice to the pypy.config.pypyoption # logic of skipping modules depending on non-installed libs - cflags = py.process.cmdexec('"%s" --cflags' % (str(path),)) + return cls._run_config_tool('"%s"' % (str(path),)) + + @classmethod + def from_pkg_config(cls, pkgname): + """Returns a new ExternalCompilationInfo instance by executing + 'pkg-config ' with --cflags and --libs arguments.""" + assert isinstance(pkgname, str) + try: + popen = subprocess.Popen(['pkg-config', pkgname, '--exists']) + result = popen.wait() + except OSError: + result = -1 + if result != 0: + raise ImportError("failed: 'pkg-config %s --exists'" % pkgname) + return cls._run_config_tool('pkg-config "%s"' % pkgname) + + @classmethod + def _run_config_tool(cls, command): + cflags = py.process.cmdexec('%s --cflags' % command) eci1 = cls.from_compiler_flags(cflags) - libs = py.process.cmdexec('"%s" --libs' % (str(path),)) + libs = py.process.cmdexec('%s --libs' % command) eci2 = cls.from_linker_flags(libs) return eci1.merge(eci2) - from_config_tool = classmethod(from_config_tool) def _value(self): return tuple([getattr(self, x) diff --git a/rpython/translator/tool/test/test_cbuild.py b/rpython/translator/tool/test/test_cbuild.py --- a/rpython/translator/tool/test/test_cbuild.py +++ b/rpython/translator/tool/test/test_cbuild.py @@ -127,6 +127,18 @@ ExternalCompilationInfo.from_config_tool, 'dxowqbncpqympqhe-config') + def test_from_pkg_config(self): + try: + cmd = ['pkg-config', 'ncurses', '--exists'] + popen = Popen(cmd) + result = popen.wait() + except OSError: + result = -1 + if result != 0: + py.test.skip("failed: %r" % (' '.join(cmd),)) + eci = ExternalCompilationInfo.from_pkg_config('ncurses') + assert 'ncurses' in eci.libraries + def test_platforms(self): from rpython.translator.platform import Platform From noreply at buildbot.pypy.org Fri May 31 22:20:35 2013 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Fri, 31 May 2013 22:20:35 +0200 (CEST) Subject: [pypy-commit] pypy default: Optimize truncating an rStringIO (used in io.BytesIO) to empty. Message-ID: <20130531202035.767EB1C1442@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r64692:7587887ac0e2 Date: 2013-05-31 13:19 -0700 http://bitbucket.org/pypy/pypy/changeset/7587887ac0e2/ Log: Optimize truncating an rStringIO (used in io.BytesIO) to empty. diff --git a/rpython/rlib/rStringIO.py b/rpython/rlib/rStringIO.py --- a/rpython/rlib/rStringIO.py +++ b/rpython/rlib/rStringIO.py @@ -101,7 +101,11 @@ self.__pos = endp def seek(self, position, mode=0): - if mode == 1: + if mode == 0: + if position == self.getsize(): + self.__pos = AT_END + return + elif mode == 1: if self.__pos == AT_END: self.__pos = self.getsize() position += self.__pos @@ -168,15 +172,19 @@ Python 2.7's cStringIO module: it will not enlarge the file, and it will always seek to the (new) end of the file.""" assert size >= 0 - if self.__bigbuffer is None or size > len(self.__bigbuffer): - self.__copy_into_bigbuffer() + if size == 0: + self.__bigbuffer = None + self.__strings = None else: - # we can drop all extra strings - if self.__strings is not None: - self.__strings = None - if size < len(self.__bigbuffer): - del self.__bigbuffer[size:] - if len(self.__bigbuffer) == 0: - self.__bigbuffer = None + if self.__bigbuffer is None or size > len(self.__bigbuffer): + self.__copy_into_bigbuffer() + else: + # we can drop all extra strings + if self.__strings is not None: + self.__strings = None + if size < len(self.__bigbuffer): + del self.__bigbuffer[size:] + if len(self.__bigbuffer) == 0: + self.__bigbuffer = None # it always has the effect of seeking at the new end self.__pos = AT_END diff --git a/rpython/rlib/test/test_rStringIO.py b/rpython/rlib/test/test_rStringIO.py --- a/rpython/rlib/test/test_rStringIO.py +++ b/rpython/rlib/test/test_rStringIO.py @@ -117,6 +117,13 @@ assert f.getvalue() == '\x00' * 3 assert f.tell() == 3 +def test_truncate_end(): + f = RStringIO() + f.write("abc") + f.seek(0) + f.truncate(0) + assert f.getvalue() == "" + def test_bug(): f = RStringIO() f.write('0') From noreply at buildbot.pypy.org Fri May 31 22:45:55 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 31 May 2013 22:45:55 +0200 (CEST) Subject: [pypy-commit] pypy py3k: merge default Message-ID: <20130531204555.68E551C1442@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64693:699f19dc7cde Date: 2013-05-31 13:29 -0700 http://bitbucket.org/pypy/pypy/changeset/699f19dc7cde/ Log: merge default diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py --- a/lib-python/2.7/socket.py +++ b/lib-python/2.7/socket.py @@ -96,6 +96,7 @@ _realsocket = socket +_type = type # WSA error codes if sys.platform.lower().startswith("win"): @@ -173,31 +174,37 @@ __doc__ = _realsocket.__doc__ + __slots__ = ["_sock", "__weakref__"] + def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None): if _sock is None: _sock = _realsocket(family, type, proto) + elif _type(_sock) is _realsocket: + _sock._reuse() + # PyPy note about refcounting: implemented with _reuse()/_drop() + # on the class '_socket.socket'. Python 3 did it differently + # with a reference counter on this class 'socket._socketobject' + # instead, but it is a less compatible change (breaks eventlet). self._sock = _sock - self._io_refs = 0 - self._closed = False def send(self, data, flags=0): - return self._sock.send(data, flags=flags) + return self._sock.send(data, flags) send.__doc__ = _realsocket.send.__doc__ def recv(self, buffersize, flags=0): - return self._sock.recv(buffersize, flags=flags) + return self._sock.recv(buffersize, flags) recv.__doc__ = _realsocket.recv.__doc__ def recv_into(self, buffer, nbytes=0, flags=0): - return self._sock.recv_into(buffer, nbytes=nbytes, flags=flags) + return self._sock.recv_into(buffer, nbytes, flags) recv_into.__doc__ = _realsocket.recv_into.__doc__ def recvfrom(self, buffersize, flags=0): - return self._sock.recvfrom(buffersize, flags=flags) + return self._sock.recvfrom(buffersize, flags) recvfrom.__doc__ = _realsocket.recvfrom.__doc__ def recvfrom_into(self, buffer, nbytes=0, flags=0): - return self._sock.recvfrom_into(buffer, nbytes=nbytes, flags=flags) + return self._sock.recvfrom_into(buffer, nbytes, flags) recvfrom_into.__doc__ = _realsocket.recvfrom_into.__doc__ def sendto(self, data, param2, param3=None): @@ -208,13 +215,17 @@ sendto.__doc__ = _realsocket.sendto.__doc__ def close(self): - # This function should not reference any globals. See issue #808164. + s = self._sock + if type(s) is _realsocket: + s._drop() self._sock = _closedsocket() close.__doc__ = _realsocket.close.__doc__ def accept(self): sock, addr = self._sock.accept() - return _socketobject(_sock=sock), addr + sockobj = _socketobject(_sock=sock) + sock._drop() # already a copy in the _socketobject() + return sockobj, addr accept.__doc__ = _realsocket.accept.__doc__ def dup(self): @@ -228,24 +239,7 @@ Return a regular file object corresponding to the socket. The mode and bufsize arguments are as for the built-in open() function.""" - self._io_refs += 1 - return _fileobject(self, mode, bufsize) - - def _decref_socketios(self): - if self._io_refs > 0: - self._io_refs -= 1 - if self._closed: - self.close() - - def _real_close(self): - # This function should not reference any globals. See issue #808164. - self._sock.close() - - def close(self): - # This function should not reference any globals. See issue #808164. - self._closed = True - if self._io_refs <= 0: - self._real_close() + return _fileobject(self._sock, mode, bufsize) family = property(lambda self: self._sock.family, doc="the socket family") type = property(lambda self: self._sock.type, doc="the socket type") @@ -286,6 +280,8 @@ "_close"] def __init__(self, sock, mode='rb', bufsize=-1, close=False): + if type(sock) is _realsocket: + sock._reuse() self._sock = sock self.mode = mode # Not actually used in this version if bufsize < 0: @@ -320,16 +316,11 @@ if self._sock: self.flush() finally: - if self._sock: - if self._close: - self._sock.close() - else: - try: - self._sock._decref_socketios() - except AttributeError: - pass # bah, someone built a _fileobject manually - # with some unexpected replacement of the - # _socketobject class + s = self._sock + if type(s) is _realsocket: + s._drop() + if self._close: + self._sock.close() self._sock = None def __del__(self): diff --git a/lib_pypy/greenlet.egg-info b/lib_pypy/greenlet.egg-info new file mode 100644 --- /dev/null +++ b/lib_pypy/greenlet.egg-info @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: greenlet +Version: 0.4.0 +Summary: Lightweight in-process concurrent programming +Home-page: https://github.com/python-greenlet/greenlet +Author: Ralf Schmitt (for CPython), PyPy team +Author-email: pypy-dev at python.org +License: MIT License +Description: UNKNOWN +Platform: UNKNOWN diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -32,13 +32,12 @@ "rctime" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_minimal_curses", - "thread", "itertools", "pyexpat", "_ssl", "array", + "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", "binascii", "_multiprocessing", '_warnings', "_collections", "_multibytecodec", "_ffi", "_continuation", "_csv", "_cffi_backend", "_posixsubprocess", # "cppyy", "micronumpy", ] -# disabled until problems are fixed )) translation_modules = default_modules.copy() diff --git a/pypy/doc/rffi.rst b/pypy/doc/rffi.rst --- a/pypy/doc/rffi.rst +++ b/pypy/doc/rffi.rst @@ -5,7 +5,7 @@ Purpose ------- -This document describes an FFI for RPython language, concentrating +This document describes an FFI for the RPython language, concentrating on low-level backends like C. It describes how to declare and call low-level (C) functions from RPython level. @@ -50,7 +50,7 @@ ------ In rffi_ there are various declared types for C-structures, like CCHARP -(char*), SIZE_T (size_t) and others. refer to file for details. +(char*), SIZE_T (size_t) and others. Refer to file for details. Instances of non-primitive types must be alloced by hand, with call to lltype.malloc, and freed by lltype.free both with keyword argument flavor='raw'. There are several helpers like string -> char* diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py --- a/pypy/module/_ffi/test/test_funcptr.py +++ b/pypy/module/_ffi/test/test_funcptr.py @@ -46,6 +46,7 @@ libm = CDLL(libm_name) pow = libm.getpointer('pow', [], types.void) pow_addr = rffi.cast(rffi.LONG, pow.funcsym) + cls._libm = libm # otherwise it gets unloaded - argh! cls.w_pow_addr = space.wrap(pow_addr) class AppTestFFI(BaseAppTestFFI): diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -25,7 +25,7 @@ from pypy.objspace.std.sliceobject import W_SliceObject from pypy.module.__builtin__.descriptor import W_Property from pypy.module.__builtin__.interp_memoryview import W_MemoryView -from rpython.rlib.entrypoint import entrypoint +from rpython.rlib.entrypoint import entrypoint_lowlevel from rpython.rlib.rposix import is_valid_fd, validate_fd from rpython.rlib.unroll import unrolling_iterable from rpython.rlib.objectmodel import specialize @@ -545,38 +545,37 @@ def make_wrapper(space, callable): "NOT_RPYTHON" names = callable.api_func.argnames - argtypes = callable.api_func.argtypes - is_wrapped_list = [name.startswith("w_") for name in names] + argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes, + [name.startswith("w_") for name in names]))) fatal_value = callable.api_func.restype._defl() - lines = [] - for i, (argtype, is_wrapped) in enumerate(zip(argtypes, is_wrapped_list)): - if is_PyObject(argtype) and is_wrapped: - new_lines = [ - 'if %(arg)s:', - ' %(arg)s = from_ref(space, rffi.cast(PyObject, %(arg)s))', - 'else:', - ' %(arg)s = None', - ] - for j in range(len(new_lines)): - new_lines[j] = new_lines[j] % {'arg': 'arg%d' % i} - lines += new_lines - middle = '\n '.join(lines) - arg_spec = ", ".join(["arg%d" % i for i in range(len(argtypes))]) - - source = py.code.Source(""" - def wrapper(%(args)s): + @specialize.ll() + def wrapper(*args): from pypy.module.cpyext.pyobject import make_ref, from_ref from pypy.module.cpyext.pyobject import Reference + # we hope that malloc removal removes the newtuple() that is + # inserted exactly here by the varargs specializer + rffi.stackcounter.stacks_counter += 1 + llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py retval = fatal_value boxed_args = () try: if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, callable, + assert len(args) == len(callable.api_func.argtypes) + for i, (typ, is_wrapped) in argtypes_enum_ui: + arg = args[i] + if is_PyObject(typ) and is_wrapped: + if arg: + arg_conv = from_ref(space, rffi.cast(PyObject, arg)) + else: + arg_conv = None + else: + arg_conv = arg + boxed_args += (arg_conv, ) state = space.fromcache(State) - %(middle)s try: - result = callable(space, %(args)s) + result = callable(space, *boxed_args) if not we_are_translated() and DEBUG_WRAPPER: print >>sys.stderr, " DONE" except OperationError, e: @@ -598,8 +597,8 @@ if failed: error_value = callable.api_func.error_value if error_value is CANNOT_FAIL: - raise SystemError("The function '%%s' was not supposed to fail" - %% (callable.__name__,)) + raise SystemError("The function '%s' was not supposed to fail" + % (callable.__name__,)) retval = error_value elif is_PyObject(callable.api_func.restype): @@ -626,13 +625,8 @@ else: print str(e) pypy_debug_catch_fatal_exception() + rffi.stackcounter.stacks_counter -= 1 return retval - """ % {"middle": middle, "args": arg_spec}) - d = {} - d.update(locals()) - d.update(globals()) - exec source.compile() in d - wrapper = d['wrapper'] callable._always_inline_ = 'try' wrapper.__name__ = "wrapper for %r" % (callable, ) return wrapper @@ -1027,7 +1021,7 @@ export_struct(name, struct) for name, func in FUNCTIONS.iteritems(): - deco = entrypoint("cpyext", func.argtypes, name) + deco = entrypoint_lowlevel("cpyext", func.argtypes, name, relax=True) deco(func.get_wrapper(space)) setup_init_functions(eci, translating=True) 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 @@ -342,7 +342,7 @@ return @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, - error=-1, external=False) + error=-1, external=True) # XXX should not be exported @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,)) def slot_tp_setattro(space, w_self, w_name, w_value): if w_value is not None: diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py --- a/pypy/module/micronumpy/test/test_scalar.py +++ b/pypy/module/micronumpy/test/test_scalar.py @@ -21,3 +21,7 @@ a = zeros(3) assert loads(dumps(sum(a))) == sum(a) + + def setup_class(cls): + import py + py.test.xfail("FIXME: dtype('int32') == dtype('int32') fails") diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py --- a/pypy/module/pypyjit/test_pypy_c/model.py +++ b/pypy/module/pypyjit/test_pypy_c/model.py @@ -184,7 +184,7 @@ def match_by_id(self, id, expected_src, **kwds): ops = list(self.ops_by_id(id, **kwds)) - matcher = OpMatcher(ops) + matcher = OpMatcher(ops, id) return matcher.match(expected_src) class PartialTraceWithIds(TraceWithIds): @@ -260,8 +260,9 @@ class OpMatcher(object): - def __init__(self, ops): + def __init__(self, ops, id=None): self.ops = ops + self.id = id self.src = '\n'.join(map(str, ops)) self.alpha_map = {} @@ -495,6 +496,7 @@ print '@' * 40 print "Loops don't match" print "=================" + print 'loop id = %r' % (self.id,) print e.args print e.msg print diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py --- a/pypy/module/pypyjit/test_pypy_c/test_bug.py +++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py @@ -6,6 +6,11 @@ def test_bug1(): if not sys.platform.startswith('linux'): py.test.skip("linux-only test") + if '__pypy__' not in sys.builtin_module_names: + try: + import cffi + except ImportError, e: + py.test.skip(str(e)) cmdline = ['taskset', '-c', '0', sys.executable, os.path.join(localdir, 'bug1.py')] diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py --- a/pypy/module/pypyjit/test_pypy_c/test_call.py +++ b/pypy/module/pypyjit/test_pypy_c/test_call.py @@ -254,17 +254,22 @@ return c # s = 0 - for i in range(x): + i = 0 + while i < x: l = [i, x, 2] s += g(*l) # ID: g1 s += h(*l) # ID: h1 s += g(i, x, 2) # ID: g2 a = 0 - for i in range(x): + i += 1 + i = 0 + while i < x: l = [x, 2] + g(*l) s += g(i, *l) # ID: g3 s += h(i, *l) # ID: h2 a = 0 + i += 1 return s # log = self.run(main, [1000]) @@ -339,6 +344,7 @@ loop, = log.loops_by_filename(self.filepath) # the int strategy is used here assert loop.match_by_id('append', """ + guard_not_invalidated? i13 = getfield_gc(p8, descr=) i15 = int_add(i13, 1) # Will be killed by the backend @@ -486,6 +492,7 @@ assert loop.match(""" i2 = int_lt(i0, i1) guard_true(i2, descr=...) + guard_not_invalidated? i3 = force_token() i4 = int_add(i0, 1) --TICK-- @@ -585,7 +592,7 @@ """, [1000]) loop, = log.loops_by_id('call') assert loop.match_by_id('call', ''' - guard_not_invalidated(descr=...) + guard_not_invalidated? i1 = force_token() ''') diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py --- a/pypy/module/pypyjit/test_pypy_c/test_containers.py +++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py @@ -13,6 +13,7 @@ a = A() a.x = 1 for s in sys.modules.keys() * 1000: + d.get(s) # force pending setfields etc. inc = a.x # ID: look d[s] = d.get(s, 0) + inc return sum(d.values()) @@ -21,8 +22,7 @@ assert log.result % 1000 == 0 loop, = log.loops_by_filename(self.filepath) ops = loop.ops_by_id('look') - assert log.opnames(ops) == ['setfield_gc', - 'guard_not_invalidated'] + assert log.opnames(ops) == [] def test_identitydict(self): def fn(n): diff --git a/pypy/module/pypyjit/test_pypy_c/test_min_max.py b/pypy/module/pypyjit/test_pypy_c/test_min_max.py --- a/pypy/module/pypyjit/test_pypy_c/test_min_max.py +++ b/pypy/module/pypyjit/test_pypy_c/test_min_max.py @@ -49,17 +49,20 @@ label(..., descr=...) ... label(..., descr=...) + guard_not_invalidated? i17 = int_ge(i11, i7) guard_false(i17, descr=...) p18 = getarrayitem_gc(p5, i11, descr=...) i19 = int_add(i11, 1) setfield_gc(p2, i19, descr=...) - guard_class(p18, ConstClass(W_IntObject), descr=...) + guard_nonnull_class(p18, ConstClass(W_IntObject), descr=...) i20 = getfield_gc_pure(p18, descr=...) i21 = int_gt(i20, i14) guard_true(i21, descr=...) jump(..., descr=...) ''') + # XXX could be "guard_class(p18)" instead; we lost somewhere + # the information that it cannot be null. def test_iter_max(self): def main(): diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py --- a/pypy/module/pypyjit/test_pypy_c/test_misc.py +++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py @@ -177,6 +177,7 @@ assert log.result == 1000 * 999 / 2 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated? i16 = int_ge(i11, i12) guard_false(i16, descr=...) i17 = int_mul(i11, i14) @@ -184,7 +185,7 @@ i20 = int_add(i11, 1) i21 = force_token() setfield_gc(p4, i20, descr=<.* .*W_AbstractSeqIterObject.inst_index .*>) - guard_not_invalidated(descr=...) + guard_not_invalidated? i23 = int_lt(i18, 0) guard_false(i23, descr=...) i25 = int_ge(i18, i9) @@ -234,6 +235,7 @@ assert log.result == 1000000 loop, = log.loops_by_filename(self.filepath) assert loop.match(""" + guard_not_invalidated? i14 = getfield_gc(p12, descr=) i16 = uint_ge(i12, i14) guard_false(i16, descr=...) @@ -242,7 +244,7 @@ i19 = int_add(i12, 1) setfield_gc(p9, i19, descr=) guard_nonnull_class(p17, ..., descr=...) - guard_not_invalidated(descr=...) + guard_not_invalidated? i21 = getfield_gc(p17, descr=) i23 = int_lt(0, i21) guard_true(i23, descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -157,7 +157,7 @@ copystrcontent(p9, p21, 0, i25, i10) i33 = int_lt(i30, 23) guard_true(i33, descr=...) - p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=) + p35 = call(ConstClass(ll_shrink_array__rpy_stringPtr_Signed), p21, i30, descr=) guard_no_exception(descr=...) i37 = strlen(p35) i38 = int_add_ovf(i5, i37) @@ -190,7 +190,7 @@ assert len(loops) == 1 for loop in loops: loop.match_by_id('getattr',''' - guard_not_invalidated(descr=...) + guard_not_invalidated? i32 = strlen(p31) i34 = int_add(5, i32) p35 = newstr(i34) diff --git a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py --- a/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py +++ b/pypy/module/test_lib_pypy/cffi_tests/test_ffi_backend.py @@ -98,10 +98,10 @@ s = ffi.new("struct s1 *") setattr(s, name, value) assert getattr(s, name) == value - raw1 = bytes(ffi.buffer(s)) + raw1 = ffi.buffer(s)[:] if lib is not None: t = lib.try_with_value(fnames.index(name), value) - raw2 = bytes(ffi.buffer(t, len(raw1))) + raw2 = ffi.buffer(t, len(raw1))[:] assert raw1 == raw2 def test_bitfield_basic(self): diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py --- a/rpython/annotator/description.py +++ b/rpython/annotator/description.py @@ -215,8 +215,9 @@ if len(self._cache) != 1: raise NoStandardGraph(self) [graph] = self._cache.values() + relax_sig_check = getattr(self.pyobj, "relax_sig_check", False) if (graph.signature != self.signature or - graph.defaults != self.defaults): + graph.defaults != self.defaults) and not relax_sig_check: raise NoStandardGraph(self) return graph diff --git a/rpython/annotator/test/test_annrpython.py b/rpython/annotator/test/test_annrpython.py --- a/rpython/annotator/test/test_annrpython.py +++ b/rpython/annotator/test/test_annrpython.py @@ -3542,6 +3542,16 @@ s = a.build_types(f, [int]) assert s.knowntype is int + def test_relax(self): + def f(*args): + return args[0] + args[1] + f.relax_sig_check = True + def g(x): + return f(x, x - x) + a = self.RPythonAnnotator() + s = a.build_types(g, [int]) + assert a.bookkeeper.getdesc(f).getuniquegraph() + def test_cannot_raise_ll_exception(self): from rpython.rtyper.annlowlevel import cast_instance_to_base_ptr # diff --git a/rpython/rlib/entrypoint.py b/rpython/rlib/entrypoint.py --- a/rpython/rlib/entrypoint.py +++ b/rpython/rlib/entrypoint.py @@ -5,13 +5,33 @@ from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rlib.objectmodel import we_are_translated + +def entrypoint_lowlevel(key, argtypes, c_name=None, relax=False): + """ Note: entrypoint should call llop.gc_stack_bottom on it's own. + That's necessary for making it work with asmgcc and hence JIT + + If in doubt, use entrypoint(). + + if key == 'main' than it's included by default + """ + from rpython.translator.tool.cbuild import ExternalCompilationInfo + + def deco(func): + secondary_entrypoints.setdefault(key, []).append((func, argtypes)) + if c_name is not None: + func.c_name = c_name + if relax: + func.relax_sig_check = True + func._compilation_info = ExternalCompilationInfo( + export_symbols=[c_name or func.func_name]) + return func + return deco + + pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void) def entrypoint(key, argtypes, c_name=None): - """ Note: entrypoint should call llop.gc_stack_bottom on it's own. - That's necessary for making it work with asmgcc and hence JIT - - if key == 'main' than it's included by default + """if key == 'main' than it's included by default """ from rpython.translator.tool.cbuild import ExternalCompilationInfo diff --git a/rpython/rlib/rStringIO.py b/rpython/rlib/rStringIO.py --- a/rpython/rlib/rStringIO.py +++ b/rpython/rlib/rStringIO.py @@ -101,7 +101,11 @@ self.__pos = endp def seek(self, position, mode=0): - if mode == 1: + if mode == 0: + if position == self.getsize(): + self.__pos = AT_END + return + elif mode == 1: if self.__pos == AT_END: self.__pos = self.getsize() position += self.__pos @@ -163,14 +167,24 @@ return ''.join(self.__bigbuffer[p:i]) def truncate(self, size): + """Warning, this gets us slightly strange behavior from the + point of view of a traditional Unix file, but consistent with + Python 2.7's cStringIO module: it will not enlarge the file, + and it will always seek to the (new) end of the file.""" assert size >= 0 - if self.__bigbuffer is None or size > len(self.__bigbuffer): - self.__copy_into_bigbuffer() + if size == 0: + self.__bigbuffer = None + self.__strings = None else: - # we can drop all extra strings - if self.__strings is not None: - self.__strings = None - if size < len(self.__bigbuffer): - del self.__bigbuffer[size:] - if len(self.__bigbuffer) == 0: - self.__bigbuffer = None + if self.__bigbuffer is None or size > len(self.__bigbuffer): + self.__copy_into_bigbuffer() + else: + # we can drop all extra strings + if self.__strings is not None: + self.__strings = None + if size < len(self.__bigbuffer): + del self.__bigbuffer[size:] + if len(self.__bigbuffer) == 0: + self.__bigbuffer = None + # it always has the effect of seeking at the new end + self.__pos = AT_END diff --git a/rpython/rlib/test/test_rStringIO.py b/rpython/rlib/test/test_rStringIO.py --- a/rpython/rlib/test/test_rStringIO.py +++ b/rpython/rlib/test/test_rStringIO.py @@ -96,7 +96,15 @@ f.truncate(20) assert f.getvalue() == '' assert f.tell() == 0 - f.write('\x00' * 20) + f.write('\x00' * 25) + f.seek(12) + f.truncate(20) + assert f.getvalue() == '\x00' * 20 + assert f.tell() == 20 + f.write('more') + f.truncate(20) + assert f.getvalue() == '\x00' * 20 + assert f.tell() == 20 f.write('hello') f.write(' world') f.truncate(30) @@ -109,6 +117,13 @@ assert f.getvalue() == '\x00' * 3 assert f.tell() == 3 +def test_truncate_end(): + f = RStringIO() + f.write("abc") + f.seek(0) + f.truncate(0) + assert f.getvalue() == "" + def test_bug(): f = RStringIO() f.write('0') diff --git a/rpython/rlib/test/test_rlocale.py b/rpython/rlib/test/test_rlocale.py --- a/rpython/rlib/test/test_rlocale.py +++ b/rpython/rlib/test/test_rlocale.py @@ -20,8 +20,8 @@ def test_setlocale_worked(self): assert u"Ą".isupper() - raises(LocaleError, setlocale, LC_ALL, "bla bla bla") - raises(LocaleError, setlocale, 1234455, None) + py.test.raises(LocaleError, setlocale, LC_ALL, "bla bla bla") + py.test.raises(LocaleError, setlocale, 1234455, None) def test_lower_upper(self): assert isupper(ord("A")) diff --git a/rpython/translator/c/test/test_genc.py b/rpython/translator/c/test/test_genc.py --- a/rpython/translator/c/test/test_genc.py +++ b/rpython/translator/c/test/test_genc.py @@ -522,8 +522,9 @@ f = getattr(self, "_f", None) if f is not None: return f - f = lambda arg: self.func(arg) + f = lambda *args: self.func(*args) f.c_name = self.name + f.relax_sig_check = True f.__name__ = "WRAP%s" % (self.name, ) self._f = f return f From noreply at buildbot.pypy.org Fri May 31 22:45:56 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 31 May 2013 22:45:56 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix handling of identifiers in the compiler and the locals' conversions Message-ID: <20130531204556.C8B591C1442@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64694:e9592b260715 Date: 2013-05-31 13:43 -0700 http://bitbucket.org/pypy/pypy/changeset/e9592b260715/ Log: fix handling of identifiers in the compiler and the locals' conversions diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -305,7 +305,7 @@ for i, default in enumerate(args.kw_defaults): if default: kwonly = args.kwonlyargs[i] - self.load_const(self.space.wrap(kwonly.arg)) + self.load_const(self.space.wrap(kwonly.arg.decode('utf-8'))) default.walkabout(self) defaults += 1 return defaults @@ -336,7 +336,8 @@ if l: if l > 65534: self.error("too many annotations", func) - w_tup = space.newtuple([space.wrap(name) for name in names]) + w_tup = space.newtuple([space.wrap(name.decode('utf-8')) + for name in names]) self.load_const(w_tup) l += 1 return l @@ -389,7 +390,7 @@ # 3. load a function (or closure) made from the code object self._make_function(code, 0) # 4. load class name - self.load_const(self.space.wrap(cls.name)) + self.load_const(self.space.wrap(cls.name.decode('utf-8'))) # 5. generate the rest of the code for the call self._make_call(2, cls.bases, cls.keywords, @@ -723,7 +724,7 @@ for i in range(len(imp.names)): alias = imp.names[i] assert isinstance(alias, ast.alias) - names_w[i] = space.wrap(alias.name) + names_w[i] = space.wrap(alias.name.decode('utf-8')) self.load_const(space.newtuple(names_w)) if imp.module: mod_name = imp.module @@ -1024,7 +1025,7 @@ self.name_op(name.id, name.ctx) def visit_keyword(self, keyword): - self.load_const(self.space.wrap(keyword.arg)) + self.load_const(self.space.wrap(keyword.arg.decode('utf-8'))) keyword.value.walkabout(self) def _make_call(self, n, # args already pushed diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py --- a/pypy/interpreter/eval.py +++ b/pypy/interpreter/eval.py @@ -108,7 +108,7 @@ name = varnames[i] w_value = fastscope_w[i] if w_value is not None: - w_name = self.space.wrap(name) + w_name = self.space.wrap(name.decode('utf-8')) self.space.setitem(self.w_locals, w_name, w_value) def locals2fast(self): @@ -120,7 +120,7 @@ new_fastlocals_w = [None] * numlocals for i in range(min(len(varnames), numlocals)): - w_name = self.space.wrap(varnames[i]) + w_name = self.space.wrap(varnames[i].decode('utf-8')) try: w_value = self.space.getitem(self.w_locals, w_name) except OperationError, e: diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -840,6 +840,10 @@ raises(SyntaxError, eval, b'\xff\x20') raises(SyntaxError, eval, b'\xef\xbb\x20') + def test_import_nonascii(self): + c = compile('from os import 日本', '', 'exec') + assert ('日本',) in c.co_consts + def test_cpython_issue2301(self): skip('XXX') try: diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py --- a/pypy/interpreter/test/test_function.py +++ b/pypy/interpreter/test/test_function.py @@ -1,3 +1,4 @@ +# encoding: utf-8 import unittest from pypy.interpreter import eval from pypy.interpreter.function import Function, Method, descr_function_get @@ -43,6 +44,17 @@ assert f.__kwdefaults__ is None raises(TypeError, f) assert f(kw=42) == 42 + def f(*, 日本=3): return kw + assert f.__kwdefaults__ == {"日本" : 3} + """ + + def test_kw_nonascii(self): + """ + def f(日本: str=1): + return 日本 + assert f.__annotations__ == {'日本': str} + assert f() == 1 + assert f(日本='bar') == 'bar' """ def test_code_is_ok(self): From noreply at buildbot.pypy.org Fri May 31 22:54:12 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 31 May 2013 22:54:12 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix identifier handling in type's repr Message-ID: <20130531205412.C62911C1442@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64695:1fc4fb3e2d15 Date: 2013-05-31 13:46 -0700 http://bitbucket.org/pypy/pypy/changeset/1fc4fb3e2d15/ Log: fix identifier handling in type's repr diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py --- a/pypy/objspace/std/test/test_typeobject.py +++ b/pypy/objspace/std/test/test_typeobject.py @@ -1,3 +1,4 @@ +# encoding: utf-8 from pypy.objspace.std.model import W_Object from pypy.objspace.std.stdtypedef import StdTypeDef @@ -682,6 +683,9 @@ assert d['A'].__module__ == 'builtins' # obscure, follows CPython assert repr(d['A']) == "" + def test_repr_unicode(self): + assert repr(type('日本', (), {})) == "" % __name__ + def test_invalid_mro(self): class A(object): pass diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py --- a/pypy/objspace/std/typeobject.py +++ b/pypy/objspace/std/typeobject.py @@ -1119,11 +1119,12 @@ if not space.isinstance_w(w_mod, space.w_unicode): mod = None else: - mod = space.str_w(w_mod) - if mod is not None and mod != 'builtins': - return space.wrap("" % (mod, w_obj.name)) + mod = space.unicode_w(w_mod) + name = w_obj.name.decode('utf-8') + if mod is not None and mod != u'builtins': + return space.wrap(u"" % (mod, name)) else: - return space.wrap("" % (w_obj.name)) + return space.wrap(u"" % (name)) def getattr__Type_ANY(space, w_type, w_name): name = space.str_w(w_name) From noreply at buildbot.pypy.org Fri May 31 22:54:14 2013 From: noreply at buildbot.pypy.org (pjenvey) Date: Fri, 31 May 2013 22:54:14 +0200 (CEST) Subject: [pypy-commit] pypy py3k: fix identifier handling in module's repr Message-ID: <20130531205414.207481C1442@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r64696:dd88d8fe7adf Date: 2013-05-31 13:51 -0700 http://bitbucket.org/pypy/pypy/changeset/dd88d8fe7adf/ Log: fix identifier handling in module's repr diff --git a/pypy/interpreter/module.py b/pypy/interpreter/module.py --- a/pypy/interpreter/module.py +++ b/pypy/interpreter/module.py @@ -112,14 +112,14 @@ def descr_module__repr__(self, space): from pypy.interpreter.mixedmodule import MixedModule if self.w_name is not None: - name = space.str_w(space.repr(self.w_name)) + name = space.unicode_w(space.repr(self.w_name)) else: - name = "'?'" + name = u"'?'" if isinstance(self, MixedModule): - return space.wrap("" % name) + return space.wrap(u"" % name) try: w___file__ = space.getattr(self, space.wrap('__file__')) - __file__ = space.str_w(space.repr(w___file__)) + __file__ = space.unicode_w(space.repr(w___file__)) except OperationError: - __file__ = '?' - return space.wrap("" % (name, __file__)) + __file__ = u'?' + return space.wrap(u"" % (name, __file__)) diff --git a/pypy/interpreter/test/test_module.py b/pypy/interpreter/test/test_module.py --- a/pypy/interpreter/test/test_module.py +++ b/pypy/interpreter/test/test_module.py @@ -1,4 +1,4 @@ - +# encoding: utf-8 from pypy.interpreter.module import Module class TestModule: @@ -75,3 +75,9 @@ assert sys.__package__ is None assert os.__package__ is None assert not hasattr(type(sys)('foo'), '__package__') + + def test_name_nonascii(self): + import sys + m = type(sys)('日本') + assert m.__name__ == '日本' + assert repr(m).startswith(" Author: Alex Gaynor Branch: Changeset: r64697:9b895ea86405 Date: 2013-05-31 13:59 -0700 http://bitbucket.org/pypy/pypy/changeset/9b895ea86405/ Log: let the JIT inline into IO, stuff like seek()/etc. are very cheap diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -109,7 +109,7 @@ 'posix', '_socket', '_sre', '_lsprof', '_weakref', '__pypy__', 'cStringIO', '_collections', 'struct', 'mmap', 'marshal', '_codecs', 'rctime', 'cppyy', - '_cffi_backend', 'pyexpat', '_continuation']: + '_cffi_backend', 'pyexpat', '_continuation', '_io']: if modname == 'pypyjit' and 'interp_resop' in rest: return False return True diff --git a/pypy/module/pypyjit/test/test_policy.py b/pypy/module/pypyjit/test/test_policy.py --- a/pypy/module/pypyjit/test/test_policy.py +++ b/pypy/module/pypyjit/test/test_policy.py @@ -36,6 +36,10 @@ from pypy.module.rctime.interp_time import time assert pypypolicy.look_inside_function(time) +def test_io(): + from pypy.module._io.interp_bytesio import W_BytesIO + assert pypypolicy.look_inside_function(W_BytesIO.seek_w.im_func) + def test_pypy_module(): from pypy.module._collections.interp_deque import W_Deque from pypy.module._random.interp_random import W_Random