diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 62c16fd6cb1db8..9fe27af8eca017 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -3538,6 +3538,44 @@ def testfunc(n): # _POP_TOP_NOP is a sign the optimizer ran and didn't hit bottom. self.assertGreaterEqual(count_ops(ex, "_POP_TOP_NOP"), 1) + def test_binary_op_subscr_init_frame(self): + class B: + def __getitem__(self, other): + return other + 1 + def testfunc(*args): + n, b = args[0] + for _ in range(n): + y = b[2] + + res, ex = self._run_with_optimizer(testfunc, (TIER2_THRESHOLD, B())) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertIn("_BINARY_OP_SUBSCR_INIT_CALL", uops) + # _POP_TOP_NOP is a sign the optimizer ran and didn't hit bottom. + self.assertGreaterEqual(count_ops(ex, "_POP_TOP_NOP"), 1) + + def test_load_attr_property_frame(self): + class B: + @property + def prop(self): + return 3 + def testfunc(*args): + n, b = args[0] + for _ in range(n): + y = b.prop + b.prop + + testfunc((3, B())) + import dis + dis.dis(testfunc, adaptive=True) + res, ex = self._run_with_optimizer(testfunc, (TIER2_THRESHOLD, B())) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + + self.assertIn("_LOAD_ATTR_PROPERTY_FRAME", uops) + # This is a sign the optimizer ran and didn't hit bottom. + self.assertIn("_INSERT_2_LOAD_CONST_INLINE_BORROW", uops) + def test_unary_negative(self): def testfunc(n): a = 3 diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 49fb9e7625aaf2..5e3031c16b0b9e 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -327,9 +327,17 @@ dummy_func(void) { GETLOCAL(this_instr->operand0) = sym_new_null(ctx); } - op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) { - new_frame = PyJitRef_NULL; - ctx->done = true; + op(_BINARY_OP_SUBSCR_INIT_CALL, (container, sub, getitem -- new_frame)) { + assert((this_instr + 1)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging(this_instr + 1); + if (co == NULL) { + ctx->done = true; + break; + } + _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); + f->locals[0] = container; + f->locals[1] = sub; + new_frame = PyJitRef_Wrap((JitOptSymbol *)f); } op(_BINARY_OP_SUBSCR_STR_INT, (str_st, sub_st -- res, s, i)) { @@ -759,9 +767,15 @@ dummy_func(void) { } op(_LOAD_ATTR_PROPERTY_FRAME, (fget/4, owner -- new_frame)) { - (void)fget; - new_frame = PyJitRef_NULL; - ctx->done = true; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging(this_instr + 2); + if (co == NULL) { + ctx->done = true; + break; + } + _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); + f->locals[0] = owner; + new_frame = PyJitRef_Wrap((JitOptSymbol *)f); } op(_INIT_CALL_BOUND_METHOD_EXACT_ARGS, (callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index d522c5a0c19459..4b1e89422ca038 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -1102,9 +1102,21 @@ } case _BINARY_OP_SUBSCR_INIT_CALL: { + JitOptRef sub; + JitOptRef container; JitOptRef new_frame; - new_frame = PyJitRef_NULL; - ctx->done = true; + sub = stack_pointer[-2]; + container = stack_pointer[-3]; + assert((this_instr + 1)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging(this_instr + 1); + if (co == NULL) { + ctx->done = true; + break; + } + _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); + f->locals[0] = container; + f->locals[1] = sub; + new_frame = PyJitRef_Wrap((JitOptSymbol *)f); CHECK_STACK_BOUNDS(-2); stack_pointer[-3] = new_frame; stack_pointer += -2; @@ -1935,11 +1947,19 @@ } case _LOAD_ATTR_PROPERTY_FRAME: { + JitOptRef owner; JitOptRef new_frame; + owner = stack_pointer[-1]; PyObject *fget = (PyObject *)this_instr->operand0; - (void)fget; - new_frame = PyJitRef_NULL; - ctx->done = true; + assert((this_instr + 2)->opcode == _PUSH_FRAME); + PyCodeObject *co = get_code_with_logging(this_instr + 2); + if (co == NULL) { + ctx->done = true; + break; + } + _Py_UOpsAbstractFrame *f = frame_new(ctx, co, 0, NULL, 0); + f->locals[0] = owner; + new_frame = PyJitRef_Wrap((JitOptSymbol *)f); stack_pointer[-1] = new_frame; break; }