Author: Philip Jenvey <pjen...@underboss.org> 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) + +@jit.oopspec('rgc.ll_shrink_array(p, smallerlength)') +@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): _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit