From f659bc7e8f4486e9a7eca8fa8f9c913b5172e84c Mon Sep 17 00:00:00 2001 From: PuQing Date: Sat, 28 Jun 2025 12:33:17 +0800 Subject: [PATCH 1/3] eliminate refcount from _CALL_BUILTION_O --- Include/internal/pycore_opcode_metadata.h | 2 +- Lib/test/test_capi/test_opt.py | 15 +++++++++ Python/bytecodes.c | 11 +++---- Python/executor_cases.c.h | 20 ++++++------ Python/generated_cases.c.h | 38 ++++++++++++++--------- Python/optimizer_cases.c.h | 8 ++++- 6 files changed, 62 insertions(+), 32 deletions(-) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index dd1bf2d1d2b51a..3459d8d079af40 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1350,7 +1350,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, - [CALL_BUILTIN_O] = { .nuops = 2, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, + [CALL_BUILTIN_O] = { .nuops = 3, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TWO, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 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 e4c9a463855a69..f407f510c6d4e3 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2011,6 +2011,21 @@ class C: self.assertNotIn("_COMPARE_OP_INT", uops) self.assertNotIn("_GUARD_IS_TRUE_POP", uops) + def test_call_builtin_o(self): + def testfunc(n): + x = 0 + for _ in range(n): + y = abs(1) + x += y + 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_BUILTIN_O", uops) + self.assertIn("_POP_TWO", 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 535e552e047475..75ed60d82a4a9a 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4202,7 +4202,7 @@ dummy_func( _CALL_BUILTIN_CLASS + _CHECK_PERIODIC; - op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res)) { + op(_CALL_BUILTIN_O, (callable, self_or_null, args[oparg] -- res, a, c)) { /* Builtin METH_O functions */ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -4222,11 +4222,9 @@ dummy_func( PyObject *res_o = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable_o), PyStackRef_AsPyObjectBorrow(arg)); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - - PyStackRef_CLOSE(arg); - DEAD(args); - DEAD(self_or_null); - PyStackRef_CLOSE(callable); + INPUTS_DEAD(); + a = arg; + c = callable; ERROR_IF(res_o == NULL); res = PyStackRef_FromPyObjectSteal(res_o); } @@ -4235,6 +4233,7 @@ dummy_func( unused/1 + unused/2 + _CALL_BUILTIN_O + + _POP_TWO + _CHECK_PERIODIC; op(_CALL_BUILTIN_FAST, (callable, self_or_null, args[oparg] -- res)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 46fc164a5b3bc2..b7bdbf263b16eb 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5703,6 +5703,8 @@ _PyStackRef self_or_null; _PyStackRef callable; _PyStackRef res; + _PyStackRef a; + _PyStackRef c; oparg = CURRENT_OPARG(); args = &stack_pointer[-oparg]; self_or_null = stack_pointer[-1 - oparg]; @@ -5737,20 +5739,18 @@ stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); + a = arg; + c = callable; if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(res_o); - stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[-2 - oparg] = res; + stack_pointer[-1 - oparg] = a; + stack_pointer[-oparg] = c; + stack_pointer += 1 - oparg; assert(WITHIN_STACK_BOUNDS()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8f7932f0033c6f..a574c58c88e563 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2447,6 +2447,10 @@ _PyStackRef self_or_null; _PyStackRef *args; _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + _PyStackRef nos; + _PyStackRef tos; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _CALL_BUILTIN_O @@ -2488,39 +2492,45 @@ stack_pointer = _PyFrame_GetStackPointer(frame); _Py_LeaveRecursiveCallTstate(tstate); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + a = arg; + c = callable; + if (res_o == NULL) { + stack_pointer += -2 - oparg; + assert(WITHIN_STACK_BOUNDS()); + JUMP_TO_LABEL(error); + } + res = PyStackRef_FromPyObjectSteal(res_o); + } + // _POP_TWO + { + tos = c; + nos = a; + stack_pointer[-2 - oparg] = res; + stack_pointer[-1 - oparg] = nos; + stack_pointer += -oparg; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); + PyStackRef_CLOSE(tos); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2 - oparg; + stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); + PyStackRef_CLOSE(nos); stack_pointer = _PyFrame_GetStackPointer(frame); - if (res_o == NULL) { - JUMP_TO_LABEL(error); - } - res = PyStackRef_FromPyObjectSteal(res_o); } // _CHECK_PERIODIC { _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); QSBR_QUIESCENT_STATE(tstate); if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_HandlePending(tstate); stack_pointer = _PyFrame_GetStackPointer(frame); if (err != 0) { JUMP_TO_LABEL(error); } - stack_pointer += -1; } } - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 10767ccdbd57f5..1c8cf6e994c816 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2251,9 +2251,15 @@ case _CALL_BUILTIN_O: { JitOptRef res; + JitOptRef a; + JitOptRef c; res = sym_new_not_null(ctx); + a = sym_new_not_null(ctx); + c = sym_new_not_null(ctx); stack_pointer[-2 - oparg] = res; - stack_pointer += -1 - oparg; + stack_pointer[-1 - oparg] = a; + stack_pointer[-oparg] = c; + stack_pointer += 1 - oparg; assert(WITHIN_STACK_BOUNDS()); break; } From 50e192f08f4c1d38bf3da0d254d848ad708a7557 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 04:32:39 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst new file mode 100644 index 00000000000000..550d70b79a97b0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst @@ -0,0 +1 @@ +Eliminate redundant refcounting from `_CALL_BUILTIN_O`. From 2c8e4c8cd1e4ac1bf39082a63ab7f4a09bfbdb56 Mon Sep 17 00:00:00 2001 From: PuQing Date: Sat, 28 Jun 2025 12:39:36 +0800 Subject: [PATCH 3/3] fix news format --- .../2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst index 550d70b79a97b0..97e24e5f881b92 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-28-04-32-38.gh-issue-134584.eZogqn.rst @@ -1 +1 @@ -Eliminate redundant refcounting from `_CALL_BUILTIN_O`. +Eliminate redundant refcounting from ``_CALL_BUILTIN_O``.