Skip to content

Commit 30962c4

Browse files
committed
Specialize LOAD_ATTR_MODULE in free-threaded builds
1 parent e991ac8 commit 30962c4

File tree

10 files changed

+294
-154
lines changed

10 files changed

+294
-154
lines changed

Include/internal/pycore_opcode_metadata.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_ids.h

Lines changed: 71 additions & 70 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 10 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2069,7 +2069,7 @@ dummy_func(
20692069
};
20702070

20712071
specializing op(_SPECIALIZE_LOAD_ATTR, (counter/1, owner -- owner)) {
2072-
#if ENABLE_SPECIALIZATION
2072+
#if ENABLE_SPECIALIZATION_FT
20732073
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
20742074
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg>>1);
20752075
next_instr = this_instr;
@@ -2078,7 +2078,7 @@ dummy_func(
20782078
}
20792079
OPCODE_DEFERRED_INC(LOAD_ATTR);
20802080
ADVANCE_ADAPTIVE_COUNTER(this_instr[1].counter);
2081-
#endif /* ENABLE_SPECIALIZATION */
2081+
#endif /* ENABLE_SPECIALIZATION_FT */
20822082
}
20832083

20842084
op(_LOAD_ATTR, (owner -- attr, self_or_null if (oparg & 1))) {
@@ -2157,33 +2157,44 @@ dummy_func(
21572157
_LOAD_ATTR_INSTANCE_VALUE +
21582158
unused/5; // Skip over rest of cache
21592159

2160-
op(_CHECK_ATTR_MODULE, (dict_version/2, owner -- owner)) {
2160+
op(_CHECK_ATTR_MODULE_PUSH_KEYS, (dict_version/2, owner -- owner, mod_keys: PyDictKeysObject *)) {
21612161
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
21622162
DEOPT_IF(Py_TYPE(owner_o)->tp_getattro != PyModule_Type.tp_getattro);
21632163
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict;
21642164
assert(dict != NULL);
2165-
DEOPT_IF(dict->ma_keys->dk_version != dict_version);
2165+
PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys);
2166+
DEOPT_IF(FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version);
2167+
mod_keys = keys;
21662168
}
21672169

2168-
op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) {
2169-
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
2170-
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict;
2171-
assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
2172-
assert(index < dict->ma_keys->dk_nentries);
2173-
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index;
2174-
PyObject *attr_o = ep->me_value;
2170+
op(_LOAD_ATTR_MODULE_FROM_KEYS, (index/1, owner, mod_keys: PyDictKeysObject* -- attr, null if (oparg & 1))) {
2171+
assert(mod_keys->dk_kind == DICT_KEYS_UNICODE);
2172+
assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(mod_keys->dk_nentries));
2173+
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mod_keys) + index;
2174+
PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value);
2175+
DEAD(mod_keys);
2176+
// Clear mod_keys from stack in case we need to deopt
2177+
SAVE_STACK();
2178+
RELOAD_STACK();
21752179
DEOPT_IF(attr_o == NULL);
2176-
STAT_INC(LOAD_ATTR, hit);
2180+
#ifdef Py_GIL_DISABLED
2181+
int increfed = _Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr);
2182+
if (!increfed) {
2183+
DEOPT_IF(true);
2184+
}
2185+
#else
21772186
Py_INCREF(attr_o);
21782187
attr = PyStackRef_FromPyObjectSteal(attr_o);
2188+
#endif
2189+
STAT_INC(LOAD_ATTR, hit);
21792190
null = PyStackRef_NULL;
2180-
DECREF_INPUTS();
2191+
PyStackRef_CLOSE(owner);
21812192
}
21822193

21832194
macro(LOAD_ATTR_MODULE) =
21842195
unused/1 +
2185-
_CHECK_ATTR_MODULE +
2186-
_LOAD_ATTR_MODULE +
2196+
_CHECK_ATTR_MODULE_PUSH_KEYS +
2197+
_LOAD_ATTR_MODULE_FROM_KEYS +
21872198
unused/5;
21882199

21892200
op(_CHECK_ATTR_WITH_HINT, (owner -- owner)) {
@@ -4961,6 +4972,21 @@ dummy_func(
49614972
null = PyStackRef_NULL;
49624973
}
49634974

4975+
tier2 op(_LOAD_ATTR_MODULE, (index/1, owner -- attr, null if (oparg & 1))) {
4976+
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
4977+
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict;
4978+
assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
4979+
assert(index < dict->ma_keys->dk_nentries);
4980+
PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index;
4981+
PyObject *attr_o = ep->me_value;
4982+
DEOPT_IF(attr_o == NULL);
4983+
STAT_INC(LOAD_ATTR, hit);
4984+
Py_INCREF(attr_o);
4985+
attr = PyStackRef_FromPyObjectSteal(attr_o);
4986+
null = PyStackRef_NULL;
4987+
DECREF_INPUTS();
4988+
}
4989+
49644990
/* Internal -- for testing executors */
49654991
op(_INTERNAL_INCREMENT_OPT_COUNTER, (opt --)) {
49664992
_PyCounterOptimizerObject *exe = (_PyCounterOptimizerObject *)PyStackRef_AsPyObjectBorrow(opt);

0 commit comments

Comments
 (0)