mirror of
https://github.com/python/cpython
synced 2024-09-20 08:38:37 +00:00
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:
commit
5c8008e59d
|
@ -1,3 +1,4 @@
|
||||||
|
import math
|
||||||
import unittest
|
import unittest
|
||||||
import sys
|
import sys
|
||||||
import _ast
|
import _ast
|
||||||
|
@ -501,8 +502,43 @@ def check_limit(prefix, repeated):
|
||||||
check_limit("a", "*a")
|
check_limit("a", "*a")
|
||||||
|
|
||||||
|
|
||||||
def test_main():
|
class TestStackSize(unittest.TestCase):
|
||||||
support.run_unittest(TestSpecifics)
|
# 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__":
|
if __name__ == "__main__":
|
||||||
test_main()
|
unittest.main()
|
||||||
|
|
|
@ -10,6 +10,11 @@ Release date: TBA
|
||||||
Core and Builtins
|
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.
|
||||||
|
|
||||||
- Issue #21418: Fix a crash in the builtin function super() when called without
|
- Issue #21418: Fix a crash in the builtin function super() when called without
|
||||||
argument and without current frame (ex: embedded Python).
|
argument and without current frame (ex: embedded Python).
|
||||||
|
|
||||||
|
|
|
@ -3862,12 +3862,16 @@ stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth)
|
||||||
target_depth = depth;
|
target_depth = depth;
|
||||||
if (instr->i_opcode == FOR_ITER) {
|
if (instr->i_opcode == FOR_ITER) {
|
||||||
target_depth = depth-2;
|
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;
|
target_depth = depth+3;
|
||||||
if (target_depth > maxdepth)
|
if (target_depth > maxdepth)
|
||||||
maxdepth = target_depth;
|
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,
|
maxdepth = stackdepth_walk(c, instr->i_target,
|
||||||
target_depth, maxdepth);
|
target_depth, maxdepth);
|
||||||
if (instr->i_opcode == JUMP_ABSOLUTE ||
|
if (instr->i_opcode == JUMP_ABSOLUTE ||
|
||||||
|
|
Loading…
Reference in a new issue