Issue #21523: Fix over-pessimistic computation of the stack effect of some opcodes in the compiler.

This also fixes a quadratic compilation time issue noticeable when compiling
code with a large number of "and" and "or" operators.
This commit is contained in:
Antoine Pitrou 2014-05-23 11:46:03 +02:00
parent e17de09101
commit 9961405ed1
3 changed files with 59 additions and 5 deletions

View File

@ -1,3 +1,4 @@
import math
import unittest
import sys
import _ast
@ -501,8 +502,43 @@ if 1:
check_limit("a", "*a")
def test_main():
support.run_unittest(TestSpecifics)
class TestStackSize(unittest.TestCase):
# These tests check that the computed stack size for a code object
# stays within reasonable bounds (see issue #21523 for an example
# dysfunction).
N = 100
def check_stack_size(self, code):
# To assert that the alleged stack size is not O(N), we
# check that it is smaller than log(N).
if isinstance(code, str):
code = compile(code, "<foo>", "single")
max_size = math.ceil(math.log(len(code.co_code)))
self.assertLessEqual(code.co_stacksize, max_size)
def test_and(self):
self.check_stack_size("x and " * self.N + "x")
def test_or(self):
self.check_stack_size("x or " * self.N + "x")
def test_and_or(self):
self.check_stack_size("x and x or " * self.N + "x")
def test_chained_comparison(self):
self.check_stack_size("x < " * self.N + "x")
def test_if_else(self):
self.check_stack_size("x if x else " * self.N + "x")
def test_binop(self):
self.check_stack_size("x + " * self.N + "x")
def test_func_and(self):
code = "def f(x):\n"
code += " x and x\n" * self.N
self.check_stack_size(code)
if __name__ == "__main__":
test_main()
unittest.main()

View File

@ -2,6 +2,20 @@
Python News
+++++++++++
What's New in Python 3.4.2?
===========================
Release date: XXXX-XX-XX
Core and Builtins
-----------------
- Issue #21523: Fix over-pessimistic computation of the stack effect of
some opcodes in the compiler. This also fixes a quadratic compilation
time issue noticeable when compiling code with a large number of "and"
and "or" operators.
What's New in Python 3.4.1?
===========================

View File

@ -3856,12 +3856,16 @@ stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth)
target_depth = depth;
if (instr->i_opcode == FOR_ITER) {
target_depth = depth-2;
} else if (instr->i_opcode == SETUP_FINALLY ||
instr->i_opcode == SETUP_EXCEPT) {
}
else if (instr->i_opcode == SETUP_FINALLY ||
instr->i_opcode == SETUP_EXCEPT) {
target_depth = depth+3;
if (target_depth > maxdepth)
maxdepth = target_depth;
}
else if (instr->i_opcode == JUMP_IF_TRUE_OR_POP ||
instr->i_opcode == JUMP_IF_FALSE_OR_POP)
depth = depth - 1;
maxdepth = stackdepth_walk(c, instr->i_target,
target_depth, maxdepth);
if (instr->i_opcode == JUMP_ABSOLUTE ||