diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index a379d1be2f9bd3..437cc340fc90e3 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1022,7 +1022,6 @@ def return_hello(): # Constant narrowing allows constant folding for second comparison self.assertLessEqual(count_ops(ex, "_COMPARE_OP_STR"), 1) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_sequential(self): def dummy12(x): return x - 1 @@ -1046,12 +1045,14 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) self.assertEqual(uop_names.count("_RETURN_VALUE"), 2) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # sequential calls: max(12, 13) == 13 - largest_stack = _testinternalcapi.get_co_framesize(dummy13.__code__) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + # Each call gets its own _CHECK_STACK_SPACE_OPERAND + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 2) + # Each _CHECK_STACK_SPACE_OPERAND has the framesize of its function + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy13.__code__)), uops_and_operands) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_nested(self): def dummy12(x): return x + 3 @@ -1074,15 +1075,12 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 2) self.assertEqual(uop_names.count("_RETURN_VALUE"), 2) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # nested calls: 15 + 12 == 27 - largest_stack = ( - _testinternalcapi.get_co_framesize(dummy15.__code__) + - _testinternalcapi.get_co_framesize(dummy12.__code__) - ) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 2) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy15.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_several_calls(self): def dummy12(x): return x + 3 @@ -1110,15 +1108,14 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 4) self.assertEqual(uop_names.count("_RETURN_VALUE"), 4) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # max(12, 18 + max(12, 13)) == 31 - largest_stack = ( - _testinternalcapi.get_co_framesize(dummy18.__code__) + - _testinternalcapi.get_co_framesize(dummy13.__code__) - ) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 4) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy13.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy18.__code__)), uops_and_operands) - @unittest.skip("gh-139109 WIP") def test_combine_stack_space_checks_several_calls_different_order(self): # same as `several_calls` but with top-level calls reversed def dummy12(x): @@ -1147,15 +1144,15 @@ def testfunc(n): self.assertEqual(uop_names.count("_PUSH_FRAME"), 4) self.assertEqual(uop_names.count("_RETURN_VALUE"), 4) self.assertEqual(uop_names.count("_CHECK_STACK_SPACE"), 0) - self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 1) - # max(18 + max(12, 13), 12) == 31 - largest_stack = ( - _testinternalcapi.get_co_framesize(dummy18.__code__) + - _testinternalcapi.get_co_framesize(dummy13.__code__) - ) - self.assertIn(("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands) - - @unittest.skip("gh-139109 WIP") + self.assertEqual(uop_names.count("_CHECK_STACK_SPACE_OPERAND"), 4) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy12.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy13.__code__)), uops_and_operands) + self.assertIn(("_CHECK_STACK_SPACE_OPERAND", + _testinternalcapi.get_co_framesize(dummy18.__code__)), uops_and_operands) + + @unittest.skip("reopen when we combine multiple stack space checks into one") def test_combine_stack_space_complex(self): def dummy0(x): return x @@ -1205,7 +1202,7 @@ def testfunc(n): ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands ) - @unittest.skip("gh-139109 WIP") + @unittest.skip("reopen when we combine multiple stack space checks into one") def test_combine_stack_space_checks_large_framesize(self): # Create a function with a large framesize. This ensures _CHECK_STACK_SPACE is # actually doing its job. Note that the resulting trace hits @@ -1267,7 +1264,7 @@ def testfunc(n): ("_CHECK_STACK_SPACE_OPERAND", largest_stack), uops_and_operands ) - @unittest.skip("gh-139109 WIP") + @unittest.skip("reopen when we combine multiple stack space checks into one") def test_combine_stack_space_checks_recursion(self): def dummy15(x): while x > 0: diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 8bc58240e908a7..e12f7961fd7a9a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -5362,7 +5362,6 @@ dummy_func( tier2 op(_CHECK_STACK_SPACE_OPERAND, (framesize/2 --)) { assert(framesize <= INT_MAX); DEOPT_IF(!_PyThreadState_HasStackSpace(tstate, framesize)); - DEOPT_IF(tstate->py_recursion_remaining <= 1); } op(_SAVE_RETURN_OFFSET, (--)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1a705098472425..4c715841aa29c3 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -18557,11 +18557,6 @@ SET_CURRENT_CACHED_VALUES(0); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - SET_CURRENT_CACHED_VALUES(0); - JUMP_TO_JUMP_TARGET(); - } SET_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; @@ -18579,12 +18574,6 @@ SET_CURRENT_CACHED_VALUES(1); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(1); - JUMP_TO_JUMP_TARGET(); - } _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(1); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); @@ -18605,13 +18594,6 @@ SET_CURRENT_CACHED_VALUES(2); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - _tos_cache1 = _stack_item_1; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(2); - JUMP_TO_JUMP_TARGET(); - } _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; SET_CURRENT_CACHED_VALUES(2); @@ -18635,14 +18617,6 @@ SET_CURRENT_CACHED_VALUES(3); JUMP_TO_JUMP_TARGET(); } - if (tstate->py_recursion_remaining <= 1) { - UOP_STAT_INC(uopcode, miss); - _tos_cache2 = _stack_item_2; - _tos_cache1 = _stack_item_1; - _tos_cache0 = _stack_item_0; - SET_CURRENT_CACHED_VALUES(3); - JUMP_TO_JUMP_TARGET(); - } _tos_cache2 = _stack_item_2; _tos_cache1 = _stack_item_1; _tos_cache0 = _stack_item_0; diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 4ccecd472b36da..d6dca78b2e84a9 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1088,13 +1088,17 @@ dummy_func(void) { } op(_CHECK_STACK_SPACE, (unused, unused, unused[oparg] -- unused, unused, unused[oparg])) { + assert((this_instr + 4)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 4)); + if (co == NULL) { + ctx->done = true; + break; + } + ADD_OP(_CHECK_STACK_SPACE_OPERAND, 0, co->co_framesize); } op (_CHECK_STACK_SPACE_OPERAND, (framesize/2 -- )) { (void)framesize; - /* We should never see _CHECK_STACK_SPACE_OPERANDs. - * They are only created at the end of this pass. */ - Py_UNREACHABLE(); } op(_PUSH_FRAME, (new_frame -- )) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 4a6f2450680bf9..70055ba50be844 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3031,6 +3031,13 @@ } case _CHECK_STACK_SPACE: { + assert((this_instr + 4)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging((this_instr + 4)); + if (co == NULL) { + ctx->done = true; + break; + } + ADD_OP(_CHECK_STACK_SPACE_OPERAND, 0, co->co_framesize); break; } @@ -3938,7 +3945,6 @@ case _CHECK_STACK_SPACE_OPERAND: { uint32_t framesize = (uint32_t)this_instr->operand0; (void)framesize; - Py_UNREACHABLE(); break; }