diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-08-27 21:02:51 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-08-27 21:02:51 (GMT) |
commit | 7e30c9bb5a6a44829d1df01354523f5c3467583d (patch) | |
tree | 1e292a0ddc847287e282e09f941f2bf8c5ca75c0 | |
parent | 058a5adad02f5ae4652d1cd1d0e5ad4ece04fa85 (diff) | |
download | cpython-7e30c9bb5a6a44829d1df01354523f5c3467583d.zip cpython-7e30c9bb5a6a44829d1df01354523f5c3467583d.tar.gz cpython-7e30c9bb5a6a44829d1df01354523f5c3467583d.tar.bz2 |
Add lookup_name() to optimize use of stack frames
The use of com_node() introduces a lot of extra stack frames, enough
to cause a stack overflow compiling test.test_parser with the standard
interpreter recursionlimit. The com_node() is a convenience function
that hides the dispatch details, but comes at a very high cost. It is
more efficient to dispatch directly in the callers. In these cases,
use lookup_node() and call the dispatched node directly.
Also handle yield_stmt in a way that will work with Python 2.1
(suggested by Shane Hathaway)
-rw-r--r-- | Lib/compiler/transformer.py | 26 | ||||
-rw-r--r-- | Tools/compiler/compiler/transformer.py | 26 |
2 files changed, 42 insertions, 10 deletions
diff --git a/Lib/compiler/transformer.py b/Lib/compiler/transformer.py index ebb3481..7f6a1b4 100644 --- a/Lib/compiler/transformer.py +++ b/Lib/compiler/transformer.py @@ -274,7 +274,8 @@ class Transformer: def expr_stmt(self, nodelist): # augassign testlist | testlist ('=' testlist)* - exprNode = self.com_node(nodelist[-1]) + en = nodelist[-1] + exprNode = self.lookup_node(en)(en[1:]) if len(nodelist) == 1: n = Discard(exprNode) n.lineno = exprNode.lineno @@ -696,6 +697,17 @@ class Transformer: # INTERNAL PARSING UTILITIES # + # The use of com_node() introduces a lot of extra stack frames, + # enough to cause a stack overflow compiling test.test_parser with + # the standard interpreter recursionlimit. The com_node() is a + # convenience function that hides the dispatch details, but comes + # at a very high cost. It is more efficient to dispatch directly + # in the callers. In these cases, use lookup_node() and call the + # dispatched node directly. + + def lookup_node(self, node): + return self._dispatch[node[0]] + def com_node(self, node): # Note: compile.c has handling in com_node for del_stmt, pass_stmt, # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt, @@ -938,14 +950,16 @@ class Transformer: "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])." l = len(nodelist) if l == 1: - return self.com_node(nodelist[0]) + n = nodelist[0] + return self.lookup_node(n)(n[1:]) items = [] for i in range(0, l, 2): - items.append(self.com_node(nodelist[i])) + n = nodelist[i] + items.append(self.lookup_node(n)(n[1:])) return constructor(items) def com_stmt(self, node): - result = self.com_node(node) + result = self.lookup_node(node)(node[1:]) assert result is not None if isinstance(result, Stmt): return result @@ -1254,7 +1268,6 @@ _legal_node_types = [ symbol.continue_stmt, symbol.return_stmt, symbol.raise_stmt, - symbol.yield_stmt, symbol.import_stmt, symbol.global_stmt, symbol.exec_stmt, @@ -1281,6 +1294,9 @@ _legal_node_types = [ symbol.atom, ] +if hasattr(symbol, 'yield_stmt'): + _legal_node_types.append(symbol.yield_stmt) + _assign_types = [ symbol.test, symbol.and_test, diff --git a/Tools/compiler/compiler/transformer.py b/Tools/compiler/compiler/transformer.py index ebb3481..7f6a1b4 100644 --- a/Tools/compiler/compiler/transformer.py +++ b/Tools/compiler/compiler/transformer.py @@ -274,7 +274,8 @@ class Transformer: def expr_stmt(self, nodelist): # augassign testlist | testlist ('=' testlist)* - exprNode = self.com_node(nodelist[-1]) + en = nodelist[-1] + exprNode = self.lookup_node(en)(en[1:]) if len(nodelist) == 1: n = Discard(exprNode) n.lineno = exprNode.lineno @@ -696,6 +697,17 @@ class Transformer: # INTERNAL PARSING UTILITIES # + # The use of com_node() introduces a lot of extra stack frames, + # enough to cause a stack overflow compiling test.test_parser with + # the standard interpreter recursionlimit. The com_node() is a + # convenience function that hides the dispatch details, but comes + # at a very high cost. It is more efficient to dispatch directly + # in the callers. In these cases, use lookup_node() and call the + # dispatched node directly. + + def lookup_node(self, node): + return self._dispatch[node[0]] + def com_node(self, node): # Note: compile.c has handling in com_node for del_stmt, pass_stmt, # break_stmt, stmt, small_stmt, flow_stmt, simple_stmt, @@ -938,14 +950,16 @@ class Transformer: "Compile 'NODE (OP NODE)*' into (type, [ node1, ..., nodeN ])." l = len(nodelist) if l == 1: - return self.com_node(nodelist[0]) + n = nodelist[0] + return self.lookup_node(n)(n[1:]) items = [] for i in range(0, l, 2): - items.append(self.com_node(nodelist[i])) + n = nodelist[i] + items.append(self.lookup_node(n)(n[1:])) return constructor(items) def com_stmt(self, node): - result = self.com_node(node) + result = self.lookup_node(node)(node[1:]) assert result is not None if isinstance(result, Stmt): return result @@ -1254,7 +1268,6 @@ _legal_node_types = [ symbol.continue_stmt, symbol.return_stmt, symbol.raise_stmt, - symbol.yield_stmt, symbol.import_stmt, symbol.global_stmt, symbol.exec_stmt, @@ -1281,6 +1294,9 @@ _legal_node_types = [ symbol.atom, ] +if hasattr(symbol, 'yield_stmt'): + _legal_node_types.append(symbol.yield_stmt) + _assign_types = [ symbol.test, symbol.and_test, |