[pypy-svn] r76412 - in pypy/trunk: . pypy/interpreter/astcompiler pypy/interpreter/test pypy/objspace/std pypy/objspace/std/test
agaynor at codespeak.net
agaynor at codespeak.net
Fri Jul 30 22:12:02 CEST 2010
Author: agaynor
Date: Fri Jul 30 22:12:00 2010
New Revision: 76412
Modified:
pypy/trunk/ (props changed)
pypy/trunk/pypy/interpreter/astcompiler/assemble.py
pypy/trunk/pypy/interpreter/astcompiler/codegen.py
pypy/trunk/pypy/interpreter/test/test_compiler.py
pypy/trunk/pypy/objspace/std/callmethod.py
pypy/trunk/pypy/objspace/std/test/test_callmethod.py
Log:
Merged call-method-kwarg into trunk. The optimized CALL_METHOD opcode is now used for calls with keyword arguments.
Modified: pypy/trunk/pypy/interpreter/astcompiler/assemble.py
==============================================================================
--- pypy/trunk/pypy/interpreter/astcompiler/assemble.py (original)
+++ pypy/trunk/pypy/interpreter/astcompiler/assemble.py Fri Jul 30 22:12:00 2010
@@ -581,7 +581,7 @@
return -(arg & 0xFF) + 1
def _compute_CALL_METHOD(arg):
- return -arg - 1
+ return _num_args(arg) - 1
_stack_effect_computers = {}
Modified: pypy/trunk/pypy/interpreter/astcompiler/codegen.py
==============================================================================
--- pypy/trunk/pypy/interpreter/astcompiler/codegen.py (original)
+++ pypy/trunk/pypy/interpreter/astcompiler/codegen.py Fri Jul 30 22:12:00 2010
@@ -960,9 +960,12 @@
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
def _call_has_simple_args(self, call):
- return not call.starargs and not call.kwargs and not call.keywords
+ return self._call_has_no_star_args(call) and not call.keywords
def _optimize_builtin_call(self, call):
if not self.space.config.objspace.opcodes.CALL_LIKELY_BUILTIN or \
@@ -988,7 +991,7 @@
def _optimize_method_call(self, call):
if not self.space.config.objspace.opcodes.CALL_METHOD or \
- not self._call_has_simple_args(call) or \
+ not self._call_has_no_star_args(call) or \
not isinstance(call.func, ast.Attribute):
return False
attr_lookup = call.func
@@ -1000,7 +1003,12 @@
arg_count = len(call.args)
else:
arg_count = 0
- self.emit_op_arg(ops.CALL_METHOD, arg_count)
+ if call.keywords:
+ self.visit_sequence(call.keywords)
+ kwarg_count = len(call.keywords)
+ else:
+ kwarg_count = 0
+ self.emit_op_arg(ops.CALL_METHOD, (kwarg_count << 8) | arg_count)
return True
def _listcomp_generator(self, list_name, gens, gen_index, elt):
Modified: pypy/trunk/pypy/interpreter/test/test_compiler.py
==============================================================================
--- pypy/trunk/pypy/interpreter/test/test_compiler.py (original)
+++ pypy/trunk/pypy/interpreter/test/test_compiler.py Fri Jul 30 22:12:00 2010
@@ -4,6 +4,7 @@
from pypy.interpreter.pycode import PyCode
from pypy.interpreter.error import OperationError
from pypy.interpreter.argument import Arguments
+from pypy.conftest import gettestobjspace
class BaseTestCompiler:
def setup_method(self, method):
@@ -848,14 +849,38 @@
import StringIO, sys, dis
s = StringIO.StringIO()
+ out = sys.stdout
sys.stdout = s
try:
dis.dis(code)
finally:
- sys.stdout = sys.__stdout__
+ sys.stdout = out
output = s.getvalue()
assert "LOAD_GLOBAL" not in output
+class AppTestCallMethod(object):
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{'objspace.opcodes.CALL_METHOD': True})
+
+ def test_call_method_kwargs(self):
+ source = """def _f(a):
+ return a.f(a=a)
+ """
+ exec source
+ code = _f.func_code
+
+ import StringIO, sys, dis
+ s = StringIO.StringIO()
+ out = sys.stdout
+ sys.stdout = s
+ try:
+ dis.dis(code)
+ finally:
+ sys.stdout = out
+ output = s.getvalue()
+ assert "CALL_METHOD" in output
+
+
class AppTestExceptions:
def test_indentation_error(self):
source = """if 1:
Modified: pypy/trunk/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/callmethod.py (original)
+++ pypy/trunk/pypy/objspace/std/callmethod.py Fri Jul 30 22:12:00 2010
@@ -56,16 +56,41 @@
f.pushvalue(w_value)
f.pushvalue(None)
-def CALL_METHOD(f, nargs, *ignored):
- # 'nargs' is the argument count excluding the implicit 'self'
- w_self = f.peekvalue(nargs)
- w_callable = f.peekvalue(nargs + 1)
- n = nargs + (w_self is not None)
- try:
- w_result = f.space.call_valuestack(w_callable, n, f)
- rstack.resume_point("CALL_METHOD", f, nargs, returns=w_result)
- finally:
- f.dropvalues(nargs + 2)
+def CALL_METHOD(f, oparg, *ignored):
+ # opargs contains the arg, and kwarg count, excluding the implicit 'self'
+ n_args = oparg & 0xff
+ n_kwargs = (oparg >> 8) & 0xff
+ w_self = f.peekvalue(n_args + (2 * n_kwargs))
+ w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1)
+ n = n_args + (w_self is not None)
+
+ if not n_kwargs:
+ try:
+ w_result = f.space.call_valuestack(w_callable, n, f)
+ rstack.resume_point("CALL_METHOD", f, n_args, returns=w_result)
+ finally:
+ f.dropvalues(n_args + 2)
+ else:
+ keywords = [None] * n_kwargs
+ keywords_w = [None] * n_kwargs
+ while True:
+ n_kwargs -= 1
+ if n_kwargs < 0:
+ break
+ w_value = f.popvalue()
+ w_key = f.popvalue()
+ key = f.space.str_w(w_key)
+ keywords[n_kwargs] = key
+ keywords_w[n_kwargs] = w_value
+
+ arguments = f.popvalues(n)
+ args = f.argument_factory(arguments, keywords, keywords_w, None, None)
+
+ try:
+ w_result = f.space.call_args(w_callable, args)
+ rstack.resume_point("CALL_METHOD", f, returns=w_result)
+ finally:
+ f.dropvalues(1 + (w_self is None))
f.pushvalue(w_result)
Modified: pypy/trunk/pypy/objspace/std/test/test_callmethod.py
==============================================================================
--- pypy/trunk/pypy/objspace/std/test/test_callmethod.py (original)
+++ pypy/trunk/pypy/objspace/std/test/test_callmethod.py Fri Jul 30 22:12:00 2010
@@ -106,6 +106,15 @@
else:
raise Exception("did not raise?")
"""
+
+ def test_kwargs(self):
+ exec """if 1:
+ class C(object):
+ def f(self, a):
+ return a + 2
+
+ assert C().f(a=3) == 5
+ """
class AppTestCallMethodWithGetattributeShortcut(AppTestCallMethod):
More information about the Pypy-commit
mailing list