gh-134584: Eliminate redundant refcounting from `_CALL_LEN` (gh-136104)

This commit is contained in:
Donghee Na 2025-12-12 00:24:34 +09:00 committed by GitHub
parent c433986005
commit a27538540e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 54 additions and 41 deletions

View File

@ -1366,7 +1366,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_AT_END, OPARG_REPLACED, 3 } } },
[CALL_KW_PY] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION_KW, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _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_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 } } },

View File

@ -431,7 +431,7 @@ extern "C" {
#define _CALL_INTRINSIC_2_r21 624
#define _CALL_ISINSTANCE_r31 625
#define _CALL_KW_NON_PY_r11 626
#define _CALL_LEN_r31 627
#define _CALL_LEN_r33 627
#define _CALL_LIST_APPEND_r30 628
#define _CALL_METHOD_DESCRIPTOR_FAST_r01 629
#define _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS_r01 630

View File

@ -2624,7 +2624,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ -1, -1, -1 },
{ -1, -1, -1 },
{ -1, -1, -1 },
{ 1, 0, _CALL_LEN_r31 },
{ 3, 0, _CALL_LEN_r33 },
},
},
[_GUARD_CALLABLE_ISINSTANCE] = {
@ -3751,7 +3751,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_GUARD_CALLABLE_LEN_r13] = _GUARD_CALLABLE_LEN,
[_GUARD_CALLABLE_LEN_r23] = _GUARD_CALLABLE_LEN,
[_GUARD_CALLABLE_LEN_r33] = _GUARD_CALLABLE_LEN,
[_CALL_LEN_r31] = _CALL_LEN,
[_CALL_LEN_r33] = _CALL_LEN,
[_GUARD_CALLABLE_ISINSTANCE_r03] = _GUARD_CALLABLE_ISINSTANCE,
[_GUARD_CALLABLE_ISINSTANCE_r13] = _GUARD_CALLABLE_ISINSTANCE,
[_GUARD_CALLABLE_ISINSTANCE_r23] = _GUARD_CALLABLE_ISINSTANCE,
@ -4042,7 +4042,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_CALL_KW_NON_PY] = "_CALL_KW_NON_PY",
[_CALL_KW_NON_PY_r11] = "_CALL_KW_NON_PY_r11",
[_CALL_LEN] = "_CALL_LEN",
[_CALL_LEN_r31] = "_CALL_LEN_r31",
[_CALL_LEN_r33] = "_CALL_LEN_r33",
[_CALL_LIST_APPEND] = "_CALL_LIST_APPEND",
[_CALL_LIST_APPEND_r30] = "_CALL_LIST_APPEND_r30",
[_CALL_METHOD_DESCRIPTOR_FAST] = "_CALL_METHOD_DESCRIPTOR_FAST",

View File

@ -2066,6 +2066,7 @@ class TestUopsOptimization(unittest.TestCase):
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):
# Make sure that len(t) is optimized for a tuple of length 5.

View File

@ -4280,7 +4280,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);
@ -4288,9 +4290,8 @@ 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);
PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg);
Py_ssize_t len_i = PyObject_Length(arg_o);
@ -4302,9 +4303,9 @@ dummy_func(
if (res_o == NULL) {
ERROR_NO_POP();
}
PyStackRef_CLOSE(arg);
DEAD(null);
PyStackRef_CLOSE(callable);
a = arg;
c = callable;
INPUTS_DEAD();
res = PyStackRef_FromPyObjectSteal(res_o);
}

View File

@ -13370,24 +13370,23 @@
break;
}
case _CALL_LEN_r31: {
case _CALL_LEN_r33: {
CHECK_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_WITH_CACHE());
_PyStackRef arg;
_PyStackRef null;
_PyStackRef callable;
_PyStackRef res;
_PyStackRef a;
_PyStackRef c;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
_PyStackRef _stack_item_2 = _tos_cache2;
arg = _stack_item_2;
null = _stack_item_1;
callable = _stack_item_0;
(void)null;
STAT_INC(CALL, hit);
PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg);
stack_pointer[0] = callable;
stack_pointer[1] = null;
stack_pointer[1] = _stack_item_1;
stack_pointer[2] = arg;
stack_pointer += 3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
@ -13404,21 +13403,15 @@
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
}
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(arg);
stack_pointer = _PyFrame_GetStackPointer(frame);
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(callable);
stack_pointer = _PyFrame_GetStackPointer(frame);
a = arg;
c = callable;
res = PyStackRef_FromPyObjectSteal(res_o);
_tos_cache2 = c;
_tos_cache1 = a;
_tos_cache0 = res;
_tos_cache1 = PyStackRef_ZERO_BITS;
_tos_cache2 = PyStackRef_ZERO_BITS;
SET_CURRENT_CACHED_VALUES(1);
SET_CURRENT_CACHED_VALUES(3);
stack_pointer += -3;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_WITH_CACHE());
break;
}

View File

@ -3144,6 +3144,9 @@
_PyStackRef callable;
_PyStackRef arg;
_PyStackRef res;
_PyStackRef a;
_PyStackRef c;
_PyStackRef value;
/* Skip 1 cache entry */
/* Skip 2 cache entries */
// _GUARD_NOS_NULL
@ -3169,7 +3172,6 @@
// _CALL_LEN
{
arg = stack_pointer[-1];
(void)null;
STAT_INC(CALL, hit);
PyObject *arg_o = PyStackRef_AsPyObjectBorrow(arg);
_PyFrame_SetStackPointer(frame, stack_pointer);
@ -3183,21 +3185,30 @@
if (res_o == NULL) {
JUMP_TO_LABEL(error);
}
a = arg;
c = callable;
res = PyStackRef_FromPyObjectSteal(res_o);
}
// _POP_TOP
{
value = c;
stack_pointer[-3] = res;
stack_pointer[-2] = a;
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_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(__FILE__, __LINE__);
_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(__FILE__, __LINE__);
DISPATCH();
}

View File

@ -1202,7 +1202,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);
Py_ssize_t tuple_length = sym_tuple_length(arg);
if (tuple_length >= 0) {
@ -1217,6 +1217,8 @@ dummy_func(void) {
res = sym_new_const(ctx, temp);
Py_DECREF(temp);
}
a = arg;
c = callable;
}
op(_GET_LEN, (obj -- obj, len)) {

View File

@ -3002,8 +3002,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);
Py_ssize_t tuple_length = sym_tuple_length(arg);
if (tuple_length >= 0) {
@ -3023,10 +3027,11 @@
Py_DECREF(temp);
stack_pointer += 2;
}
CHECK_STACK_BOUNDS(-2);
a = arg;
c = callable;
stack_pointer[-3] = res;
stack_pointer += -2;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
stack_pointer[-2] = a;
stack_pointer[-1] = c;
break;
}