diff --git a/Include/internal/pycore_optimizer_types.h b/Include/internal/pycore_optimizer_types.h index c1928ec9ebdac3b..a722652cc8163aa 100644 --- a/Include/internal/pycore_optimizer_types.h +++ b/Include/internal/pycore_optimizer_types.h @@ -140,7 +140,6 @@ typedef union { typedef struct _Py_UOpsAbstractFrame { bool globals_watched; - bool builtins_checked; // The version number of the globals dicts, once checked. 0 if unchecked. uint32_t globals_checked_version; // Max stacklen diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index e84ea680c781b2d..207422cc670330d 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -5106,35 +5106,6 @@ def f(n): # A different function enters the same executor with other builtins. self.assertEqual(f_copied(8), [42] * 8) - def test_builtins_guard_emitted_once_per_frame(self): - # A frame's builtins cannot change once the frame is pushed, so - # repeated builtin loads in one frame share a single guard, just as - # they already share a single _GUARD_GLOBALS_VERSION. - - def warmup(n): - x = 0 - for _ in range(n): - x += len("ab") - return x - - def one_frame(n): - x = 0 - for _ in range(n): - x += len("ab") + abs(-1) + ord("c") - return x - - # The optimizer context is reused for every compilation, so compile an - # unrelated trace first: state that is not reset per frame leaks here. - warmup(TIER2_THRESHOLD) - self.assertIsNotNone(get_first_executor(warmup)) - - _, ex = self._run_with_optimizer(one_frame, TIER2_THRESHOLD) - self.assertIsNotNone(ex) - uop_names = get_opnames(ex) - self.assertNotIn("_LOAD_GLOBAL_BUILTINS", uop_names) # all folded - self.assertEqual(uop_names.count("_GUARD_BUILTINS_IS_CANONICAL"), 1) - self.assertEqual(uop_names.count("_GUARD_GLOBALS_VERSION"), 1) - def test_reference_tracking_across_call_doesnt_crash(self): def f1(): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index a8ad6b38d01307e..5e2c4148a4e1ac3 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1,5 +1,3 @@ -#include - #include "Python.h" #include "pycore_long.h" #include "pycore_opcode_utils.h" @@ -2534,8 +2532,9 @@ dummy_func(void) { uop_buffer_remaining_space(&ctx->out_buffer) >= 2) { cnst = convert_global_to_const(this_instr, builtins); - if (cnst != NULL && !ctx->frame->builtins_checked) { - ctx->frame->builtins_checked = true; + if (cnst != NULL) { + /* convert_global_to_const already chose the right + * _LOAD_CONST_INLINE[_BORROW] opcode; reuse it. */ ADD_OP(_GUARD_BUILTINS_IS_CANONICAL, 0, 0); ADD_OP(this_instr->opcode, 0, (uintptr_t)cnst); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 14e84e94caae944..c0268efa1291095 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2314,8 +2314,7 @@ uop_buffer_remaining_space(&ctx->out_buffer) >= 2) { cnst = convert_global_to_const(this_instr, builtins); - if (cnst != NULL && !ctx->frame->builtins_checked) { - ctx->frame->builtins_checked = true; + if (cnst != NULL) { ADD_OP(_GUARD_BUILTINS_IS_CANONICAL, 0, 0); ADD_OP(this_instr->opcode, 0, (uintptr_t)cnst); } diff --git a/Python/optimizer_symbols.c b/Python/optimizer_symbols.c index 7495c95efccafd0..79f81482d247e37 100644 --- a/Python/optimizer_symbols.c +++ b/Python/optimizer_symbols.c @@ -1378,7 +1378,6 @@ _Py_uop_frame_new( frame->stack_pointer = frame->stack; frame->globals_checked_version = 0; frame->globals_watched = false; - frame->builtins_checked = false; frame->func = NULL; frame->caller = false; frame->is_c_recursion_checked = false;