Author: Ronny Pfannschmidt <ronny.pfannschm...@gmx.de> Branch: Changeset: r54331:f7ddf20f141f Date: 2012-04-13 12:52 +0200 http://bitbucket.org/pypy/pypy/changeset/f7ddf20f141f/
Log: merge upstream diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py --- a/pypy/annotation/test/test_annrpython.py +++ b/pypy/annotation/test/test_annrpython.py @@ -3746,9 +3746,9 @@ return g(i) def main(i): if i == 2: - return f(i) + return f(2) elif i == 3: - return f(i) + return f(3) else: raise NotImplementedError diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py --- a/pypy/interpreter/argument.py +++ b/pypy/interpreter/argument.py @@ -169,9 +169,11 @@ def _combine_starstarargs_wrapped(self, w_starstararg): # unpack the ** arguments space = self.space + keywords, values_w = space.view_as_kwargs(w_starstararg) + if keywords is not None: # this path also taken for empty dicts + self._add_keywordargs_no_unwrapping(keywords, values_w) + return not jit.isconstant(len(self.keywords)) if space.isinstance_w(w_starstararg, space.w_dict): - if not space.is_true(w_starstararg): - return False # don't call unpackiterable - it's jit-opaque keys_w = space.unpackiterable(w_starstararg) else: try: @@ -186,11 +188,8 @@ "a mapping, not %s" % (typename,))) raise keys_w = space.unpackiterable(w_keys) - if keys_w: - self._do_combine_starstarargs_wrapped(keys_w, w_starstararg) - return True - else: - return False # empty dict; don't disable the JIT + self._do_combine_starstarargs_wrapped(keys_w, w_starstararg) + return True def _do_combine_starstarargs_wrapped(self, keys_w, w_starstararg): space = self.space @@ -227,6 +226,26 @@ self.keywords_w = self.keywords_w + keywords_w self.keyword_names_w = keys_w + @jit.look_inside_iff(lambda self, keywords, keywords_w: + jit.isconstant(len(keywords) and + jit.isconstant(self.keywords))) + def _add_keywordargs_no_unwrapping(self, keywords, keywords_w): + if self.keywords is None: + self.keywords = keywords[:] # copy to make non-resizable + self.keywords_w = keywords_w[:] + else: + # looks quadratic, but the JIT should remove all of it nicely. + # Also, all the lists should be small + for key in keywords: + for otherkey in self.keywords: + if otherkey == key: + raise operationerrfmt(self.space.w_TypeError, + "got multiple values " + "for keyword argument " + "'%s'", key) + self.keywords = self.keywords + keywords + self.keywords_w = self.keywords_w + keywords_w + def fixedunpack(self, argcount): """The simplest argument parsing: get the 'argcount' arguments, or raise a real ValueError if the length is wrong.""" @@ -385,7 +404,7 @@ # collect extra keyword arguments into the **kwarg if has_kwarg: - w_kwds = self.space.newdict() + w_kwds = self.space.newdict(kwargs=True) if num_remainingkwds: # limit = len(keywords) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -914,6 +914,12 @@ """ return None + def view_as_kwargs(self, w_dict): + """ if w_dict is a kwargs-dict, return two lists, one of unwrapped + strings and one of wrapped values. otherwise return (None, None) + """ + return (None, None) + def newlist_str(self, list_s): return self.newlist([self.wrap(s) for s in list_s]) 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 @@ -75,7 +75,10 @@ def unpackiterable(self, it): return list(it) - def newdict(self): + def view_as_kwargs(self, x): + return None, None + + def newdict(self, kwargs=False): return {} def newlist(self, l=[]): @@ -488,6 +491,57 @@ assert len(l) == 1 assert l[0] == space.wrap(5) + def test_starstarargs_special(self): + class kwargs(object): + def __init__(self, k, v): + self.k = k + self.v = v + class MyDummySpace(DummySpace): + def view_as_kwargs(self, kw): + if isinstance(kw, kwargs): + return kw.k, kw.v + return None, None + space = MyDummySpace() + for i in range(3): + kwds = [("c", 3)] + kwds_w = dict(kwds[:i]) + keywords = kwds_w.keys() + keywords_w = kwds_w.values() + rest = dict(kwds[i:]) + w_kwds = kwargs(rest.keys(), rest.values()) + if i == 2: + w_kwds = None + assert len(keywords) == len(keywords_w) + args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) + l = [None, None, None] + args._match_signature(None, l, Signature(["a", "b", "c"]), defaults_w=[4]) + assert l == [1, 2, 3] + args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) + l = [None, None, None, None] + args._match_signature(None, l, Signature(["a", "b", "b1", "c"]), defaults_w=[4, 5]) + assert l == [1, 2, 4, 3] + args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) + l = [None, None, None, None] + args._match_signature(None, l, Signature(["a", "b", "c", "d"]), defaults_w=[4, 5]) + assert l == [1, 2, 3, 5] + args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) + l = [None, None, None, None] + py.test.raises(ArgErr, args._match_signature, None, l, + Signature(["c", "b", "a", "d"]), defaults_w=[4, 5]) + args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) + l = [None, None, None, None] + py.test.raises(ArgErr, args._match_signature, None, l, + Signature(["a", "b", "c1", "d"]), defaults_w=[4, 5]) + args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds) + l = [None, None, None] + args._match_signature(None, l, Signature(["a", "b"], None, "**")) + assert l == [1, 2, {'c': 3}] + excinfo = py.test.raises(OperationError, Arguments, space, [], ["a"], + [1], w_starstararg=kwargs(["a"], [2])) + assert excinfo.value.w_type is TypeError + + + class TestErrorHandling(object): def test_missing_args(self): # got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg, 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 @@ -244,6 +244,7 @@ print guards assert len(guards) <= 20 + def test_stararg_virtual(self): def main(x): def g(*args): @@ -486,3 +487,38 @@ --TICK-- jump(..., descr=...) """) + + def test_kwargs_virtual2(self): + log = self.run(""" + def f(*args, **kwargs): + kwargs['a'] = kwargs['z'] * 0 + return g(1, *args, **kwargs) + + def g(x, y, z=2, a=1): + return x - y + z + a + + def main(stop): + res = 0 + i = 0 + while i < stop: + res = f(res, z=i) # ID: call + i += 1 + return res""", [1000]) + assert log.result == 500 + loop, = log.loops_by_id('call') + print loop.ops_by_id('call') + assert loop.match(""" + i65 = int_lt(i58, i29) + guard_true(i65, descr=...) + guard_not_invalidated(..., descr=...) + i66 = force_token() + i67 = force_token() + i69 = int_sub_ovf(1, i56) + guard_no_overflow(..., descr=...) + i70 = int_add_ovf(i69, i58) + guard_no_overflow(..., descr=...) + i71 = int_add(i58, 1) + --TICK-- + jump(..., descr=...) + """) + 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,7 +110,7 @@ "NOT_RPYTHON" raise NotImplementedError - def newdict(self, module=False, instance=False, + def newdict(self, module=False, instance=False, kwargs=False, strdict=False): return w_some_obj() 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 @@ -33,7 +33,7 @@ @staticmethod def allocate_and_init_instance(space, w_type=None, module=False, - instance=False, strdict=False): + instance=False, strdict=False, kwargs=False): if space.config.objspace.std.withcelldict and module: from pypy.objspace.std.celldict import ModuleDictStrategy @@ -46,11 +46,15 @@ assert w_type is None strategy = space.fromcache(StringDictStrategy) + elif kwargs: + assert w_type is None + from pypy.objspace.std.kwargsdict import KwargsDictStrategy + strategy = space.fromcache(KwargsDictStrategy) else: strategy = space.fromcache(EmptyDictStrategy) - if w_type is None: w_type = space.w_dict + storage = strategy.get_empty_storage() w_self = space.allocate_instance(W_DictMultiObject, w_type) W_DictMultiObject.__init__(w_self, space, strategy, storage) @@ -91,7 +95,8 @@ getitem_str delitem length \ clear w_keys values \ items iter setdefault \ - popitem listview_str listview_int".split() + popitem listview_str listview_int \ + view_as_kwargs".split() def make_method(method): def f(self, *args): @@ -165,6 +170,9 @@ def listview_int(self, w_dict): return None + def view_as_kwargs(self, w_dict): + return (None, None) + class EmptyDictStrategy(DictStrategy): erase, unerase = rerased.new_erasing_pair("empty") @@ -254,6 +262,9 @@ def popitem(self, w_dict): raise KeyError + def view_as_kwargs(self, w_dict): + return ([], []) + registerimplementation(W_DictMultiObject) # DictImplementation lattice diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/kwargsdict.py @@ -0,0 +1,165 @@ +## ---------------------------------------------------------------------------- +## dict strategy (see dictmultiobject.py) + +from pypy.rlib import rerased, jit +from pypy.objspace.std.dictmultiobject import (DictStrategy, + IteratorImplementation, + ObjectDictStrategy, + StringDictStrategy) + + +class KwargsDictStrategy(DictStrategy): + erase, unerase = rerased.new_erasing_pair("kwargsdict") + erase = staticmethod(erase) + unerase = staticmethod(unerase) + + def wrap(self, key): + return self.space.wrap(key) + + def unwrap(self, wrapped): + return self.space.str_w(wrapped) + + def get_empty_storage(self): + d = ([], []) + return self.erase(d) + + def is_correct_type(self, w_obj): + space = self.space + return space.is_w(space.type(w_obj), space.w_str) + + def _never_equal_to(self, w_lookup_type): + return False + + def iter(self, w_dict): + return KwargsDictIterator(self.space, self, w_dict) + + def w_keys(self, w_dict): + return self.space.newlist([self.space.wrap(key) for key in self.unerase(w_dict.dstorage)[0]]) + + def setitem(self, w_dict, w_key, w_value): + space = self.space + if self.is_correct_type(w_key): + self.setitem_str(w_dict, self.unwrap(w_key), w_value) + return + else: + self.switch_to_object_strategy(w_dict) + w_dict.setitem(w_key, w_value) + + def setitem_str(self, w_dict, key, w_value): + self._setitem_str_indirection(w_dict, key, w_value) + + @jit.look_inside_iff(lambda self, w_dict, key, w_value: + jit.isconstant(self.length(w_dict)) and jit.isconstant(key)) + def _setitem_str_indirection(self, w_dict, key, w_value): + keys, values_w = self.unerase(w_dict.dstorage) + result = [] + for i in range(len(keys)): + if keys[i] == key: + values_w[i] = w_value + break + else: + # limit the size so that the linear searches don't become too long + if len(keys) >= 16: + self.switch_to_string_strategy(w_dict) + w_dict.setitem_str(key, w_value) + else: + keys.append(key) + values_w.append(w_value) + + def setdefault(self, w_dict, w_key, w_default): + # XXX could do better, but is it worth it? + self.switch_to_object_strategy(w_dict) + return w_dict.setdefault(w_key, w_default) + + def delitem(self, w_dict, w_key): + # XXX could do better, but is it worth it? + self.switch_to_object_strategy(w_dict) + return w_dict.delitem(w_key) + + def length(self, w_dict): + return len(self.unerase(w_dict.dstorage)[0]) + + def getitem_str(self, w_dict, key): + return self._getitem_str_indirection(w_dict, key) + + @jit.look_inside_iff(lambda self, w_dict, key: jit.isconstant(self.length(w_dict)) and jit.isconstant(key)) + def _getitem_str_indirection(self, w_dict, key): + keys, values_w = self.unerase(w_dict.dstorage) + result = [] + for i in range(len(keys)): + if keys[i] == key: + return values_w[i] + return None + + def getitem(self, w_dict, w_key): + space = self.space + if self.is_correct_type(w_key): + return self.getitem_str(w_dict, self.unwrap(w_key)) + elif self._never_equal_to(space.type(w_key)): + return None + else: + self.switch_to_object_strategy(w_dict) + return w_dict.getitem(w_key) + + def w_keys(self, w_dict): + l = self.unerase(w_dict.dstorage)[0] + return self.space.newlist_str(l[:]) + + def values(self, w_dict): + return self.unerase(w_dict.dstorage)[1][:] # to make non-resizable + + def items(self, w_dict): + space = self.space + keys, values_w = self.unerase(w_dict.dstorage) + result = [] + for i in range(len(keys)): + result.append(space.newtuple([self.wrap(keys[i]), values_w[i]])) + return result + + def popitem(self, w_dict): + keys, values_w = self.unerase(w_dict.dstorage) + key = keys.pop() + w_value = values_w.pop() + return (self.wrap(key), w_value) + + def clear(self, w_dict): + w_dict.dstorage = self.get_empty_storage() + + def switch_to_object_strategy(self, w_dict): + strategy = self.space.fromcache(ObjectDictStrategy) + keys, values_w = self.unerase(w_dict.dstorage) + d_new = strategy.unerase(strategy.get_empty_storage()) + for i in range(len(keys)): + d_new[self.wrap(keys[i])] = values_w[i] + w_dict.strategy = strategy + w_dict.dstorage = strategy.erase(d_new) + + def switch_to_string_strategy(self, w_dict): + strategy = self.space.fromcache(StringDictStrategy) + keys, values_w = self.unerase(w_dict.dstorage) + storage = strategy.get_empty_storage() + d_new = strategy.unerase(storage) + for i in range(len(keys)): + d_new[keys[i]] = values_w[i] + w_dict.strategy = strategy + w_dict.dstorage = storage + + def view_as_kwargs(self, w_dict): + return self.unerase(w_dict.dstorage) + + +class KwargsDictIterator(IteratorImplementation): + def __init__(self, space, strategy, dictimplementation): + IteratorImplementation.__init__(self, space, strategy, dictimplementation) + keys, values_w = strategy.unerase(self.dictimplementation.dstorage) + self.iterator = iter(range(len(keys))) + # XXX this potentially leaks + self.keys = keys + self.values_w = values_w + + def next_entry(self): + # note that this 'for' loop only runs once, at most + for i in self.iterator: + return self.space.wrap(self.keys[i]), self.values_w[i] + else: + return None, None 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 @@ -313,11 +313,11 @@ def newlist_str(self, list_s): return W_ListObject.newlist_str(self, list_s) - def newdict(self, module=False, instance=False, + def newdict(self, module=False, instance=False, kwargs=False, strdict=False): return W_DictMultiObject.allocate_and_init_instance( self, module=module, instance=instance, - strdict=strdict) + strdict=strdict, kwargs=kwargs) def newset(self): from pypy.objspace.std.setobject import newset @@ -472,6 +472,11 @@ return w_obj.getitems_int() return None + def view_as_kwargs(self, w_dict): + if type(w_dict) is W_DictMultiObject: + return w_dict.view_as_kwargs() + return (None, None) + def _uses_list_iter(self, w_obj): from pypy.objspace.descroperation import list_iter return self.lookup(w_obj, '__iter__') is list_iter(self) diff --git a/pypy/objspace/std/test/test_kwargsdict.py b/pypy/objspace/std/test/test_kwargsdict.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_kwargsdict.py @@ -0,0 +1,120 @@ +import py +from pypy.conftest import gettestobjspace, option +from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictMultiObject +from pypy.objspace.std.kwargsdict import * + +space = FakeSpace() +strategy = KwargsDictStrategy(space) + +def test_create(): + keys = ["a", "b", "c"] + values = [1, 2, 3] + storage = strategy.erase((keys, values)) + d = W_DictMultiObject(space, strategy, storage) + assert d.getitem_str("a") == 1 + assert d.getitem_str("b") == 2 + assert d.getitem_str("c") == 3 + assert d.getitem(space.wrap("a")) == 1 + assert d.getitem(space.wrap("b")) == 2 + assert d.getitem(space.wrap("c")) == 3 + assert d.w_keys() == keys + assert d.values() == values + +def test_set_existing(): + keys = ["a", "b", "c"] + values = [1, 2, 3] + storage = strategy.erase((keys, values)) + d = W_DictMultiObject(space, strategy, storage) + assert d.getitem_str("a") == 1 + assert d.getitem_str("b") == 2 + assert d.getitem_str("c") == 3 + assert d.setitem_str("a", 4) is None + assert d.getitem_str("a") == 4 + assert d.getitem_str("b") == 2 + assert d.getitem_str("c") == 3 + assert d.setitem_str("b", 5) is None + assert d.getitem_str("a") == 4 + assert d.getitem_str("b") == 5 + assert d.getitem_str("c") == 3 + assert d.setitem_str("c", 6) is None + assert d.getitem_str("a") == 4 + assert d.getitem_str("b") == 5 + assert d.getitem_str("c") == 6 + assert d.getitem(space.wrap("a")) == 4 + assert d.getitem(space.wrap("b")) == 5 + assert d.getitem(space.wrap("c")) == 6 + assert d.w_keys() == keys + assert d.values() == values + assert keys == ["a", "b", "c"] + assert values == [4, 5, 6] + + +def test_set_new(): + keys = ["a", "b", "c"] + values = [1, 2, 3] + storage = strategy.erase((keys, values)) + d = W_DictMultiObject(space, strategy, storage) + assert d.getitem_str("a") == 1 + assert d.getitem_str("b") == 2 + assert d.getitem_str("c") == 3 + assert d.getitem_str("d") is None + assert d.setitem_str("d", 4) is None + assert d.getitem_str("a") == 1 + assert d.getitem_str("b") == 2 + assert d.getitem_str("c") == 3 + assert d.getitem_str("d") == 4 + assert d.w_keys() == keys + assert d.values() == values + assert keys == ["a", "b", "c", "d"] + assert values == [1, 2, 3, 4] + +def test_limit_size(): + storage = strategy.get_empty_storage() + d = W_DictMultiObject(space, strategy, storage) + for i in range(100): + assert d.setitem_str("d%s" % i, 4) is None + assert d.strategy is not strategy + assert "StringDictStrategy" == d.strategy.__class__.__name__ + +def test_keys_doesnt_wrap(): + space = FakeSpace() + space.newlist = None + strategy = KwargsDictStrategy(space) + keys = ["a", "b", "c"] + values = [1, 2, 3] + storage = strategy.erase((keys, values)) + d = W_DictMultiObject(space, strategy, storage) + w_l = d.w_keys() # does not crash + + +from pypy.objspace.std.test.test_dictmultiobject import BaseTestRDictImplementation, BaseTestDevolvedDictImplementation +def get_impl(self): + storage = strategy.erase(([], [])) + return W_DictMultiObject(space, strategy, storage) +class TestKwargsDictImplementation(BaseTestRDictImplementation): + StrategyClass = KwargsDictStrategy + get_impl = get_impl + def test_delitem(self): + pass # delitem devolves for now + +class TestDevolvedKwargsDictImplementation(BaseTestDevolvedDictImplementation): + get_impl = get_impl + StrategyClass = KwargsDictStrategy + + +class AppTestKwargsDictStrategy(object): + def setup_class(cls): + if option.runappdirect: + py.test.skip("__repr__ doesn't work on appdirect") + + def w_get_strategy(self, obj): + import __pypy__ + r = __pypy__.internal_repr(obj) + return r[r.find("(") + 1: r.find(")")] + + def test_create(self): + def f(**args): + return args + d = f(a=1) + assert "KwargsDictStrategy" in self.get_strategy(d) + _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit