[pypy-commit] pypy virtual-arguments: replace the used_keywords list of bools with a much shorter list
cfbolz
noreply at buildbot.pypy.org
Mon Apr 23 11:54:28 CEST 2012
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: virtual-arguments
Changeset: r54656:075a2619161a
Date: 2012-04-22 11:37 +0200
http://bitbucket.org/pypy/pypy/changeset/075a2619161a/
Log: replace the used_keywords list of bools with a much shorter list
that is as long as the number of potentially missing arguments the
content of the list is an index into keywords_w
the idea is that scope_w should not be passed into a residual call.
that would make it escape, which is bad, scope_w is part of an
(ideally virtual) frame later
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -296,35 +296,45 @@
# handle keyword arguments
num_remainingkwds = 0
- used_keywords = None
keywords_w = self.keywords_w
+ kwds_mapping = None
if num_kwds:
- used_keywords = [False] * num_kwds
+ # kwds_mapping maps target indexes in the scope (minus input_argcount)
+ # to positions in the keywords_w list
+ kwds_mapping = [-1] * (co_argcount - input_argcount)
# match the keywords given at the call site to the argument names
# the called function takes
+ # this function must not take a scope_w, to make the scope not
+ # escape
num_remainingkwds = _match_keywords(
signature, blindargs, input_argcount, keywords,
- keywords_w, scope_w, used_keywords,
- self._jit_few_keywords)
+ kwds_mapping, self._jit_few_keywords)
if num_remainingkwds:
if w_kwds is not None:
# collect extra keyword arguments into the **kwarg
_collect_keyword_args(
self.space, keywords, keywords_w, w_kwds,
- used_keywords, self.keyword_names_w, self._jit_few_keywords)
+ kwds_mapping, self.keyword_names_w, self._jit_few_keywords)
else:
if co_argcount == 0:
raise ArgErrCount(avail, num_kwds, signature, defaults_w, 0)
raise ArgErrUnknownKwds(self.space, num_remainingkwds, keywords,
- used_keywords, self.keyword_names_w)
+ kwds_mapping, self.keyword_names_w)
- # check for missing arguments and fill them with defaults, if available
+ # check for missing arguments and fill them from the kwds,
+ # or with defaults, if available
missing = 0
if input_argcount < co_argcount:
def_first = co_argcount - (0 if defaults_w is None else len(defaults_w))
+ j = 0
+ kwds_index = -1
for i in range(input_argcount, co_argcount):
- if scope_w[i] is not None:
- continue
+ if kwds_mapping is not None:
+ kwds_index = kwds_mapping[j]
+ j += 1
+ if kwds_index != -1:
+ scope_w[i] = keywords_w[kwds_index]
+ continue
defnum = i - def_first
if defnum >= 0:
scope_w[i] = defaults_w[defnum]
@@ -441,10 +451,10 @@
i += 1
@jit.look_inside_iff(
- lambda signature, blindargs, input_argcount, keywords, keywords_w,
- scope_w, used_keywords, jiton: jiton)
+ lambda signature, blindargs, input_argcount, keywords,
+ scope_w, kwds_mapping, jiton: jiton)
def _match_keywords(signature, blindargs, input_argcount,
- keywords, keywords_w, scope_w, used_keywords, _):
+ keywords, kwds_mapping, _):
# letting JIT unroll the loop is *only* safe if the callsite didn't
# use **args because num_kwds can be arbitrarily large otherwise.
num_kwds = num_remainingkwds = len(keywords)
@@ -466,22 +476,25 @@
if blindargs <= j:
raise ArgErrMultipleValues(name)
else:
- assert scope_w[j] is None
- scope_w[j] = keywords_w[i]
- used_keywords[i] = True # mark as used
+ kwds_mapping[j - input_argcount] = i # map to the right index
num_remainingkwds -= 1
return num_remainingkwds
@jit.look_inside_iff(
- lambda space, keywords, keywords_w, w_kwds, used_keywords,
+ lambda space, keywords, keywords_w, w_kwds, kwds_mapping,
keyword_names_w, jiton: jiton)
-def _collect_keyword_args(space, keywords, keywords_w, w_kwds, used_keywords,
+def _collect_keyword_args(space, keywords, keywords_w, w_kwds, kwds_mapping,
keyword_names_w, _):
limit = len(keywords)
if keyword_names_w is not None:
limit -= len(keyword_names_w)
for i in range(len(keywords)):
- if not used_keywords[i]:
+ # again a dangerous-looking loop that either the JIT unrolls
+ # or that is not too bad, because len(kwds_mapping) is small
+ for j in kwds_mapping:
+ if i == j:
+ break
+ else:
if i < limit:
w_key = space.wrap(keywords[i])
else:
@@ -701,13 +714,13 @@
class ArgErrUnknownKwds(ArgErr):
- def __init__(self, space, num_remainingkwds, keywords, used_keywords,
+ def __init__(self, space, num_remainingkwds, keywords, kwds_mapping,
keyword_names_w):
name = ''
self.num_kwds = num_remainingkwds
if num_remainingkwds == 1:
for i in range(len(keywords)):
- if not used_keywords[i]:
+ if i not in kwds_mapping:
name = keywords[i]
if name is None:
# We'll assume it's unicode. Encode it.
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
@@ -632,11 +632,14 @@
def test_unknown_keywords(self):
space = DummySpace()
- err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [True, False], None)
+ err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [0], None)
s = err.getmsg()
assert s == "got an unexpected keyword argument 'b'"
+ err = ArgErrUnknownKwds(space, 1, ['a', 'b'], [1], None)
+ s = err.getmsg()
+ assert s == "got an unexpected keyword argument 'a'"
err = ArgErrUnknownKwds(space, 2, ['a', 'b', 'c'],
- [True, False, False], None)
+ [0], None)
s = err.getmsg()
assert s == "got 2 unexpected keyword arguments"
@@ -646,7 +649,7 @@
defaultencoding = 'utf-8'
space = DummySpaceUnicode()
err = ArgErrUnknownKwds(space, 1, ['a', None, 'b', 'c'],
- [True, False, True, True],
+ [0, 3, 2],
[unichr(0x1234), u'b', u'c'])
s = err.getmsg()
assert s == "got an unexpected keyword argument '\xe1\x88\xb4'"
More information about the pypy-commit
mailing list