mirror of
https://github.com/python/cpython.git
synced 2025-07-08 03:45:36 +00:00
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:
parent
ab11c09705
commit
54965f3fb2
15 changed files with 615 additions and 1005 deletions
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue