[pypy-svn] r79172 - in pypy/trunk/pypy: interpreter interpreter/test module/array module/pypyjit/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Wed Nov 17 10:44:47 CET 2010
Author: cfbolz
Date: Wed Nov 17 10:44:46 2010
New Revision: 79172
Modified:
pypy/trunk/pypy/interpreter/argument.py
pypy/trunk/pypy/interpreter/test/test_argument.py
pypy/trunk/pypy/module/array/interp_array.py
pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
Log:
svn merge -r79092:HEAD http://codespeak.net/svn/pypy/branch/jit-starargs
make the jit handle better calling functions with *args.
Modified: pypy/trunk/pypy/interpreter/argument.py
==============================================================================
--- pypy/trunk/pypy/interpreter/argument.py (original)
+++ pypy/trunk/pypy/interpreter/argument.py Wed Nov 17 10:44:46 2010
@@ -64,7 +64,7 @@
return not self == other
- # make it look tuply for the annotator
+ # make it look tuply for its use in the annotator
def __len__(self):
return 3
@@ -103,10 +103,11 @@
make_sure_not_resized(self.keywords_w)
make_sure_not_resized(self.arguments_w)
- if ((w_stararg is not None and w_stararg) or
- (w_starstararg is not None and w_starstararg)):
- self._combine_wrapped(w_stararg, w_starstararg)
- # if we have a call where * or ** args are used at the callsite
+ if w_stararg is not None and space.is_true(w_stararg):
+ self._combine_starargs_wrapped(w_stararg)
+ if w_starstararg is not None and space.is_true(w_starstararg):
+ self._combine_starstarargs_wrapped(w_starstararg)
+ # if we have a call where **args are used at the callsite
# we shouldn't let the JIT see the argument matching
self._dont_jit = True
else:
@@ -142,42 +143,48 @@
def _combine_wrapped(self, w_stararg, w_starstararg):
"unpack the *arg and **kwd into arguments_w and keywords_w"
- # unpack the * arguments
if w_stararg is not None:
- self.arguments_w = (self.arguments_w +
- self.space.fixedview(w_stararg))
- # unpack the ** arguments
+ self._combine_starargs_wrapped(w_stararg)
if w_starstararg is not None:
- space = self.space
- if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
+ self._combine_starstarargs_wrapped(w_starstararg)
+
+ def _combine_starargs_wrapped(self, w_stararg):
+ # unpack the * arguments
+ self.arguments_w = (self.arguments_w +
+ self.space.fixedview(w_stararg))
+
+ def _combine_starstarargs_wrapped(self, w_starstararg):
+ # unpack the ** arguments
+ space = self.space
+ if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("argument after ** must be "
+ "a dictionary"))
+ keywords_w = [None] * space.int_w(space.len(w_starstararg))
+ keywords = [None] * space.int_w(space.len(w_starstararg))
+ i = 0
+ for w_key in space.unpackiterable(w_starstararg):
+ try:
+ key = space.str_w(w_key)
+ except OperationError, e:
+ if not e.match(space, space.w_TypeError):
+ raise
raise OperationError(space.w_TypeError,
- space.wrap("argument after ** must be "
- "a dictionary"))
- keywords_w = [None] * space.int_w(space.len(w_starstararg))
- keywords = [None] * space.int_w(space.len(w_starstararg))
- i = 0
- for w_key in space.unpackiterable(w_starstararg):
- try:
- key = space.str_w(w_key)
- except OperationError, e:
- if not e.match(space, space.w_TypeError):
- raise
- raise OperationError(space.w_TypeError,
- space.wrap("keywords must be strings"))
- if self.keywords and key in self.keywords:
- raise operationerrfmt(self.space.w_TypeError,
- "got multiple values "
- "for keyword argument "
- "'%s'", key)
- keywords[i] = key
- keywords_w[i] = space.getitem(w_starstararg, w_key)
- i += 1
- if self.keywords is None:
- self.keywords = keywords
- self.keywords_w = keywords_w
- else:
- self.keywords = self.keywords + keywords
- self.keywords_w = self.keywords_w + keywords_w
+ space.wrap("keywords must be strings"))
+ if self.keywords and key in self.keywords:
+ raise operationerrfmt(self.space.w_TypeError,
+ "got multiple values "
+ "for keyword argument "
+ "'%s'", key)
+ keywords[i] = key
+ keywords_w[i] = space.getitem(w_starstararg, w_key)
+ i += 1
+ if self.keywords is None:
+ self.keywords = keywords
+ self.keywords_w = keywords_w
+ else:
+ 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,
@@ -226,6 +233,10 @@
# argnames = list of formal parameter names
# scope_w = resulting list of wrapped values
#
+
+ # some comments about the JIT: it assumes that signature is a constant,
+ # so all values coming from there can be assumed constant. It assumes
+ # that the length of the defaults_w does not vary too much.
co_argcount = signature.num_argnames() # expected formal arguments, without */**
has_vararg = signature.has_vararg()
has_kwarg = signature.has_kwarg()
@@ -245,12 +256,6 @@
args_w = self.arguments_w
num_args = len(args_w)
- keywords = self.keywords
- keywords_w = self.keywords_w
- num_kwds = 0
- if keywords is not None:
- num_kwds = len(keywords)
-
avail = num_args + upfront
if input_argcount < co_argcount:
@@ -260,15 +265,24 @@
else:
take = num_args
+ # letting the JIT unroll this loop is safe, because take is always
+ # smaller than co_argcount
for i in range(take):
scope_w[i + input_argcount] = args_w[i]
input_argcount += take
+ keywords = self.keywords
+ keywords_w = self.keywords_w
+ num_kwds = 0
+ if keywords is not None:
+ num_kwds = len(keywords)
# the code assumes that keywords can potentially be large, but that
# argnames is typically not too large
num_remainingkwds = num_kwds
used_keywords = None
if keywords:
+ # letting JIT unroll the loop is *only* safe if the callsite didn't
+ # use **args because num_kwds can be arbitrarily large otherwise.
used_keywords = [False] * num_kwds
for i in range(num_kwds):
name = keywords[i]
@@ -276,7 +290,7 @@
if j < 0:
continue
elif j < input_argcount:
- # check that no keyword argument conflicts with these note
+ # check that no keyword argument conflicts with these. note
# that for this purpose we ignore the first blindargs,
# which were put into place by prepend(). This way,
# keywords do not conflict with the hidden extra argument
Modified: pypy/trunk/pypy/interpreter/test/test_argument.py
==============================================================================
--- pypy/trunk/pypy/interpreter/test/test_argument.py (original)
+++ pypy/trunk/pypy/interpreter/test/test_argument.py Wed Nov 17 10:44:46 2010
@@ -52,12 +52,17 @@
assert y == "d"
assert z == "e"
+class dummy_wrapped_dict(dict):
+ def __nonzero__(self):
+ raise NotImplementedError
class DummySpace(object):
def newtuple(self, items):
return tuple(items)
def is_true(self, obj):
+ if isinstance(obj, dummy_wrapped_dict):
+ return bool(dict(obj))
return bool(obj)
def fixedview(self, it):
@@ -229,7 +234,7 @@
kwds_w = dict(kwds[:i])
keywords = kwds_w.keys()
keywords_w = kwds_w.values()
- w_kwds = dict(kwds[i:])
+ w_kwds = dummy_wrapped_dict(kwds[i:])
if i == 2:
w_kwds = None
assert len(keywords) == len(keywords_w)
@@ -265,7 +270,7 @@
kwds_w = dict(kwds[:i])
keywords = kwds_w.keys()
keywords_w = kwds_w.values()
- w_kwds = dict(kwds[i:])
+ w_kwds = dummy_wrapped_dict(kwds[i:])
if i == 3:
w_kwds = None
args = Arguments(space, [1, 2], keywords, keywords_w, w_starstararg=w_kwds)
Modified: pypy/trunk/pypy/module/array/interp_array.py
==============================================================================
--- pypy/trunk/pypy/module/array/interp_array.py (original)
+++ pypy/trunk/pypy/module/array/interp_array.py Wed Nov 17 10:44:46 2010
@@ -27,7 +27,7 @@
typecode = typecode[0]
if space.is_w(w_cls, space.gettypeobject(W_ArrayBase.typedef)):
- if len(w_args.keywords_w) > 0:
+ if w_args.keywords: # XXX this might be forbidden fishing
msg = 'array.array() does not take keyword arguments'
raise OperationError(space.w_TypeError, space.wrap(msg))
Modified: pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py (original)
+++ pypy/trunk/pypy/module/pypyjit/test/test_pypy_c.py Wed Nov 17 10:44:46 2010
@@ -377,10 +377,75 @@
([1000], 49500),
([10000], 495000),
([100000], 4950000))
- assert len(self.loops) == 2
+ assert len(self.loops) == 3
op, = self.get_by_bytecode("CALL_FUNCTION_KW")
# XXX a bit too many guards, but better than before
- assert len(op.get_opnames("guard")) <= 10
+ assert len(op.get_opnames("guard")) <= 12
+
+ def test_stararg_virtual(self):
+ self.run_source('''
+ d = {}
+
+ def g(*args):
+ return len(args)
+ def h(a, b, c):
+ return c
+
+ def main(x):
+ s = 0
+ for i in range(x):
+ l = [i, x, 2]
+ s += g(*l)
+ s += h(*l)
+ s += g(i, x, 2)
+ for i in range(x):
+ l = [x, 2]
+ s += g(i, *l)
+ s += h(i, *l)
+ return s
+ ''', 100000, ([100], 1300),
+ ([1000], 13000),
+ ([10000], 130000),
+ ([100000], 1300000))
+ assert len(self.loops) == 2
+ ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
+ assert len(ops) == 4
+ for op in ops:
+ assert len(op.get_opnames("new")) == 0
+ assert len(op.get_opnames("call_may_force")) == 0
+
+ ops = self.get_by_bytecode("CALL_FUNCTION")
+ for op in ops:
+ assert len(op.get_opnames("new")) == 0
+ assert len(op.get_opnames("call_may_force")) == 0
+
+ def test_stararg(self):
+ self.run_source('''
+ d = {}
+
+ def g(*args):
+ return args[-1]
+ def h(*args):
+ return len(args)
+
+ def main(x):
+ s = 0
+ l = []
+ i = 0
+ while i < x:
+ l.append(1)
+ s += g(*l)
+ i = h(*l)
+ return s
+ ''', 100000, ([100], 100),
+ ([1000], 1000),
+ ([2000], 2000),
+ ([4000], 4000))
+ assert len(self.loops) == 1
+ ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
+ for op in ops:
+ assert len(op.get_opnames("new_with_vtable")) == 0
+ assert len(op.get_opnames("call_may_force")) == 0
def test_virtual_instance(self):
self.run_source('''
More information about the Pypy-commit
mailing list