GH-130296: Avoid stack transients in four instructions. (GH-130310)

* Combine _GUARD_GLOBALS_VERSION_PUSH_KEYS and _LOAD_GLOBAL_MODULE_FROM_KEYS into _LOAD_GLOBAL_MODULE

* Combine _GUARD_BUILTINS_VERSION_PUSH_KEYS and _LOAD_GLOBAL_BUILTINS_FROM_KEYS into _LOAD_GLOBAL_BUILTINS

* Combine _CHECK_ATTR_MODULE_PUSH_KEYS and _LOAD_ATTR_MODULE_FROM_KEYS into _LOAD_ATTR_MODULE

* Remove stack transient in LOAD_ATTR_WITH_HINT
This commit is contained in:
Mark Shannon 2025-02-28 18:00:38 +00:00 committed by GitHub
parent ab11c09705
commit 54965f3fb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 615 additions and 1005 deletions

View file

@ -93,26 +93,27 @@ type_watcher_callback(PyTypeObject* type)
}
static PyObject *
convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj)
convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool pop)
{
assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS || inst->opcode == _LOAD_ATTR_MODULE_FROM_KEYS);
assert(inst->opcode == _LOAD_GLOBAL_MODULE || inst->opcode == _LOAD_GLOBAL_BUILTINS || inst->opcode == _LOAD_ATTR_MODULE);
assert(PyDict_CheckExact(obj));
PyDictObject *dict = (PyDictObject *)obj;
assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
assert(inst->operand0 <= UINT16_MAX);
if ((int)inst->operand0 >= dict->ma_keys->dk_nentries) {
int64_t index = inst->operand1;
assert(index <= UINT16_MAX);
if ((int)index >= dict->ma_keys->dk_nentries) {
return NULL;
}
PyObject *res = entries[inst->operand0].me_value;
PyObject *res = entries[index].me_value;
if (res == NULL) {
return NULL;
}
if (_Py_IsImmortal(res)) {
inst->opcode = _LOAD_CONST_INLINE_BORROW;
inst->opcode = pop ? _POP_TOP_LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE_BORROW;
}
else {
inst->opcode = _LOAD_CONST_INLINE;
inst->opcode = pop ? _POP_TOP_LOAD_CONST_INLINE : _LOAD_CONST_INLINE;
}
if (inst->oparg & 1) {
assert(inst[1].opcode == _PUSH_NULL_CONDITIONAL);
@ -198,48 +199,12 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
_PyUOpInstruction *inst = &buffer[pc];
int opcode = inst->opcode;
switch(opcode) {
case _GUARD_BUILTINS_VERSION_PUSH_KEYS:
if (incorrect_keys(inst, builtins)) {
OPT_STAT_INC(remove_globals_incorrect_keys);
return 0;
}
if (interp->rare_events.builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
continue;
}
if (!check_next_uop(buffer, buffer_size, pc,
_LOAD_GLOBAL_BUILTINS_FROM_KEYS)) {
continue;
}
if ((builtins_watched & 1) == 0) {
PyDict_Watch(BUILTINS_WATCHER_ID, builtins);
builtins_watched |= 1;
}
if (function_checked & 1) {
buffer[pc].opcode = NOP;
}
else {
buffer[pc].opcode = _CHECK_FUNCTION;
buffer[pc].operand0 = function_version;
function_checked |= 1;
}
// We're no longer pushing the builtins keys; rewrite the
// instruction that consumed the keys to load them from the
// frame.
buffer[pc + 1].opcode = _LOAD_GLOBAL_BUILTINS;
break;
case _GUARD_GLOBALS_VERSION:
case _GUARD_GLOBALS_VERSION_PUSH_KEYS:
if (incorrect_keys(inst, globals)) {
OPT_STAT_INC(remove_globals_incorrect_keys);
return 0;
}
uint64_t watched_mutations = get_mutations(globals);
if (watched_mutations >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) {
continue;
}
if (opcode == _GUARD_GLOBALS_VERSION_PUSH_KEYS &&
!check_next_uop(buffer, buffer_size, pc,
_LOAD_GLOBAL_MODULE_FROM_KEYS)) {
if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) {
continue;
}
if ((globals_watched & 1) == 0) {
@ -255,21 +220,43 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
buffer[pc].operand0 = function_version;
function_checked |= 1;
}
if (opcode == _GUARD_GLOBALS_VERSION_PUSH_KEYS) {
// We're no longer pushing the globals keys; rewrite the
// instruction that consumed the keys to load them from the
// frame.
buffer[pc + 1].opcode = _LOAD_GLOBAL_MODULE;
}
break;
case _LOAD_GLOBAL_BUILTINS:
if (function_checked & globals_watched & builtins_watched & 1) {
convert_global_to_const(inst, builtins);
if (incorrect_keys(inst, builtins)) {
OPT_STAT_INC(remove_globals_incorrect_keys);
return 0;
}
if (interp->rare_events.builtin_dict >= _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS) {
continue;
}
if ((builtins_watched & 1) == 0) {
PyDict_Watch(BUILTINS_WATCHER_ID, builtins);
builtins_watched |= 1;
}
if (function_checked & globals_watched & 1) {
convert_global_to_const(inst, builtins, false);
}
break;
case _LOAD_GLOBAL_MODULE:
if (function_checked & globals_watched & 1) {
convert_global_to_const(inst, globals);
if (incorrect_keys(inst, globals)) {
OPT_STAT_INC(remove_globals_incorrect_keys);
return 0;
}
if (get_mutations(globals) >= _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS) {
continue;
}
if ((globals_watched & 1) == 0) {
PyDict_Watch(GLOBALS_WATCHER_ID, globals);
_Py_BloomFilter_Add(dependencies, globals);
globals_watched |= 1;
}
if ((function_checked & 1) == 0 && buffer[pc-1].opcode == _NOP) {
buffer[pc-1].opcode = _CHECK_FUNCTION;
buffer[pc-1].operand0 = function_version;
function_checked |= 1;
}
if (function_checked & 1) {
convert_global_to_const(inst, globals, false);
}
break;
case _PUSH_FRAME: