diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index dd1bf2d1d2b51a..8d1d1f8a4c223c 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1357,7 +1357,7 @@ _PyOpcode_macro_expansion[256] = { [CALL_KW_BOUND_METHOD] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION_KW, 2, 1 }, { _EXPAND_METHOD_KW, OPARG_SIMPLE, 3 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, [CALL_KW_NON_PY] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE_KW, OPARG_SIMPLE, 3 }, { _CALL_KW_NON_PY, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_KW_PY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _PY_FRAME_KW, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } }, - [CALL_LEN] = { .nuops = 3, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 } } }, + [CALL_LEN] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } }, [CALL_LIST_APPEND] = { .nuops = 4, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC, OPARG_SIMPLE, 3 } } }, diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py index e4c9a463855a69..e7f0a9a8ff4485 100644 --- a/Lib/test/test_capi/test_opt.py +++ b/Lib/test/test_capi/test_opt.py @@ -1967,6 +1967,7 @@ def testfunc(n): self.assertIn("_CALL_LEN", uops) self.assertNotIn("_GUARD_NOS_INT", uops) self.assertNotIn("_GUARD_TOS_INT", uops) + self.assertIn("_POP_TOP_NOP", uops) def test_call_len_known_length_small_int(self): def testfunc(n): diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1a5a9ff13a23a5..63ac32fe28f842 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4315,7 +4315,9 @@ dummy_func( unused/2 + _GUARD_NOS_NULL + _GUARD_CALLABLE_LEN + - _CALL_LEN; + _CALL_LEN + + POP_TOP + + POP_TOP; op(_GUARD_CALLABLE_LEN, (callable, unused, unused -- callable, unused, unused)){ PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable); @@ -4323,10 +4325,10 @@ dummy_func( DEOPT_IF(callable_o != interp->callable_cache.len); } - op(_CALL_LEN, (callable, null, arg -- res)) { + op(_CALL_LEN, (callable, null, arg -- res, a, c)) { /* len(o) */ - (void)null; STAT_INC(CALL, hit); + INPUTS_DEAD(); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); Py_ssize_t len_i = PyObject_Length(arg_o); if (len_i < 0) { @@ -4337,10 +4339,9 @@ dummy_func( if (res_o == NULL) { ERROR_NO_POP(); } - PyStackRef_CLOSE(arg); - DEAD(null); - PyStackRef_CLOSE(callable); res = PyStackRef_FromPyObjectSteal(res_o); + a = arg; + c = callable; } op(_GUARD_CALLABLE_ISINSTANCE, (callable, unused, unused, unused -- callable, unused, unused, unused)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 46fc164a5b3bc2..9ca52bea3a9163 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5937,15 +5937,16 @@ case _CALL_LEN: { _PyStackRef arg; - _PyStackRef null; _PyStackRef callable; _PyStackRef res; + _PyStackRef a; + _PyStackRef c; arg = stack_pointer[-1]; - null = stack_pointer[-2]; callable = stack_pointer[-3]; - (void)null; STAT_INC(CALL, hit); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(arg_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -5957,19 +5958,13 @@ if (res_o == NULL) { JUMP_TO_ERROR(); } - stack_pointer += -1; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); - stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); - stack_pointer = _PyFrame_GetStackPointer(frame); res = PyStackRef_FromPyObjectSteal(res_o); + a = arg; + c = callable; stack_pointer[0] = res; - stack_pointer += 1; + stack_pointer[1] = a; + stack_pointer[2] = c; + stack_pointer += 3; assert(WITHIN_STACK_BOUNDS()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 8f7932f0033c6f..f8dab3960bb102 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3408,6 +3408,9 @@ _PyStackRef callable; _PyStackRef arg; _PyStackRef res; + _PyStackRef a; + _PyStackRef c; + _PyStackRef value; /* Skip 1 cache entry */ /* Skip 2 cache entries */ // _GUARD_NOS_NULL @@ -3433,9 +3436,10 @@ // _CALL_LEN { arg = stack_pointer[-1]; - (void)null; STAT_INC(CALL, hit); PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg); + stack_pointer += -3; + assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); Py_ssize_t len_i = PyObject_Length(arg_o); stack_pointer = _PyFrame_GetStackPointer(frame); @@ -3447,21 +3451,30 @@ if (res_o == NULL) { JUMP_TO_LABEL(error); } - stack_pointer += -1; + res = PyStackRef_FromPyObjectSteal(res_o); + a = arg; + c = callable; + } + // _POP_TOP + { + value = c; + stack_pointer[0] = res; + stack_pointer[1] = a; + stack_pointer += 2; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(arg); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += -2; + } + // _POP_TOP + { + value = a; + stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(callable); + PyStackRef_XCLOSE(value); stack_pointer = _PyFrame_GetStackPointer(frame); - res = PyStackRef_FromPyObjectSteal(res_o); } - stack_pointer[0] = res; - stack_pointer += 1; - assert(WITHIN_STACK_BOUNDS()); DISPATCH(); } diff --git a/Python/optimizer_bytecodes.c b/Python/optimizer_bytecodes.c index 3182e8b3b70144..158a8cae844351 100644 --- a/Python/optimizer_bytecodes.c +++ b/Python/optimizer_bytecodes.c @@ -1178,7 +1178,7 @@ dummy_func(void) { sym_set_const(callable, (PyObject *)&PyUnicode_Type); } - op(_CALL_LEN, (callable, null, arg -- res)) { + op(_CALL_LEN, (callable, null, arg -- res, a, c)) { res = sym_new_type(ctx, &PyLong_Type); int tuple_length = sym_tuple_length(arg); if (tuple_length >= 0) { @@ -1193,6 +1193,8 @@ dummy_func(void) { res = sym_new_const(ctx, temp); Py_DECREF(temp); } + a = arg; + c = callable; } op(_GET_LEN, (obj -- obj, len)) { diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index 8d30df3aa7d429..8b90cc773c5344 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2460,8 +2460,12 @@ case _CALL_LEN: { JitOptRef arg; + JitOptRef callable; JitOptRef res; + JitOptRef a; + JitOptRef c; arg = stack_pointer[-1]; + callable = stack_pointer[-3]; res = sym_new_type(ctx, &PyLong_Type); int tuple_length = sym_tuple_length(arg); if (tuple_length >= 0) { @@ -2480,9 +2484,11 @@ Py_DECREF(temp); stack_pointer += 2; } + a = arg; + c = callable; stack_pointer[-3] = res; - stack_pointer += -2; - assert(WITHIN_STACK_BOUNDS()); + stack_pointer[-2] = a; + stack_pointer[-1] = c; break; }