Skip to content

Commit 2984ff9

Browse files
authored
gh-130373: Avoid locking in _LOAD_ATTR_WITH_HINT (#130372)
Avoid locking in _LOAD_ATTR_WITH_HINT
1 parent 00f0771 commit 2984ff9

File tree

6 files changed

+67
-41
lines changed

6 files changed

+67
-41
lines changed

Include/internal/pycore_dict.h

+4
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ extern int _PyDict_Pop_KnownHash(
150150
Py_hash_t hash,
151151
PyObject **result);
152152

153+
#ifdef Py_GIL_DISABLED
154+
PyAPI_FUNC(void) _PyDict_EnsureSharedOnRead(PyDictObject *mp);
155+
#endif
156+
153157
#define DKIX_EMPTY (-1)
154158
#define DKIX_DUMMY (-2) /* Used internally */
155159
#define DKIX_ERROR (-3)

Objects/dictobject.c

+6
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,12 @@ ensure_shared_on_read(PyDictObject *mp)
13261326
Py_END_CRITICAL_SECTION();
13271327
}
13281328
}
1329+
1330+
void
1331+
_PyDict_EnsureSharedOnRead(PyDictObject *mp)
1332+
{
1333+
ensure_shared_on_read(mp);
1334+
}
13291335
#endif
13301336

13311337
static inline void

Python/bytecodes.c

+15-13
Original file line numberDiff line numberDiff line change
@@ -2283,34 +2283,36 @@ dummy_func(
22832283
assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
22842284
PyDictObject *dict = _PyObject_GetManagedDict(owner_o);
22852285
DEOPT_IF(dict == NULL);
2286+
PyDictKeysObject *dk = FT_ATOMIC_LOAD_PTR(dict->ma_keys);
22862287
assert(PyDict_CheckExact((PyObject *)dict));
2288+
#ifdef Py_GIL_DISABLED
2289+
DEOPT_IF(!_Py_IsOwnedByCurrentThread((PyObject *)dict) && !_PyObject_GC_IS_SHARED(dict));
2290+
#endif
22872291
PyObject *attr_o;
2288-
if (!LOCK_OBJECT(dict)) {
2292+
if (hint >= (size_t)FT_ATOMIC_LOAD_SSIZE_RELAXED(dk->dk_nentries)) {
22892293
DEOPT_IF(true);
22902294
}
22912295

2292-
if (hint >= (size_t)dict->ma_keys->dk_nentries) {
2293-
UNLOCK_OBJECT(dict);
2294-
DEOPT_IF(true);
2295-
}
22962296
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
2297-
if (dict->ma_keys->dk_kind != DICT_KEYS_UNICODE) {
2298-
UNLOCK_OBJECT(dict);
2297+
if (dk->dk_kind != DICT_KEYS_UNICODE) {
22992298
DEOPT_IF(true);
23002299
}
2301-
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
2302-
if (ep->me_key != name) {
2303-
UNLOCK_OBJECT(dict);
2300+
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dk) + hint;
2301+
if (FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key) != name) {
23042302
DEOPT_IF(true);
23052303
}
2306-
attr_o = ep->me_value;
2304+
attr_o = FT_ATOMIC_LOAD_PTR(ep->me_value);
23072305
if (attr_o == NULL) {
2308-
UNLOCK_OBJECT(dict);
23092306
DEOPT_IF(true);
23102307
}
23112308
STAT_INC(LOAD_ATTR, hit);
2309+
#ifdef Py_GIL_DISABLED
2310+
if (!_Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr)) {
2311+
DEOPT_IF(true);
2312+
}
2313+
#else
23122314
attr = PyStackRef_FromPyObjectNew(attr_o);
2313-
UNLOCK_OBJECT(dict);
2315+
#endif
23142316
PyStackRef_CLOSE(owner);
23152317
}
23162318

Python/executor_cases.c.h

+19-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

+20-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

+3
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,9 @@ specialize_dict_access_hint(
10091009
_PyAttrCache *cache = (_PyAttrCache *)(instr + 1);
10101010

10111011
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(dict);
1012+
#ifdef Py_GIL_DISABLED
1013+
_PyDict_EnsureSharedOnRead(dict);
1014+
#endif
10121015

10131016
// We found an instance with a __dict__.
10141017
if (_PyDict_HasSplitTable(dict)) {

0 commit comments

Comments
 (0)