gh-130373: Avoid locking in _LOAD_ATTR_WITH_HINT (#130372)

Avoid locking in _LOAD_ATTR_WITH_HINT
This commit is contained in:
Dino Viehland 2025-03-28 15:16:41 -07:00 committed by GitHub
parent 00f0771e4d
commit 2984ff9e51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 72 additions and 46 deletions

View File

@ -150,6 +150,10 @@ extern int _PyDict_Pop_KnownHash(
Py_hash_t hash,
PyObject **result);
#ifdef Py_GIL_DISABLED
PyAPI_FUNC(void) _PyDict_EnsureSharedOnRead(PyDictObject *mp);
#endif
#define DKIX_EMPTY (-1)
#define DKIX_DUMMY (-2) /* Used internally */
#define DKIX_ERROR (-3)

View File

@ -1326,6 +1326,12 @@ ensure_shared_on_read(PyDictObject *mp)
Py_END_CRITICAL_SECTION();
}
}
void
_PyDict_EnsureSharedOnRead(PyDictObject *mp)
{
ensure_shared_on_read(mp);
}
#endif
static inline void

View File

@ -2283,34 +2283,36 @@ dummy_func(
assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictObject *dict = _PyObject_GetManagedDict(owner_o);
DEOPT_IF(dict == NULL);
PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
assert(PyDict_CheckExact((PyObject *)dict));
#ifdef Py_GIL_DISABLED
DEOPT_IF(!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict));
#endif
PyObject *attr_o;
if (!LOCK_OBJECT(dict)) {
if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) {
DEOPT_IF(true);
}
if (hint >= (size_t)dict->ma_keys->dk_nentries) {
UNLOCK_OBJECT(dict);
DEOPT_IF(true);
}
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
UNLOCK_OBJECT(dict);
if (dk->dk_kind != DICT_KEYS_UNICODE) {
DEOPT_IF(true);
}
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
if (ep->me_key != name) {
UNLOCK_OBJECT(dict);
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + hint;
if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) {
DEOPT_IF(true);
}
attr_o = ep->me_value;
attr_o = FT_ATOMIC_LOAD_PTR(ep->me_value);
if (attr_o == NULL) {
UNLOCK_OBJECT(dict);
DEOPT_IF(true);
}
STAT_INC(LOAD_ATTR, hit);
#ifdef Py_GIL_DISABLED
if (!_Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr)) {
DEOPT_IF(true);
}
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
UNLOCK_OBJECT(dict);
#endif
PyStackRef_CLOSE(owner);
}

View File

@ -3209,48 +3209,53 @@
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
assert(PyDict_CheckExact((PyObject *)dict));
PyObject *attr_o;
if (!LOCK_OBJECT(dict)) {
if (true) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
#ifdef Py_GIL_DISABLED
if (!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict)) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
if (hint >= (size_t)dict->ma_keys->dk_nentries) {
UNLOCK_OBJECT(dict);
#endif
PyObject *attr_o;
if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) {
if (true) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
}
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
UNLOCK_OBJECT(dict);
if (dk->dk_kind != DICT_KEYS_UNICODE) {
if (true) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
}
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
if (ep->me_key != name) {
UNLOCK_OBJECT(dict);
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + hint;
if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) {
if (true) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
}
attr_o = ep->me_value;
attr_o = FT_ATOMIC_LOAD_PTR(ep->me_value);
if (attr_o == NULL) {
UNLOCK_OBJECT(dict);
if (true) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
}
STAT_INC(LOAD_ATTR, hit);
#ifdef Py_GIL_DISABLED
if (!_Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr)) {
if (true) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
}
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
UNLOCK_OBJECT(dict);
#endif
stack_pointer[-1] = attr;
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(owner);

View File

@ -8618,17 +8618,17 @@
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
JUMP_TO_PREDICTED(LOAD_ATTR);
}
PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
assert(PyDict_CheckExact((PyObject *)dict));
PyObject *attr_o;
if (!LOCK_OBJECT(dict)) {
if (true) {
UPDATE_MISS_STATS(LOAD_ATTR);
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
JUMP_TO_PREDICTED(LOAD_ATTR);
}
#ifdef Py_GIL_DISABLED
if (!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict)) {
UPDATE_MISS_STATS(LOAD_ATTR);
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
JUMP_TO_PREDICTED(LOAD_ATTR);
}
if (hint >= (size_t)dict->ma_keys->dk_nentries) {
UNLOCK_OBJECT(dict);
#endif
PyObject *attr_o;
if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) {
if (true) {
UPDATE_MISS_STATS(LOAD_ATTR);
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
@ -8636,26 +8636,23 @@
}
}
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
UNLOCK_OBJECT(dict);
if (dk->dk_kind != DICT_KEYS_UNICODE) {
if (true) {
UPDATE_MISS_STATS(LOAD_ATTR);
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
JUMP_TO_PREDICTED(LOAD_ATTR);
}
}
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
if (ep->me_key != name) {
UNLOCK_OBJECT(dict);
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + hint;
if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) {
if (true) {
UPDATE_MISS_STATS(LOAD_ATTR);
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
JUMP_TO_PREDICTED(LOAD_ATTR);
}
}
attr_o = ep->me_value;
attr_o = FT_ATOMIC_LOAD_PTR(ep->me_value);
if (attr_o == NULL) {
UNLOCK_OBJECT(dict);
if (true) {
UPDATE_MISS_STATS(LOAD_ATTR);
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
@ -8663,8 +8660,17 @@
}
}
STAT_INC(LOAD_ATTR, hit);
#ifdef Py_GIL_DISABLED
if (!_Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr)) {
if (true) {
UPDATE_MISS_STATS(LOAD_ATTR);
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
JUMP_TO_PREDICTED(LOAD_ATTR);
}
}
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
UNLOCK_OBJECT(dict);
#endif
stack_pointer[-1] = attr;
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(owner);

View File

@ -1009,6 +1009,9 @@ specialize_dict_access_hint(
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict);
#ifdef Py_GIL_DISABLED
_PyDict_EnsureSharedOnRead(dict);
#endif
// We found an instance with a __dict__.
if (_PyDict_HasSplitTable(dict)) {