From b51bdcd32370b1dc54c9dab49258cd31892184ee Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Mon, 13 Apr 2026 20:47:51 +0800 Subject: [PATCH 1/2] gh-131798: JIT: Optimize `_CHECK_IS_NOT_PY_CALLABLE_KW` and `_CHECK_IS_NOT_PY_CALLABLE_EX` --- Lib/test/test_capi/test_opt.py | 29 +++++++++++++++++++++++++++++ Python/optimizer_bytecodes.c | 14 ++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index 03ec53b93a3ba9..fd57cd9a25721a 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2845,6 +2845,35 @@ def testfunc(n): uops = get_opnames(ex) self.assertNotIn("_CHECK_IS_NOT_PY_CALLABLE", uops) + def test_check_is_not_py_callable_ex(self): + def testfunc(n): + total = 0 + xs = (1, 2, 3) + args = (xs,) + for _ in range(n): + total += len(*args) + return total + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, 3 * TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_CHECK_IS_NOT_PY_CALLABLE_EX", uops) + + def test_check_is_not_py_callable_kw(self): + def testfunc(n): + total = 0 + xs = (3, 1, 2) + for _ in range(n): + total += sorted(xs, reverse=False)[0] + return total + + res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD) + self.assertEqual(res, TIER2_THRESHOLD) + self.assertIsNotNone(ex) + uops = get_opnames(ex) + self.assertNotIn("_CHECK_IS_NOT_PY_CALLABLE_KW", uops) + def test_call_len_string(self): def testfunc(n): for _ in range(n): diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 957575dcfaccce..39889fd48c52f4 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1273,6 +1273,20 @@ dummy_func(void) { } } + op(_CHECK_IS_NOT_PY_CALLABLE_EX, (func_st, unused, unused, unused -- func_st, unused, unused, unused)) { + PyTypeObject *type = sym_get_type(func_st); + if (type && type != &PyFunction_Type) { + ADD_OP(_NOP, 0, 0); + } + } + + op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable, unused, unused[oparg], unused -- callable, unused, unused[oparg], unused)) { + PyTypeObject *type = sym_get_type(callable); + if (type && type != &PyFunction_Type && type != &PyMethod_Type) { + ADD_OP(_NOP, 0, 0); + } + } + op(_PUSH_FRAME, (new_frame -- )) { SYNC_SP(); if (!CURRENT_FRAME_IS_INIT_SHIM()) { From e47b631650b298fc4c00f6f4a1fe51874773f23b Mon Sep 17 00:00:00 2001 From: Wulian233 <1055917385@qq.com> Date: Mon, 13 Apr 2026 20:53:48 +0800 Subject: [PATCH 2/2] update --- Python/optimizer_cases.c.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 553d819fcdeefb..e67b63dcd85018 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -4624,6 +4624,12 @@ } case _CHECK_IS_NOT_PY_CALLABLE_KW: { + JitOptRef callable; + callable = stack_pointer[-3 - oparg]; + PyTypeObject *type = sym_get_type(callable); + if (type && type != &PyFunction_Type && type != &PyMethod_Type) { + ADD_OP(_NOP, 0, 0); + } break; } @@ -4660,6 +4666,12 @@ } case _CHECK_IS_NOT_PY_CALLABLE_EX: { + JitOptRef func_st; + func_st = stack_pointer[-4]; + PyTypeObject *type = sym_get_type(func_st); + if (type && type != &PyFunction_Type) { + ADD_OP(_NOP, 0, 0); + } break; }