mirror of
https://github.com/python/cpython.git
synced 2025-08-31 14:07:50 +00:00
gh-115999: Refactor LOAD_GLOBAL
specializations to avoid reloading {globals, builtins} keys (gh-124953)
Each of the `LOAD_GLOBAL` specializations is implemented roughly as: 1. Load keys version. 2. Load cached keys version. 3. Deopt if (1) and (2) don't match. 4. Load keys. 5. Load cached index into keys. 6. Load object from (4) at offset from (5). This is not thread-safe in free-threaded builds; the keys object may be replaced in between steps (3) and (4). This change refactors the specializations to avoid reloading the keys object and instead pass the keys object from guards to be consumed by downstream uops.
This commit is contained in:
parent
b9a8ca0a6a
commit
f978fb4f8d
9 changed files with 379 additions and 162 deletions
91
Python/executor_cases.c.h
generated
91
Python/executor_cases.c.h
generated
|
@ -1791,7 +1791,28 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BUILTINS_VERSION: {
|
||||
case _GUARD_GLOBALS_VERSION_PUSH_KEYS: {
|
||||
PyDictKeysObject *globals_keys;
|
||||
uint16_t version = (uint16_t)CURRENT_OPERAND();
|
||||
PyDictObject *dict = (PyDictObject *)GLOBALS();
|
||||
if (!PyDict_CheckExact(dict)) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
if (dict->ma_keys->dk_version != version) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
globals_keys = dict->ma_keys;
|
||||
assert(DK_IS_UNICODE(globals_keys));
|
||||
stack_pointer[0].bits = (uintptr_t)globals_keys;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
case _GUARD_BUILTINS_VERSION_PUSH_KEYS: {
|
||||
PyDictKeysObject *builtins_keys;
|
||||
uint16_t version = (uint16_t)CURRENT_OPERAND();
|
||||
PyDictObject *dict = (PyDictObject *)BUILTINS();
|
||||
if (!PyDict_CheckExact(dict)) {
|
||||
|
@ -1802,18 +1823,25 @@
|
|||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
assert(DK_IS_UNICODE(dict->ma_keys));
|
||||
builtins_keys = dict->ma_keys;
|
||||
assert(DK_IS_UNICODE(builtins_keys));
|
||||
stack_pointer[0].bits = (uintptr_t)builtins_keys;
|
||||
stack_pointer += 1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
case _LOAD_GLOBAL_MODULE: {
|
||||
case _LOAD_GLOBAL_MODULE_FROM_KEYS: {
|
||||
PyDictKeysObject *globals_keys;
|
||||
_PyStackRef res;
|
||||
_PyStackRef null = PyStackRef_NULL;
|
||||
oparg = CURRENT_OPARG();
|
||||
globals_keys = (PyDictKeysObject *)stack_pointer[-1].bits;
|
||||
uint16_t index = (uint16_t)CURRENT_OPERAND();
|
||||
PyDictObject *dict = (PyDictObject *)GLOBALS();
|
||||
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
|
||||
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(globals_keys);
|
||||
PyObject *res_o = entries[index].me_value;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
if (res_o == NULL) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
|
@ -1829,14 +1857,17 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _LOAD_GLOBAL_BUILTINS: {
|
||||
case _LOAD_GLOBAL_BUILTINS_FROM_KEYS: {
|
||||
PyDictKeysObject *builtins_keys;
|
||||
_PyStackRef res;
|
||||
_PyStackRef null = PyStackRef_NULL;
|
||||
oparg = CURRENT_OPARG();
|
||||
builtins_keys = (PyDictKeysObject *)stack_pointer[-1].bits;
|
||||
uint16_t index = (uint16_t)CURRENT_OPERAND();
|
||||
PyDictObject *bdict = (PyDictObject *)BUILTINS();
|
||||
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys);
|
||||
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(builtins_keys);
|
||||
PyObject *res_o = entries[index].me_value;
|
||||
stack_pointer += -1;
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
if (res_o == NULL) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
|
@ -5698,6 +5729,50 @@
|
|||
break;
|
||||
}
|
||||
|
||||
case _LOAD_GLOBAL_MODULE: {
|
||||
_PyStackRef res;
|
||||
_PyStackRef null = PyStackRef_NULL;
|
||||
oparg = CURRENT_OPARG();
|
||||
uint16_t index = (uint16_t)CURRENT_OPERAND();
|
||||
PyDictObject *dict = (PyDictObject *)GLOBALS();
|
||||
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
|
||||
PyObject *res_o = entries[index].me_value;
|
||||
if (res_o == NULL) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
Py_INCREF(res_o);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
null = PyStackRef_NULL;
|
||||
stack_pointer[0] = res;
|
||||
if (oparg & 1) stack_pointer[1] = null;
|
||||
stack_pointer += 1 + (oparg & 1);
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
case _LOAD_GLOBAL_BUILTINS: {
|
||||
_PyStackRef res;
|
||||
_PyStackRef null = PyStackRef_NULL;
|
||||
oparg = CURRENT_OPARG();
|
||||
uint16_t index = (uint16_t)CURRENT_OPERAND();
|
||||
PyDictObject *dict = (PyDictObject *)BUILTINS();
|
||||
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
|
||||
PyObject *res_o = entries[index].me_value;
|
||||
if (res_o == NULL) {
|
||||
UOP_STAT_INC(uopcode, miss);
|
||||
JUMP_TO_JUMP_TARGET();
|
||||
}
|
||||
Py_INCREF(res_o);
|
||||
res = PyStackRef_FromPyObjectSteal(res_o);
|
||||
null = PyStackRef_NULL;
|
||||
stack_pointer[0] = res;
|
||||
if (oparg & 1) stack_pointer[1] = null;
|
||||
stack_pointer += 1 + (oparg & 1);
|
||||
assert(WITHIN_STACK_BOUNDS());
|
||||
break;
|
||||
}
|
||||
|
||||
case _INTERNAL_INCREMENT_OPT_COUNTER: {
|
||||
_PyStackRef opt;
|
||||
opt = stack_pointer[-1];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue