aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/executor_cases.c.h
diff options
context:
space:
mode:
authormpage <mpage@meta.com>2024-12-13 10:17:16 -0800
committerGitHub <noreply@github.com>2024-12-13 10:17:16 -0800
commit2de048ce79e621f5ae0574095b9600fe8595f607 (patch)
treede3116284fc2016192787297de7a67ba348e5825 /Python/executor_cases.c.h
parent292067fbc9db81896c16ff12d51c21d2b0f233e2 (diff)
downloadcpython-2de048ce79e621f5ae0574095b9600fe8595f607.tar.gz
cpython-2de048ce79e621f5ae0574095b9600fe8595f607.zip
gh-115999: Specialize loading attributes from modules in free-threaded builds (#127711)
We use the same approach that was used for specialization of LOAD_GLOBAL in free-threaded builds: _CHECK_ATTR_MODULE is renamed to _CHECK_ATTR_MODULE_PUSH_KEYS; it pushes the keys object for the following _LOAD_ATTR_MODULE_FROM_KEYS (nee _LOAD_ATTR_MODULE). This arrangement avoids having to recheck the keys version. _LOAD_ATTR_MODULE is renamed to _LOAD_ATTR_MODULE_FROM_KEYS; it loads the value from the keys object pushed by the preceding _CHECK_ATTR_MODULE_PUSH_KEYS at the cached index.
Diffstat (limited to 'Python/executor_cases.c.h')
-rw-r--r--Python/executor_cases.c.h70
1 files changed, 59 insertions, 11 deletions
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 19ba67a8af6..55e9c3aa2db 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -2641,8 +2641,9 @@
/* _LOAD_ATTR_INSTANCE_VALUE is split on (oparg & 1) */
- case _CHECK_ATTR_MODULE: {
+ case _CHECK_ATTR_MODULE_PUSH_KEYS: {
_PyStackRef owner;
+ PyDictKeysObject *mod_keys;
owner = stack_pointer[-1];
uint32_t dict_version = (uint32_t)CURRENT_OPERAND0();
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
@@ -2652,33 +2653,51 @@
}
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict;
assert(dict != NULL);
- if (dict->ma_keys->dk_version != dict_version) {
+ PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(dict->ma_keys);
+ if (FT_ATOMIC_LOAD_UINT32_RELAXED(keys->dk_version) != dict_version) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
+ mod_keys = keys;
+ stack_pointer[0].bits = (uintptr_t)mod_keys;
+ stack_pointer += 1;
+ assert(WITHIN_STACK_BOUNDS());
break;
}
- case _LOAD_ATTR_MODULE: {
+ case _LOAD_ATTR_MODULE_FROM_KEYS: {
+ PyDictKeysObject *mod_keys;
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef null = PyStackRef_NULL;
oparg = CURRENT_OPARG();
- owner = stack_pointer[-1];
+ mod_keys = (PyDictKeysObject *)stack_pointer[-1].bits;
+ owner = stack_pointer[-2];
uint16_t index = (uint16_t)CURRENT_OPERAND0();
- PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
- PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict;
- assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
- assert(index < dict->ma_keys->dk_nentries);
- PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index;
- PyObject *attr_o = ep->me_value;
+ assert(mod_keys->dk_kind == DICT_KEYS_UNICODE);
+ assert(index < FT_ATOMIC_LOAD_SSIZE_RELAXED(mod_keys->dk_nentries));
+ PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mod_keys) + index;
+ PyObject *attr_o = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_value);
+ // Clear mod_keys from stack in case we need to deopt
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
if (attr_o == NULL) {
UOP_STAT_INC(uopcode, miss);
JUMP_TO_JUMP_TARGET();
}
- STAT_INC(LOAD_ATTR, hit);
+ #ifdef Py_GIL_DISABLED
+ int increfed = _Py_TryIncrefCompareStackRef(&ep->me_value, attr_o, &attr);
+ if (!increfed) {
+ if (true) {
+ UOP_STAT_INC(uopcode, miss);
+ JUMP_TO_JUMP_TARGET();
+ }
+ }
+ #else
Py_INCREF(attr_o);
attr = PyStackRef_FromPyObjectSteal(attr_o);
+ #endif
+ STAT_INC(LOAD_ATTR, hit);
null = PyStackRef_NULL;
PyStackRef_CLOSE(owner);
stack_pointer[-1] = attr;
@@ -5928,6 +5947,35 @@
break;
}
+ case _LOAD_ATTR_MODULE: {
+ _PyStackRef owner;
+ _PyStackRef attr;
+ _PyStackRef null = PyStackRef_NULL;
+ oparg = CURRENT_OPARG();
+ owner = stack_pointer[-1];
+ uint16_t index = (uint16_t)CURRENT_OPERAND0();
+ PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
+ PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner_o)->md_dict;
+ assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
+ assert(index < dict->ma_keys->dk_nentries);
+ PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + index;
+ PyObject *attr_o = ep->me_value;
+ if (attr_o == NULL) {
+ UOP_STAT_INC(uopcode, miss);
+ JUMP_TO_JUMP_TARGET();
+ }
+ STAT_INC(LOAD_ATTR, hit);
+ Py_INCREF(attr_o);
+ attr = PyStackRef_FromPyObjectSteal(attr_o);
+ null = PyStackRef_NULL;
+ PyStackRef_CLOSE(owner);
+ stack_pointer[-1] = attr;
+ if (oparg & 1) stack_pointer[0] = null;
+ stack_pointer += (oparg & 1);
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
+
case _INTERNAL_INCREMENT_OPT_COUNTER: {
_PyStackRef opt;
opt = stack_pointer[-1];