From: Kumar Aditya Date: Wed, 8 Apr 2026 15:23:20 +0000 (+0530) Subject: gh-148210: fix incorrect `_BINARY_OP_SUBSCR_DICT` JIT optimization (GH-148213) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6e081614eb7b7e93d3ddcdd1c34abe551e9c6550;p=thirdparty%2FPython%2Fcpython.git gh-148210: fix incorrect `_BINARY_OP_SUBSCR_DICT` JIT optimization (GH-148213) --- diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index b25c3c4c4e70..f89f0d8bc4ee 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2340,6 +2340,21 @@ class TestUopsOptimization(unittest.TestCase): self.assertIn("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH", uops) self.assertNotIn("_BINARY_OP_SUBSCR_DICT", uops) + + def test_binary_op_subscr_constant_frozendict_known_hash(self): + def testfunc(n): + x = 0 + for _ in range(n): + x += FROZEN_DICT_CONST['x'] + return x + + res, ex = self._run_with_optimizer(testfunc, 2 * TIER2_THRESHOLD) + self.assertEqual(res, 2 * TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_BINARY_OP_SUBSCR_DICT_KNOWN_HASH", uops) + self.assertNotIn("_BINARY_OP_SUBSCR_DICT", uops) + def test_store_subscr_dict_known_hash(self): # str, int, bytes, float, complex, tuple and any python object which has generic hash def testfunc(n): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index f0abdc098dd8..3ba404b81ea0 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -515,18 +515,18 @@ dummy_func(void) { } op(_BINARY_OP_SUBSCR_DICT, (dict_st, sub_st -- res, ds, ss)) { - PyObject *sub = sym_get_const(ctx, sub_st); - if (sub != NULL) { - optimize_dict_known_hash(ctx, dependencies, this_instr, - sub, _BINARY_OP_SUBSCR_DICT_KNOWN_HASH); - } res = sym_new_not_null(ctx); ds = dict_st; ss = sub_st; + PyObject *sub = sym_get_const(ctx, sub_st); if (sym_is_not_container(sub_st) && sym_matches_type(dict_st, &PyFrozenDict_Type)) { REPLACE_OPCODE_IF_EVALUATES_PURE(dict_st, sub_st, res); } + else if (sub != NULL) { + optimize_dict_known_hash(ctx, dependencies, this_instr, + sub, _BINARY_OP_SUBSCR_DICT_KNOWN_HASH); + } } op(_BINARY_OP_SUBSCR_LIST_SLICE, (list_st, sub_st -- res, ls, ss)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 6f9b0e6a4d03..2c8a0bff13ce 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1463,14 +1463,10 @@ JitOptRef ss; sub_st = stack_pointer[-1]; dict_st = stack_pointer[-2]; - PyObject *sub = sym_get_const(ctx, sub_st); - if (sub != NULL) { - optimize_dict_known_hash(ctx, dependencies, this_instr, - sub, _BINARY_OP_SUBSCR_DICT_KNOWN_HASH); - } res = sym_new_not_null(ctx); ds = dict_st; ss = sub_st; + PyObject *sub = sym_get_const(ctx, sub_st); if (sym_is_not_container(sub_st) && sym_matches_type(dict_st, &PyFrozenDict_Type)) { if ( @@ -1520,6 +1516,10 @@ break; } } + else if (sub != NULL) { + optimize_dict_known_hash(ctx, dependencies, this_instr, + sub, _BINARY_OP_SUBSCR_DICT_KNOWN_HASH); + } CHECK_STACK_BOUNDS(1); stack_pointer[-2] = res; stack_pointer[-1] = ds;