From a66fc14b24723d2175041fb4e946dd10e1fbf34d Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Thu, 1 Jan 2026 23:27:57 +0900 Subject: [PATCH 1/7] gh-134584: Eliminate redundant refcounting from _CALL_METHOD_DESCRIPTOR_O --- Include/internal/pycore_opcode_metadata.h | 4 +- Include/internal/pycore_uop_ids.h | 2 +- Include/internal/pycore_uop_metadata.h | 8 ++-- Lib/test/test_capi/test_opt.py | 16 +++++++ Python/bytecodes.c | 14 ++++-- Python/executor_cases.c.h | 37 ++++++--------- Python/generated_cases.c.h | 58 +++++++++++++++-------- Python/optimizer_cases.c.h | 13 ++++- 8 files changed, 96 insertions(+), 56 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 424ec337eb8afd..adce512d32941f 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1125,7 +1125,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, - [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, [CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG }, @@ -1371,7 +1371,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_O, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_METHOD_DESCRIPTOR_O] = { .nuops = 5, .uops = { { _CALL_METHOD_DESCRIPTOR_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, OPARG_SIMPLE, 3 }, { _CALL_NON_PY_GENERAL, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_PY_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_PY_GENERAL] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, diff --git a/Include/internal/pycore_uop_ids.h b/Include/internal/pycore_uop_ids.h index ebeec6387a741a..a7da996a99ae2d 100644 --- a/Include/internal/pycore_uop_ids.h +++ b/Include/internal/pycore_uop_ids.h @@ -422,7 +422,7 @@ extern "C" { #define _CALL_METHOD_DESCRIPTOR_FAST_r01 616 #define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 617 #define _CALL_METHOD_DESCRIPTOR_NOARGS_r01 618 -#define _CALL_METHOD_DESCRIPTOR_O_r01 619 +#define _CALL_METHOD_DESCRIPTOR_O_r03 619 #define _CALL_NON_PY_GENERAL_r01 620 #define _CALL_STR_1_r32 621 #define _CALL_TUPLE_1_r32 622 diff --git a/Include/internal/pycore_uop_metadata.h b/Include/internal/pycore_uop_metadata.h index 1838dd3f0977b2..8c65565890b557 100644 --- a/Include/internal/pycore_uop_metadata.h +++ b/Include/internal/pycore_uop_metadata.h @@ -288,7 +288,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = { [_CALL_ISINSTANCE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_GUARD_CALLABLE_LIST_APPEND] = HAS_DEOPT_FLAG, [_CALL_LIST_APPEND] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG, - [_CALL_METHOD_DESCRIPTOR_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, + [_CALL_METHOD_DESCRIPTOR_O] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_NOARGS] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, [_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, @@ -2648,7 +2648,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = { [_CALL_METHOD_DESCRIPTOR_O] = { .best = { 0, 0, 0, 0 }, .entries = { - { 1, 0, _CALL_METHOD_DESCRIPTOR_O_r01 }, + { 3, 0, _CALL_METHOD_DESCRIPTOR_O_r03 }, { -1, -1, -1 }, { -1, -1, -1 }, { -1, -1, -1 }, @@ -3764,7 +3764,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = { [_CALL_LIST_APPEND_r13] = _CALL_LIST_APPEND, [_CALL_LIST_APPEND_r23] = _CALL_LIST_APPEND, [_CALL_LIST_APPEND_r33] = _CALL_LIST_APPEND, - [_CALL_METHOD_DESCRIPTOR_O_r01] = _CALL_METHOD_DESCRIPTOR_O, + [_CALL_METHOD_DESCRIPTOR_O_r03] = _CALL_METHOD_DESCRIPTOR_O, [_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01] = _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, [_CALL_METHOD_DESCRIPTOR_NOARGS_r01] = _CALL_METHOD_DESCRIPTOR_NOARGS, [_CALL_METHOD_DESCRIPTOR_FAST_r01] = _CALL_METHOD_DESCRIPTOR_FAST, @@ -4045,7 +4045,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = { [_CALL_METHOD_DESCRIPTOR_NOARGS] = "_CALL_METHOD_DESCRIPTOR_NOARGS", [_CALL_METHOD_DESCRIPTOR_NOARGS_r01] = "_CALL_METHOD_DESCRIPTOR_NOARGS_r01", [_CALL_METHOD_DESCRIPTOR_O] = "_CALL_METHOD_DESCRIPTOR_O", - [_CALL_METHOD_DESCRIPTOR_O_r01] = "_CALL_METHOD_DESCRIPTOR_O_r01", + [_CALL_METHOD_DESCRIPTOR_O_r03] = "_CALL_METHOD_DESCRIPTOR_O_r03", [_CALL_NON_PY_GENERAL] = "_CALL_NON_PY_GENERAL", [_CALL_NON_PY_GENERAL_r01] = "_CALL_NON_PY_GENERAL_r01", [_CALL_STR_1] = "_CALL_STR_1", diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 3780bdb28c8c44..faaeea0d276eb0 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2212,6 +2212,22 @@ def testfunc(n): self.assertIn("_CALL_BUILTIN_O", uops) self.assertIn("_POP_TOP", uops) + def test_call_method_descriptor_o(self): + def testfunc(n): + x = 0 + for _ in range(n): + y = (1, 2, 3) + z = y.count(2) + x += z + return x + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertIn("_CALL_METHOD_DESCRIPTOR_O", uops) + self.assertIn("_POP_TOP", uops) + def test_get_len_with_const_tuple(self): def testfunc(n): x = 0.0 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ea09c0645aa39c..ab60bad738cda3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4362,7 +4362,7 @@ dummy_func( none = PyStackRef_None; } - op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res)) { + op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, a0, a1, c)) { PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; @@ -4390,8 +4390,13 @@ dummy_func( PyStackRef_AsPyObjectBorrow(arg_stackref)); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - DECREF_INPUTS(); - ERROR_IF(res_o == NULL); + if (res_o == NULL) { + ERROR_NO_POP(); + } + a0 = self_stackref; + a1 = arg_stackref; + c = callable; + INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4399,6 +4404,9 @@ dummy_func( unused/1 + unused/2 + _CALL_METHOD_DESCRIPTOR_O + + POP_TOP + + POP_TOP + + POP_TOP + _CHECK_PERIODIC_AT_END; op(_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, (callable, self_or_null, args[oparg] -- res)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 4e8fa34c0b2c0d..1572a0430d3dd8 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -14302,13 +14302,16 @@ break; } - case _CALL_METHOD_DESCRIPTOR_O_r01: { + case _CALL_METHOD_DESCRIPTOR_O_r03: { CHECK_CURRENT_CACHED_VALUES(0); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); _PyStackRef *args; _PyStackRef self_or_null; _PyStackRef callable; _PyStackRef res; + _PyStackRef a0; + _PyStackRef a1; + _PyStackRef c; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; @@ -14359,33 +14362,21 @@ stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } + a0 = self_stackref; + a1 = arg_stackref; + c = callable; res = PyStackRef_FromPyObjectSteal(res_o); - _tos_cache0 = res; - _tos_cache1 = PyStackRef_ZERO_BITS; - _tos_cache2 = PyStackRef_ZERO_BITS; - SET_CURRENT_CACHED_VALUES(1); + _tos_cache2 = c; + _tos_cache1 = a1; + _tos_cache0 = a0; + SET_CURRENT_CACHED_VALUES(3); + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index e63852aee1134c..a1b716654bfeac 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3613,6 +3613,10 @@ _PyStackRef self_or_null; _PyStackRef *args; _PyStackRef res; + _PyStackRef a0; + _PyStackRef a1; + _PyStackRef c; + _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_METHOD_DESCRIPTOR_O @@ -3666,34 +3670,46 @@ stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyStackRef tmp; - for (int _i = oparg; --_i >= 0;) { - tmp = args[_i]; - args[_i] = PyStackRef_NULL; - PyStackRef_CLOSE(tmp); - } - tmp = self_or_null; - self_or_null = PyStackRef_NULL; - stack_pointer[-1 - oparg] = self_or_null; - PyStackRef_XCLOSE(tmp); - tmp = callable; - callable = PyStackRef_NULL; - stack_pointer[-2 - oparg] = callable; - PyStackRef_CLOSE(tmp); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); if (res_o == NULL) { JUMP_TO_LABEL(error); } + a0 = self_stackref; + a1 = arg_stackref; + c = callable; res = PyStackRef_FromPyObjectSteal(res_o); } - // _CHECK_PERIODIC_AT_END + // _POP_TOP { - stack_pointer[0] = res; - stack_pointer += 1; + value = c; + stack_pointer[-2 - oparg] = res; + stack_pointer[-1 - oparg] = a0; + stack_pointer[-oparg] = a1; + stack_pointer += 1 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = a1; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = a0; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _CHECK_PERIODIC_AT_END + { _PyFrame_SetStackPointer(frame, stack_pointer); int err = check_periodics(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index b043a9493cbd7c..8e726f227c2322 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2913,10 +2913,19 @@ case _CALL_METHOD_DESCRIPTOR_O: { JitOptRef res; + JitOptRef a0; + JitOptRef a1; + JitOptRef c; res = sym_new_not_null(ctx); - CHECK_STACK_BOUNDS(-1 - oparg); + a0 = sym_new_not_null(ctx); + a1 = sym_new_not_null(ctx); + c = sym_new_not_null(ctx); + CHECK_STACK_BOUNDS(2 - oparg); stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + stack_pointer[-1 - oparg] = a0; + stack_pointer[-oparg] = a1; + stack_pointer[1 - oparg] = c; + stack_pointer += 2 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } From 88d3fa3fb21e90577828a59e0f3a1c7026fde179 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Thu, 1 Jan 2026 23:48:05 +0900 Subject: [PATCH 2/7] Update for _CALL_BUILTIN_O --- Lib/test/test_capi/test_opt.py | 1 + Python/optimizer_bytecodes.c | 6 ++++++ Python/optimizer_cases.c.h | 8 ++++++-- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index faaeea0d276eb0..98fd0f04d0ce8f 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2211,6 +2211,7 @@ def testfunc(n): uops = get_opnames(ex) self.assertIn("_CALL_BUILTIN_O", uops) self.assertIn("_POP_TOP", uops) + self.assertIn("_POP_TOP_NOP", uops) def test_call_method_descriptor_o(self): def testfunc(n): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 3e37cb81388ae0..34f88e6bf3bafe 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1064,6 +1064,12 @@ dummy_func(void) { none = sym_new_const(ctx, Py_None); } + op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, a, c)) { + res = sym_new_not_null(ctx); + a = args[0]; + c = callable; + } + op(_GUARD_IS_FALSE_POP, (flag -- )) { if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 8e726f227c2322..b2d81b4fc3595d 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2764,12 +2764,16 @@ } case _CALL_BUILTIN_O: { + JitOptRef *args; + JitOptRef callable; JitOptRef res; JitOptRef a; JitOptRef c; + args = &stack_pointer[-oparg]; + callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); - a = sym_new_not_null(ctx); - c = sym_new_not_null(ctx); + a = args[0]; + c = callable; CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer[-1 - oparg] = a; From fc99b867dc0c204819597d729a9fe3e17cd6e372 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Thu, 1 Jan 2026 23:49:23 +0900 Subject: [PATCH 3/7] Update --- Python/optimizer_bytecodes.c | 7 +++++++ Python/optimizer_cases.c.h | 10 +++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 34f88e6bf3bafe..2ec645147a18dc 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1070,6 +1070,13 @@ dummy_func(void) { c = callable; } + op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, a0, a1, c)) { + res = sym_new_not_null(ctx); + a0 = args[0]; + a1 = args[1]; + c = callable; + } + op(_GUARD_IS_FALSE_POP, (flag -- )) { if (sym_is_const(ctx, flag)) { PyObject *value = sym_get_const(ctx, flag); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index b2d81b4fc3595d..2ecbc9e0b7f5dd 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2916,14 +2916,18 @@ } case _CALL_METHOD_DESCRIPTOR_O: { + JitOptRef *args; + JitOptRef callable; JitOptRef res; JitOptRef a0; JitOptRef a1; JitOptRef c; + args = &stack_pointer[-oparg]; + callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); - a0 = sym_new_not_null(ctx); - a1 = sym_new_not_null(ctx); - c = sym_new_not_null(ctx); + a0 = args[0]; + a1 = args[1]; + c = callable; CHECK_STACK_BOUNDS(2 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer[-1 - oparg] = a0; From 216440a6f2c466c3c2a6245fd58dbdf7a73241c2 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Thu, 1 Jan 2026 23:57:31 +0900 Subject: [PATCH 4/7] fix --- Python/optimizer_bytecodes.c | 5 +++++ Python/optimizer_cases.c.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 2ec645147a18dc..350e72304d9e96 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1066,12 +1066,17 @@ dummy_func(void) { op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, a, c)) { res = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); + args[0] = sym_new_unknown(ctx); a = args[0]; c = callable; } op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, a0, a1, c)) { res = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); + args[0] = sym_new_unknown(ctx); + args[1] = sym_new_unknown(ctx); a0 = args[0]; a1 = args[1]; c = callable; diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2ecbc9e0b7f5dd..17b240161bc939 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2765,13 +2765,17 @@ case _CALL_BUILTIN_O: { JitOptRef *args; + JitOptRef self_or_null; JitOptRef callable; JitOptRef res; JitOptRef a; JitOptRef c; args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); + args[0] = sym_new_unknown(ctx); a = args[0]; c = callable; CHECK_STACK_BOUNDS(1 - oparg); @@ -2917,14 +2921,19 @@ case _CALL_METHOD_DESCRIPTOR_O: { JitOptRef *args; + JitOptRef self_or_null; JitOptRef callable; JitOptRef res; JitOptRef a0; JitOptRef a1; JitOptRef c; args = &stack_pointer[-oparg]; + self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); + self_or_null = sym_new_not_null(ctx); + args[0] = sym_new_unknown(ctx); + args[1] = sym_new_unknown(ctx); a0 = args[0]; a1 = args[1]; c = callable; From 760a9c2abef7ce4bbcbafed577222db289b0a543 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 1 Jan 2026 15:36:11 +0000 Subject: [PATCH 5/7] fixup --- Include/internal/pycore_opcode_metadata.h | 2 +- Lib/test/test_capi/test_opt.py | 9 +++-- Python/bytecodes.c | 12 ++++--- Python/executor_cases.c.h | 29 +++++++++------- Python/generated_cases.c.h | 42 +++++++++++++++-------- Python/optimizer_bytecodes.c | 18 ++++------ Python/optimizer_cases.c.h | 36 +++++++++---------- 7 files changed, 81 insertions(+), 67 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index adce512d32941f..6269ad95ddd716 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1359,7 +1359,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_BUILTIN_O] = { .nuops = 4, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_BUILTIN_O] = { .nuops = 5, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_1, OPARG_SIMPLE, 0 } } }, [CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_2, OPARG_SIMPLE, 0 } } }, [CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } }, diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 98fd0f04d0ce8f..93433b841740b4 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2201,7 +2201,8 @@ def test_call_builtin_o(self): def testfunc(n): x = 0 for _ in range(n): - y = abs(1) + my_abs = abs + y = my_abs(1) x += y return x @@ -2210,7 +2211,7 @@ def testfunc(n): self.assertIsNotNone(ex) uops = get_opnames(ex) self.assertIn("_CALL_BUILTIN_O", uops) - self.assertIn("_POP_TOP", uops) + self.assertNotIn("_POP_TOP", uops) self.assertIn("_POP_TOP_NOP", uops) def test_call_method_descriptor_o(self): @@ -2226,8 +2227,10 @@ def testfunc(n): self.assertEqual(res, TIER2_THRESHOLD) self.assertIsNotNone(ex) uops = get_opnames(ex) + pop_tops = [opname for opname in iter_opnames(ex) if opname == "_POP_TOP"] self.assertIn("_CALL_METHOD_DESCRIPTOR_O", uops) - self.assertIn("_POP_TOP", uops) + self.assertIn("_POP_TOP_NOP", uops) + self.assertLessEqual(len(pop_tops), 1) def test_get_len_with_const_tuple(self): def testfunc(n): diff --git a/Python/bytecodes.c b/Python/bytecodes.c index ab60bad738cda3..c7cc8f411cc9e3 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4170,7 +4170,7 @@ dummy_func( _CALL_BUILTIN_CLASS + _CHECK_PERIODIC_AT_END; - op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, a, c)) { + op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { /* Builtin METH_O functions */ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -4193,8 +4193,9 @@ dummy_func( if (res_o == NULL) { ERROR_NO_POP(); } - a = arg; c = callable; + s = self_or_null; + a = args[0]; INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4205,6 +4206,7 @@ dummy_func( _CALL_BUILTIN_O + POP_TOP + POP_TOP + + POP_TOP + _CHECK_PERIODIC_AT_END; op(_CALL_BUILTIN_FAST, (callable, self_or_null, args[oparg] -- res)) { @@ -4362,7 +4364,7 @@ dummy_func( none = PyStackRef_None; } - op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, a0, a1, c)) { + op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); int total_args = oparg; @@ -4393,9 +4395,9 @@ dummy_func( if (res_o == NULL) { ERROR_NO_POP(); } - a0 = self_stackref; - a1 = arg_stackref; c = callable; + s = self_or_null; + a = args[0]; INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1572a0430d3dd8..e3ff29e527afb5 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -13568,8 +13568,9 @@ _PyStackRef self_or_null; _PyStackRef callable; _PyStackRef res; - _PyStackRef a; _PyStackRef c; + _PyStackRef s; + _PyStackRef a; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; @@ -13612,14 +13613,16 @@ SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - a = arg; c = callable; + s = self_or_null; + a = args[0]; res = PyStackRef_FromPyObjectSteal(res_o); - _tos_cache2 = c; - _tos_cache1 = a; - _tos_cache0 = res; + _tos_cache2 = a; + _tos_cache1 = s; + _tos_cache0 = c; SET_CURRENT_CACHED_VALUES(3); - stack_pointer += -2 - oparg; + stack_pointer[-2 - oparg] = res; + stack_pointer += -1 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; @@ -14309,9 +14312,9 @@ _PyStackRef self_or_null; _PyStackRef callable; _PyStackRef res; - _PyStackRef a0; - _PyStackRef a1; _PyStackRef c; + _PyStackRef s; + _PyStackRef a; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; @@ -14366,13 +14369,13 @@ SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } - a0 = self_stackref; - a1 = arg_stackref; c = callable; + s = self_or_null; + a = args[0]; res = PyStackRef_FromPyObjectSteal(res_o); - _tos_cache2 = c; - _tos_cache1 = a1; - _tos_cache0 = a0; + _tos_cache2 = a; + _tos_cache1 = s; + _tos_cache0 = c; SET_CURRENT_CACHED_VALUES(3); stack_pointer[-2 - oparg] = res; stack_pointer += -1 - oparg; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a1b716654bfeac..76e2a10e71e19f 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2327,8 +2327,9 @@ _PyStackRef self_or_null; _PyStackRef *args; _PyStackRef res; - _PyStackRef a; _PyStackRef c; + _PyStackRef s; + _PyStackRef a; _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ @@ -2374,16 +2375,18 @@ if (res_o == NULL) { JUMP_TO_LABEL(error); } - a = arg; c = callable; + s = self_or_null; + a = args[0]; res = PyStackRef_FromPyObjectSteal(res_o); } // _POP_TOP { - value = c; + value = a; stack_pointer[-2 - oparg] = res; - stack_pointer[-1 - oparg] = a; - stack_pointer += -oparg; + stack_pointer[-1 - oparg] = c; + stack_pointer[-oparg] = s; + stack_pointer += 1 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(value); @@ -2391,7 +2394,16 @@ } // _POP_TOP { - value = a; + value = s; + stack_pointer += -1; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_XCLOSE(value); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + // _POP_TOP + { + value = c; stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -3613,9 +3625,9 @@ _PyStackRef self_or_null; _PyStackRef *args; _PyStackRef res; - _PyStackRef a0; - _PyStackRef a1; _PyStackRef c; + _PyStackRef s; + _PyStackRef a; _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ @@ -3673,17 +3685,17 @@ if (res_o == NULL) { JUMP_TO_LABEL(error); } - a0 = self_stackref; - a1 = arg_stackref; c = callable; + s = self_or_null; + a = args[0]; res = PyStackRef_FromPyObjectSteal(res_o); } // _POP_TOP { - value = c; + value = a; stack_pointer[-2 - oparg] = res; - stack_pointer[-1 - oparg] = a0; - stack_pointer[-oparg] = a1; + stack_pointer[-1 - oparg] = c; + stack_pointer[-oparg] = s; stack_pointer += 1 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -3692,7 +3704,7 @@ } // _POP_TOP { - value = a1; + value = s; stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); @@ -3701,7 +3713,7 @@ } // _POP_TOP { - value = a0; + value = c; stack_pointer += -1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 350e72304d9e96..d53d8108f079fd 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -131,7 +131,7 @@ dummy_func(void) { } op(_PUSH_NULL, (-- res)) { - res = sym_new_null(ctx); + res = PyJitRef_Borrow(sym_new_null(ctx)); } op(_GUARD_TOS_INT, (value -- value)) { @@ -1064,22 +1064,18 @@ dummy_func(void) { none = sym_new_const(ctx, Py_None); } - op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, a, c)) { + op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { res = sym_new_not_null(ctx); - self_or_null = sym_new_not_null(ctx); - args[0] = sym_new_unknown(ctx); - a = args[0]; c = callable; + s = self_or_null; + a = args[0]; } - op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, a0, a1, c)) { + op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { res = sym_new_not_null(ctx); - self_or_null = sym_new_not_null(ctx); - args[0] = sym_new_unknown(ctx); - args[1] = sym_new_unknown(ctx); - a0 = args[0]; - a1 = args[1]; c = callable; + s = self_or_null; + a = args[0]; } op(_GUARD_IS_FALSE_POP, (flag -- )) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 17b240161bc939..5221c5792eef4b 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -185,7 +185,7 @@ case _PUSH_NULL: { JitOptRef res; - res = sym_new_null(ctx); + res = PyJitRef_Borrow(sym_new_null(ctx)); CHECK_STACK_BOUNDS(1); stack_pointer[0] = res; stack_pointer += 1; @@ -2768,21 +2768,22 @@ JitOptRef self_or_null; JitOptRef callable; JitOptRef res; - JitOptRef a; JitOptRef c; + JitOptRef s; + JitOptRef a; args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); - self_or_null = sym_new_not_null(ctx); - args[0] = sym_new_unknown(ctx); - a = args[0]; c = callable; - CHECK_STACK_BOUNDS(1 - oparg); + s = self_or_null; + a = args[0]; + CHECK_STACK_BOUNDS(2 - oparg); stack_pointer[-2 - oparg] = res; - stack_pointer[-1 - oparg] = a; - stack_pointer[-oparg] = c; - stack_pointer += 1 - oparg; + stack_pointer[-1 - oparg] = c; + stack_pointer[-oparg] = s; + stack_pointer[1 - oparg] = a; + stack_pointer += 2 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2924,24 +2925,21 @@ JitOptRef self_or_null; JitOptRef callable; JitOptRef res; - JitOptRef a0; - JitOptRef a1; JitOptRef c; + JitOptRef s; + JitOptRef a; args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); - self_or_null = sym_new_not_null(ctx); - args[0] = sym_new_unknown(ctx); - args[1] = sym_new_unknown(ctx); - a0 = args[0]; - a1 = args[1]; c = callable; + s = self_or_null; + a = args[0]; CHECK_STACK_BOUNDS(2 - oparg); stack_pointer[-2 - oparg] = res; - stack_pointer[-1 - oparg] = a0; - stack_pointer[-oparg] = a1; - stack_pointer[1 - oparg] = c; + stack_pointer[-1 - oparg] = c; + stack_pointer[-oparg] = s; + stack_pointer[1 - oparg] = a; stack_pointer += 2 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; From d86cd72e458cdceb1c7124fafd7cc9b53b4ea2eb Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 1 Jan 2026 15:51:28 +0000 Subject: [PATCH 6/7] fix refleak problems --- Include/internal/pycore_opcode_metadata.h | 2 +- Python/bytecodes.c | 10 ++++------ Python/executor_cases.c.h | 17 +++++++---------- Python/generated_cases.c.h | 22 +++++----------------- Python/optimizer_bytecodes.c | 15 ++++++++++----- Python/optimizer_cases.c.h | 19 +++++++++++-------- 6 files changed, 38 insertions(+), 47 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 6269ad95ddd716..adce512d32941f 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1359,7 +1359,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, - [CALL_BUILTIN_O] = { .nuops = 5, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, + [CALL_BUILTIN_O] = { .nuops = 4, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } }, [CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_1, OPARG_SIMPLE, 0 } } }, [CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_2, OPARG_SIMPLE, 0 } } }, [CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } }, diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c7cc8f411cc9e3..0b74a03a4e56d4 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4170,7 +4170,7 @@ dummy_func( _CALL_BUILTIN_CLASS + _CHECK_PERIODIC_AT_END; - op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { + op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, c, s)) { /* Builtin METH_O functions */ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -4194,8 +4194,7 @@ dummy_func( ERROR_NO_POP(); } c = callable; - s = self_or_null; - a = args[0]; + s = args[0]; INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4206,7 +4205,6 @@ dummy_func( _CALL_BUILTIN_O + POP_TOP + POP_TOP + - POP_TOP + _CHECK_PERIODIC_AT_END; op(_CALL_BUILTIN_FAST, (callable, self_or_null, args[oparg] -- res)) { @@ -4396,8 +4394,8 @@ dummy_func( ERROR_NO_POP(); } c = callable; - s = self_or_null; - a = args[0]; + s = arguments[0]; + a = arguments[1]; INPUTS_DEAD(); res = PyStackRef_FromPyObjectSteal(res_o); } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index e3ff29e527afb5..adac2914803d46 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -13570,7 +13570,6 @@ _PyStackRef res; _PyStackRef c; _PyStackRef s; - _PyStackRef a; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; @@ -13614,15 +13613,13 @@ JUMP_TO_ERROR(); } c = callable; - s = self_or_null; - a = args[0]; + s = args[0]; res = PyStackRef_FromPyObjectSteal(res_o); - _tos_cache2 = a; - _tos_cache1 = s; - _tos_cache0 = c; + _tos_cache2 = s; + _tos_cache1 = c; + _tos_cache0 = res; SET_CURRENT_CACHED_VALUES(3); - stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + stack_pointer += -2 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; @@ -14370,8 +14367,8 @@ JUMP_TO_ERROR(); } c = callable; - s = self_or_null; - a = args[0]; + s = arguments[0]; + a = arguments[1]; res = PyStackRef_FromPyObjectSteal(res_o); _tos_cache2 = a; _tos_cache1 = s; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 76e2a10e71e19f..6e4ba9e9ece07b 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2329,7 +2329,6 @@ _PyStackRef res; _PyStackRef c; _PyStackRef s; - _PyStackRef a; _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ @@ -2376,26 +2375,15 @@ JUMP_TO_LABEL(error); } c = callable; - s = self_or_null; - a = args[0]; + s = args[0]; res = PyStackRef_FromPyObjectSteal(res_o); } // _POP_TOP { - value = a; + value = s; stack_pointer[-2 - oparg] = res; stack_pointer[-1 - oparg] = c; - stack_pointer[-oparg] = s; - stack_pointer += 1 - oparg; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_XCLOSE(value); - stack_pointer = _PyFrame_GetStackPointer(frame); - } - // _POP_TOP - { - value = s; - stack_pointer += -1; + stack_pointer += -oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyStackRef_XCLOSE(value); @@ -3686,8 +3674,8 @@ JUMP_TO_LABEL(error); } c = callable; - s = self_or_null; - a = args[0]; + s = arguments[0]; + a = arguments[1]; res = PyStackRef_FromPyObjectSteal(res_o); } // _POP_TOP diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index d53d8108f079fd..6e935dcf0ec92d 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1064,18 +1064,23 @@ dummy_func(void) { none = sym_new_const(ctx, Py_None); } - op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { + op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, c, s)) { res = sym_new_not_null(ctx); c = callable; - s = self_or_null; - a = args[0]; + if (sym_is_not_null(self_or_null)) { + args--; + } + s = args[0]; } op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { res = sym_new_not_null(ctx); c = callable; - s = self_or_null; - a = args[0]; + if (sym_is_not_null(self_or_null)) { + args--; + } + s = args[0]; + a = args[1]; } op(_GUARD_IS_FALSE_POP, (flag -- )) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 5221c5792eef4b..76ae9e717d92bc 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2770,20 +2770,20 @@ JitOptRef res; JitOptRef c; JitOptRef s; - JitOptRef a; args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); c = callable; - s = self_or_null; - a = args[0]; - CHECK_STACK_BOUNDS(2 - oparg); + if (sym_is_not_null(self_or_null)) { + args--; + } + s = args[0]; + CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer[-1 - oparg] = c; stack_pointer[-oparg] = s; - stack_pointer[1 - oparg] = a; - stack_pointer += 2 - oparg; + stack_pointer += 1 - oparg; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); break; } @@ -2933,8 +2933,11 @@ callable = stack_pointer[-2 - oparg]; res = sym_new_not_null(ctx); c = callable; - s = self_or_null; - a = args[0]; + if (sym_is_not_null(self_or_null)) { + args--; + } + s = args[0]; + a = args[1]; CHECK_STACK_BOUNDS(2 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer[-1 - oparg] = c; From 3e6fe609528c1508672b4c6bd6dc4f2df99472e7 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Thu, 1 Jan 2026 15:59:16 +0000 Subject: [PATCH 7/7] fix optimizer --- Python/optimizer_bytecodes.c | 16 +++++++++++++--- Python/optimizer_cases.c.h | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 6e935dcf0ec92d..aaa786ae5fd724 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1069,8 +1069,14 @@ dummy_func(void) { c = callable; if (sym_is_not_null(self_or_null)) { args--; + s = args[0]; + } + else if (sym_is_null(self_or_null)) { + s = args[0]; + } + else { + s = sym_new_unknown(ctx); } - s = args[0]; } op(_CALL_METHOD_DESCRIPTOR_O, (callable, self_or_null, args[oparg] -- res, c, s, a)) { @@ -1078,9 +1084,13 @@ dummy_func(void) { c = callable; if (sym_is_not_null(self_or_null)) { args--; + s = args[0]; + a = args[1]; + } + else { + s = sym_new_unknown(ctx); + a = sym_new_unknown(ctx); } - s = args[0]; - a = args[1]; } op(_GUARD_IS_FALSE_POP, (flag -- )) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 76ae9e717d92bc..87c2d1a779b990 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2777,8 +2777,14 @@ c = callable; if (sym_is_not_null(self_or_null)) { args--; + s = args[0]; + } + else if (sym_is_null(self_or_null)) { + s = args[0]; + } + else { + s = sym_new_unknown(ctx); } - s = args[0]; CHECK_STACK_BOUNDS(1 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer[-1 - oparg] = c; @@ -2935,9 +2941,13 @@ c = callable; if (sym_is_not_null(self_or_null)) { args--; + s = args[0]; + a = args[1]; + } + else { + s = sym_new_unknown(ctx); + a = sym_new_unknown(ctx); } - s = args[0]; - a = args[1]; CHECK_STACK_BOUNDS(2 - oparg); stack_pointer[-2 - oparg] = res; stack_pointer[-1 - oparg] = c;