mirror of https://github.com/python/cpython.git
gh-130373: Avoid locking in _LOAD_ATTR_WITH_HINT (#130372)
Avoid locking in _LOAD_ATTR_WITH_HINT
This commit is contained in:
parent
00f0771e4d
commit
2984ff9e51
|
@ -150,6 +150,10 @@ extern int _PyDict_Pop_KnownHash(
|
||||||
Py_hash_t hash,
|
Py_hash_t hash,
|
||||||
PyObject **result);
|
PyObject **result);
|
||||||
|
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
PyAPI_FUNC(void) _PyDict_EnsureSharedOnRead(PyDictObject *mp);
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DKIX_EMPTY (-1)
|
#define DKIX_EMPTY (-1)
|
||||||
#define DKIX_DUMMY (-2) /* Used internally */
|
#define DKIX_DUMMY (-2) /* Used internally */
|
||||||
#define DKIX_ERROR (-3)
|
#define DKIX_ERROR (-3)
|
||||||
|
|
|
@ -1326,6 +1326,12 @@ ensure_shared_on_read(PyDictObject *mp)
|
||||||
Py_END_CRITICAL_SECTION();
|
Py_END_CRITICAL_SECTION();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_PyDict_EnsureSharedOnRead(PyDictObject *mp)
|
||||||
|
{
|
||||||
|
ensure_shared_on_read(mp);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
|
@ -2283,34 +2283,36 @@ dummy_func(
|
||||||
assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
|
||||||
PyDictObject *dict = _PyObject_GetManagedDict(owner_o);
|
PyDictObject *dict = _PyObject_GetManagedDict(owner_o);
|
||||||
DEOPT_IF(dict == NULL);
|
DEOPT_IF(dict == NULL);
|
||||||
|
PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
|
||||||
assert(PyDict_CheckExact((PyObject *)dict));
|
assert(PyDict_CheckExact((PyObject *)dict));
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
DEOPT_IF(!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict));
|
||||||
|
#endif
|
||||||
PyObject *attr_o;
|
PyObject *attr_o;
|
||||||
if (!LOCK_OBJECT(dict)) {
|
if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) {
|
||||||
DEOPT_IF(true);
|
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);
|
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
|
||||||
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
|
if (dk->dk_kind != DICT_KEYS_UNICODE) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
DEOPT_IF(true);
|
DEOPT_IF(true);
|
||||||
}
|
}
|
||||||
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
|
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + hint;
|
||||||
if (ep->me_key != name) {
|
if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
DEOPT_IF(true);
|
DEOPT_IF(true);
|
||||||
}
|
}
|
||||||
attr_o = ep->me_value;
|
attr_o = FT_ATOMIC_LOAD_PTR(ep->me_value);
|
||||||
if (attr_o == NULL) {
|
if (attr_o == NULL) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
DEOPT_IF(true);
|
DEOPT_IF(true);
|
||||||
}
|
}
|
||||||
STAT_INC(LOAD_ATTR, hit);
|
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);
|
attr = PyStackRef_FromPyObjectNew(attr_o);
|
||||||
UNLOCK_OBJECT(dict);
|
#endif
|
||||||
PyStackRef_CLOSE(owner);
|
PyStackRef_CLOSE(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3209,48 +3209,53 @@
|
||||||
UOP_STAT_INC(uopcode, miss);
|
UOP_STAT_INC(uopcode, miss);
|
||||||
JUMP_TO_JUMP_TARGET();
|
JUMP_TO_JUMP_TARGET();
|
||||||
}
|
}
|
||||||
|
PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
|
||||||
assert(PyDict_CheckExact((PyObject *)dict));
|
assert(PyDict_CheckExact((PyObject *)dict));
|
||||||
PyObject *attr_o;
|
#ifdef Py_GIL_DISABLED
|
||||||
if (!LOCK_OBJECT(dict)) {
|
if (!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict)) {
|
||||||
if (true) {
|
UOP_STAT_INC(uopcode, miss);
|
||||||
UOP_STAT_INC(uopcode, miss);
|
JUMP_TO_JUMP_TARGET();
|
||||||
JUMP_TO_JUMP_TARGET();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (hint >= (size_t)dict->ma_keys->dk_nentries) {
|
#endif
|
||||||
UNLOCK_OBJECT(dict);
|
PyObject *attr_o;
|
||||||
|
if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) {
|
||||||
if (true) {
|
if (true) {
|
||||||
UOP_STAT_INC(uopcode, miss);
|
UOP_STAT_INC(uopcode, miss);
|
||||||
JUMP_TO_JUMP_TARGET();
|
JUMP_TO_JUMP_TARGET();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
|
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
|
||||||
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
|
if (dk->dk_kind != DICT_KEYS_UNICODE) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
if (true) {
|
if (true) {
|
||||||
UOP_STAT_INC(uopcode, miss);
|
UOP_STAT_INC(uopcode, miss);
|
||||||
JUMP_TO_JUMP_TARGET();
|
JUMP_TO_JUMP_TARGET();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
|
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + hint;
|
||||||
if (ep->me_key != name) {
|
if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
if (true) {
|
if (true) {
|
||||||
UOP_STAT_INC(uopcode, miss);
|
UOP_STAT_INC(uopcode, miss);
|
||||||
JUMP_TO_JUMP_TARGET();
|
JUMP_TO_JUMP_TARGET();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attr_o = ep->me_value;
|
attr_o = FT_ATOMIC_LOAD_PTR(ep->me_value);
|
||||||
if (attr_o == NULL) {
|
if (attr_o == NULL) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
if (true) {
|
if (true) {
|
||||||
UOP_STAT_INC(uopcode, miss);
|
UOP_STAT_INC(uopcode, miss);
|
||||||
JUMP_TO_JUMP_TARGET();
|
JUMP_TO_JUMP_TARGET();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STAT_INC(LOAD_ATTR, hit);
|
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);
|
attr = PyStackRef_FromPyObjectNew(attr_o);
|
||||||
UNLOCK_OBJECT(dict);
|
#endif
|
||||||
stack_pointer[-1] = attr;
|
stack_pointer[-1] = attr;
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||||
PyStackRef_CLOSE(owner);
|
PyStackRef_CLOSE(owner);
|
||||||
|
|
|
@ -8618,17 +8618,17 @@
|
||||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||||
}
|
}
|
||||||
|
PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
|
||||||
assert(PyDict_CheckExact((PyObject *)dict));
|
assert(PyDict_CheckExact((PyObject *)dict));
|
||||||
PyObject *attr_o;
|
#ifdef Py_GIL_DISABLED
|
||||||
if (!LOCK_OBJECT(dict)) {
|
if (!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict)) {
|
||||||
if (true) {
|
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (hint >= (size_t)dict->ma_keys->dk_nentries) {
|
#endif
|
||||||
UNLOCK_OBJECT(dict);
|
PyObject *attr_o;
|
||||||
|
if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) {
|
||||||
if (true) {
|
if (true) {
|
||||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||||
|
@ -8636,26 +8636,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
|
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
|
||||||
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
|
if (dk->dk_kind != DICT_KEYS_UNICODE) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
if (true) {
|
if (true) {
|
||||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||||
JUMP_TO_PREDICTED(LOAD_ATTR);
|
JUMP_TO_PREDICTED(LOAD_ATTR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
|
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + hint;
|
||||||
if (ep->me_key != name) {
|
if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
if (true) {
|
if (true) {
|
||||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||||
JUMP_TO_PREDICTED(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) {
|
if (attr_o == NULL) {
|
||||||
UNLOCK_OBJECT(dict);
|
|
||||||
if (true) {
|
if (true) {
|
||||||
UPDATE_MISS_STATS(LOAD_ATTR);
|
UPDATE_MISS_STATS(LOAD_ATTR);
|
||||||
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
assert(_PyOpcode_Deopt[opcode] == (LOAD_ATTR));
|
||||||
|
@ -8663,8 +8660,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STAT_INC(LOAD_ATTR, hit);
|
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);
|
attr = PyStackRef_FromPyObjectNew(attr_o);
|
||||||
UNLOCK_OBJECT(dict);
|
#endif
|
||||||
stack_pointer[-1] = attr;
|
stack_pointer[-1] = attr;
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||||
PyStackRef_CLOSE(owner);
|
PyStackRef_CLOSE(owner);
|
||||||
|
|
|
@ -1009,6 +1009,9 @@ specialize_dict_access_hint(
|
||||||
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
|
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
|
||||||
|
|
||||||
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict);
|
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict);
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
_PyDict_EnsureSharedOnRead(dict);
|
||||||
|
#endif
|
||||||
|
|
||||||
// We found an instance with a __dict__.
|
// We found an instance with a __dict__.
|
||||||
if (_PyDict_HasSplitTable(dict)) {
|
if (_PyDict_HasSplitTable(dict)) {
|
||||||
|
|
Loading…
Reference in New Issue