diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index f11413cc625422..2678a620763b4b 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -2755,6 +2755,21 @@ def testfunc(n): self.assertNotIn("_GUARD_TOS_INT", uops) self.assertIn("_POP_TOP_NOP", uops) + def test_check_is_not_py_callable(self): + def testfunc(n): + total = 0 + f = len + xs = (1, 2, 3) + for _ in range(n): + total += f(xs) + 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", 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 c12a4f4131bc7e..7a5ad26281132a 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1213,6 +1213,13 @@ dummy_func(void) { (void)framesize; } + op(_CHECK_IS_NOT_PY_CALLABLE, (callable, unused, unused[oparg] -- callable, unused, unused[oparg])) { + 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()) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 2db2c87cb3610b..e84f7f5aa1bc07 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -3647,6 +3647,12 @@ } case _CHECK_IS_NOT_PY_CALLABLE: { + JitOptRef callable; + callable = stack_pointer[-2 - oparg]; + PyTypeObject *type = sym_get_type(callable); + if (type && type != &PyFunction_Type && type != &PyMethod_Type) { + ADD_OP(_NOP, 0, 0); + } break; }