[pypy-svn] r50252 - in pypy/branch/astcompilertests/pypy/interpreter/astcompiler: . test
arigo at codespeak.net
arigo at codespeak.net
Wed Jan 2 11:53:13 CET 2008
Author: arigo
Date: Wed Jan 2 11:53:12 2008
New Revision: 50252
Modified:
pypy/branch/astcompilertests/pypy/interpreter/astcompiler/pycodegen.py
pypy/branch/astcompilertests/pypy/interpreter/astcompiler/test/test_compiler.py
Log:
Avoids the intermediate tuple during tuple assignment in some common cases.
Modified: pypy/branch/astcompilertests/pypy/interpreter/astcompiler/pycodegen.py
==============================================================================
--- pypy/branch/astcompilertests/pypy/interpreter/astcompiler/pycodegen.py (original)
+++ pypy/branch/astcompilertests/pypy/interpreter/astcompiler/pycodegen.py Wed Jan 2 11:53:12 2008
@@ -5,7 +5,7 @@
import sys
from pypy.interpreter.astcompiler import ast
-from pypy.interpreter.astcompiler import pyassem, misc, future, symbols
+from pypy.interpreter.astcompiler import pyassem, misc, future, symbols, opt
from pypy.interpreter.astcompiler.consts import SC_LOCAL, SC_GLOBAL, \
SC_FREE, SC_CELL, SC_DEFAULT, OP_APPLY, OP_ASSIGN, OP_DELETE, OP_NONE
from pypy.interpreter.astcompiler.consts import CO_VARARGS, CO_VARKEYWORDS, \
@@ -14,6 +14,7 @@
from pypy.interpreter.pyparser.error import SyntaxError
from pypy.interpreter.astcompiler.opt import is_constant_false
from pypy.interpreter.astcompiler.opt import is_constant_true
+from pypy.interpreter.error import OperationError
# drop VERSION dependency since it the ast transformer for 2.4 doesn't work with 2.3 anyway
VERSION = 2
@@ -921,14 +922,82 @@
def visitAssign(self, node):
self.set_lineno(node)
+ if opt.OPTIMIZE and self._visitTupleAssignment(node):
+ return
node.expr.accept( self )
dups = len(node.nodes) - 1
for i in range(len(node.nodes)):
elt = node.nodes[i]
if i < dups:
self.emit('DUP_TOP')
- if isinstance(elt, ast.Node):
- elt.accept( self )
+ assert isinstance(elt, ast.Node)
+ elt.accept( self )
+
+ def _visitTupleAssignment(self, parentnode):
+ # look for the assignment pattern (...) = (...)
+ space = self.space
+ expr = parentnode.expr
+ if isinstance(expr, ast.Tuple):
+ srcnodes = expr.nodes
+ elif isinstance(expr, ast.List):
+ srcnodes = expr.nodes
+ elif isinstance(expr, ast.Const):
+ try:
+ values_w = space.unpackiterable(expr.value)
+ except OperationError:
+ return False
+ srcnodes = [ast.Const(w) for w in values_w]
+ else:
+ return False
+ if len(parentnode.nodes) != 1:
+ return False
+ target = parentnode.nodes[0]
+ if not isinstance(target, ast.AssSeq):
+ return False
+ targetnodes = target.nodes
+ if len(targetnodes) != len(srcnodes):
+ return False
+ # we can only optimize two (common) particular cases, because
+ # the order of evaluation of the expression *and* the order
+ # of assignment should both be kept, in principle.
+ # 1. if all targetnodes are simple names, the assignment order
+ # *should* not really matter.
+ # 2. otherwise, if the tuple is of length <= 3, we can emit simple
+ # bytecodes to reverse the items in the value stack.
+ for node in targetnodes:
+ if not isinstance(node, ast.AssName):
+ break # not a simple name
+ else:
+ # all simple names, case 1.
+ for node in srcnodes:
+ node.accept(self)
+ # let's be careful about the same name appearing several times
+ seen = {}
+ for i in range(len(targetnodes)-1, -1, -1):
+ node = targetnodes[i]
+ assert isinstance(node, ast.AssName)
+ if node.name not in seen:
+ seen[node.name] = True
+ self.storeName(node.name, node.lineno)
+ else:
+ self.emit('POP_TOP')
+ return True # done
+
+ n = len(srcnodes)
+ if n > 3:
+ return False # can't do it
+ else:
+ # case 2.
+ for node in srcnodes:
+ node.accept(self)
+ if n == 2:
+ self.emit('ROT_TWO')
+ elif n == 3:
+ self.emit('ROT_THREE')
+ self.emit('ROT_TWO')
+ for node in targetnodes:
+ node.accept(self)
+ return True # done
def visitAssName(self, node):
if node.flags == OP_ASSIGN:
Modified: pypy/branch/astcompilertests/pypy/interpreter/astcompiler/test/test_compiler.py
==============================================================================
--- pypy/branch/astcompilertests/pypy/interpreter/astcompiler/test/test_compiler.py (original)
+++ pypy/branch/astcompilertests/pypy/interpreter/astcompiler/test/test_compiler.py Wed Jan 2 11:53:12 2008
@@ -33,6 +33,7 @@
source = str(py.code.Source(source))
space = self.space
code = compile_with_astcompiler(source, 'exec', space)
+ print
code.dump()
w_dict = space.newdict()
code.exec_code(space, w_dict, w_dict)
@@ -78,6 +79,32 @@
yield self.simple_test, "[x,y,z,t] = [1,2,3,4]", "x,y,z,t", (1, 2, 3,4)
yield self.simple_test, "[x,y,x,t] = 1,2,3,4", "x,y,t", (3, 2, 4)
+ def test_tuple_assign_order(self):
+ decl = py.code.Source("""
+ class A:
+ def __getattr__(self, name):
+ global seen
+ seen += name
+ return name
+ def __setattr__(self, name, value):
+ global seen
+ seen += '%s=%s' % (name, value)
+ seen = ''
+ a = A()
+ """)
+ decl = str(decl) + '\n'
+ yield self.st, decl+"a.x,= a.a,", 'seen', 'ax=a'
+ yield self.st, decl+"a.x,a.y = a.a,a.b", 'seen', 'abx=ay=b'
+ yield self.st, decl+"a.x,a.y,a.z = a.a,a.b,a.c", 'seen', 'abcx=ay=bz=c'
+ yield self.st, decl+"a.x,a.y,a.x,a.t = a.a,a.b,a.c,a.d", 'seen', \
+ 'abcdx=ay=bx=ct=d'
+ yield self.st, decl+"[a.x] = [a.a]", 'seen', 'ax=a'
+ yield self.st, decl+"[a.x,a.y] = a.a,a.b", 'seen', 'abx=ay=b'
+ yield self.st, decl+"[a.x,a.y,a.z] = [a.a,a.b,a.c]", 'seen', \
+ 'abcx=ay=bz=c'
+ yield self.st, decl+"[a.x,a.y,a.x,a.t] = a.a,a.b,a.c,a.d", 'seen', \
+ 'abcdx=ay=bx=ct=d'
+
def test_binary_operator(self):
for operator in ['+', '-', '*', '**', '/', '&', '|', '^', '//',
'<<', '>>', 'and', 'or', '<', '>', '<=', '>=',
More information about the Pypy-commit
mailing list