changeset: 90796:cd62cc331572 branch: 3.4 parent: 90794:3f2b6034b73a user: Antoine Pitrou date: Fri May 23 11:46:03 2014 +0200 files: Lib/test/test_compile.py Misc/NEWS Python/compile.c description: 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. diff -r 3f2b6034b73a -r cd62cc331572 Lib/test/test_compile.py --- a/Lib/test/test_compile.py Fri May 23 00:34:12 2014 -0400 +++ b/Lib/test/test_compile.py Fri May 23 11:46:03 2014 +0200 @@ -1,3 +1,4 @@ +import math import unittest import sys import _ast @@ -501,8 +502,43 @@ 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, "", "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() diff -r 3f2b6034b73a -r cd62cc331572 Misc/NEWS --- a/Misc/NEWS Fri May 23 00:34:12 2014 -0400 +++ b/Misc/NEWS Fri May 23 11:46:03 2014 +0200 @@ -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? =========================== diff -r 3f2b6034b73a -r cd62cc331572 Python/compile.c --- a/Python/compile.c Fri May 23 00:34:12 2014 -0400 +++ b/Python/compile.c Fri May 23 11:46:03 2014 +0200 @@ -3856,12 +3856,16 @@ 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 ||