gh-134584: Eliminate redundant refcounting from _LOAD_ATTR_SLOT (GH-143320)

Signed-off-by: Manjusaka <me@manjusaka.me>
Co-authored-by: Ken Jin <kenjin4096@gmail.com>
This commit is contained in:
Nadeshiko Manju 2026-01-02 01:27:02 +08:00 committed by GitHub
parent 1fb8e0eb51
commit d00d39f58e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 442 additions and 331 deletions

View file

@ -2485,7 +2485,7 @@ dummy_func(
unused/5 +
_PUSH_NULL_CONDITIONAL;
op(_LOAD_ATTR_SLOT, (index/1, owner -- attr)) {
op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, o)) {
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
PyObject **addr = (PyObject **)((char *)owner_o + index);
@ -2498,13 +2498,15 @@ dummy_func(
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
STAT_INC(LOAD_ATTR, hit);
DECREF_INPUTS();
o = owner;
DEAD(owner);
}
macro(LOAD_ATTR_SLOT) =
unused/1 +
_GUARD_TYPE_VERSION +
_LOAD_ATTR_SLOT + // NOTE: This action may also deopt
POP_TOP +
unused/5 +
_PUSH_NULL_CONDITIONAL;

View file

@ -8532,11 +8532,49 @@
break;
}
case _LOAD_ATTR_SLOT_r11: {
case _LOAD_ATTR_SLOT_r02: {
CHECK_CURRENT_CACHED_VALUES(0);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef o;
owner = stack_pointer[-1];
uint16_t index = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
PyObject **addr = (PyObject **)((char *)owner_o + index);
PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr);
if (attr_o == NULL) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
#ifdef Py_GIL_DISABLED
int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr);
if (!increfed) {
UOP_STAT_INC(uopcode, miss);
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_JUMP_TARGET();
}
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
STAT_INC(LOAD_ATTR, hit);
o = owner;
_tos_cache1 = o;
_tos_cache0 = attr;
SET_CURRENT_CACHED_VALUES(2);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _LOAD_ATTR_SLOT_r12: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
owner = _stack_item_0;
uint16_t index = (uint16_t)CURRENT_OPERAND0_16();
@ -8561,21 +8599,52 @@
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
STAT_INC(LOAD_ATTR, hit);
stack_pointer[0] = owner;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = owner;
owner = attr;
stack_pointer[-1] = owner;
PyStackRef_CLOSE(tmp);
stack_pointer = _PyFrame_GetStackPointer(frame);
o = owner;
_tos_cache1 = o;
_tos_cache0 = attr;
_tos_cache1 = PyStackRef_ZERO_BITS;
_tos_cache2 = PyStackRef_ZERO_BITS;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}
case _LOAD_ATTR_SLOT_r23: {
CHECK_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
_PyStackRef _stack_item_1 = _tos_cache1;
owner = _stack_item_1;
uint16_t index = (uint16_t)CURRENT_OPERAND0_16();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
PyObject **addr = (PyObject **)((char *)owner_o + index);
PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr);
if (attr_o == NULL) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = owner;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
#ifdef Py_GIL_DISABLED
int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr);
if (!increfed) {
UOP_STAT_INC(uopcode, miss);
_tos_cache1 = owner;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(2);
JUMP_TO_JUMP_TARGET();
}
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
STAT_INC(LOAD_ATTR, hit);
o = owner;
_tos_cache2 = o;
_tos_cache1 = attr;
_tos_cache0 = _stack_item_0;
SET_CURRENT_CACHED_VALUES(3);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}

View file

@ -8284,6 +8284,8 @@
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef o;
_PyStackRef value;
_PyStackRef *null;
/* Skip 1 cache entry */
// _GUARD_TYPE_VERSION
@ -8320,11 +8322,14 @@
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
STAT_INC(LOAD_ATTR, hit);
o = owner;
}
// _POP_TOP
{
value = o;
stack_pointer[-1] = attr;
_PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = owner;
owner = attr;
stack_pointer[-1] = owner;
PyStackRef_CLOSE(tmp);
PyStackRef_XCLOSE(value);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
/* Skip 5 cache entries */

View file

@ -661,9 +661,10 @@ dummy_func(void) {
o = owner;
}
op(_LOAD_ATTR_SLOT, (index/1, owner -- attr)) {
op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, o)) {
attr = sym_new_not_null(ctx);
(void)index;
o = owner;
}
op(_LOAD_ATTR_CLASS, (descr/4, owner -- attr)) {

View file

@ -1666,11 +1666,19 @@
}
case _LOAD_ATTR_SLOT: {
JitOptRef owner;
JitOptRef attr;
JitOptRef o;
owner = stack_pointer[-1];
uint16_t index = (uint16_t)this_instr->operand0;
attr = sym_new_not_null(ctx);
(void)index;
o = owner;
CHECK_STACK_BOUNDS(1);
stack_pointer[-1] = attr;
stack_pointer[0] = o;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
break;
}