mirror of
https://github.com/python/cpython.git
synced 2024-11-23 18:04:37 +08:00
GH-111485: Mark some instructions as TIER_ONE_ONLY
(GH-113155)
This commit is contained in:
parent
55ef998a8d
commit
737d23ffcd
@ -506,6 +506,7 @@ dummy_func(
|
||||
// specializations, but there is no output.
|
||||
// At the end we just skip over the STORE_FAST.
|
||||
op(_BINARY_OP_INPLACE_ADD_UNICODE, (unused/1, left, right --)) {
|
||||
TIER_ONE_ONLY
|
||||
assert(next_instr->op.code == STORE_FAST);
|
||||
PyObject **target_local = &GETLOCAL(next_instr->op.arg);
|
||||
DEOPT_IF(*target_local != left);
|
||||
@ -786,6 +787,7 @@ dummy_func(
|
||||
}
|
||||
|
||||
inst(INTERPRETER_EXIT, (retval --)) {
|
||||
TIER_ONE_ONLY
|
||||
assert(frame == &entry_frame);
|
||||
assert(_PyFrame_IsIncomplete(frame));
|
||||
/* Restore previous frame and return. */
|
||||
@ -1072,6 +1074,7 @@ dummy_func(
|
||||
}
|
||||
|
||||
inst(YIELD_VALUE, (retval -- unused)) {
|
||||
TIER_ONE_ONLY
|
||||
// NOTE: It's important that YIELD_VALUE never raises an exception!
|
||||
// The compiler treats any exception raised here as a failed close()
|
||||
// or throw() call.
|
||||
@ -2297,6 +2300,7 @@ dummy_func(
|
||||
}
|
||||
|
||||
inst(JUMP_FORWARD, (--)) {
|
||||
TIER_ONE_ONLY
|
||||
JUMPBY(oparg);
|
||||
}
|
||||
|
||||
@ -2402,6 +2406,7 @@ dummy_func(
|
||||
macro(POP_JUMP_IF_NOT_NONE) = _IS_NONE + _POP_JUMP_IF_FALSE;
|
||||
|
||||
inst(JUMP_BACKWARD_NO_INTERRUPT, (--)) {
|
||||
TIER_ONE_ONLY
|
||||
/* This bytecode is used in the `yield from` or `await` loop.
|
||||
* If there is an interrupt, we want it handled in the innermost
|
||||
* generator or coroutine, so we deliberately do not check it here.
|
||||
@ -3454,6 +3459,7 @@ dummy_func(
|
||||
|
||||
// This is secretly a super-instruction
|
||||
inst(CALL_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused)) {
|
||||
TIER_ONE_ONLY
|
||||
assert(oparg == 1);
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
DEOPT_IF(callable != interp->callable_cache.list_append);
|
||||
@ -3792,6 +3798,7 @@ dummy_func(
|
||||
}
|
||||
|
||||
inst(RETURN_GENERATOR, (--)) {
|
||||
TIER_ONE_ONLY
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
|
139
Python/executor_cases.c.h
generated
139
Python/executor_cases.c.h
generated
@ -375,38 +375,6 @@
|
||||
break;
|
||||
}
|
||||
|
||||
case _BINARY_OP_INPLACE_ADD_UNICODE: {
|
||||
PyObject *right;
|
||||
PyObject *left;
|
||||
right = stack_pointer[-1];
|
||||
left = stack_pointer[-2];
|
||||
assert(next_instr->op.code == STORE_FAST);
|
||||
PyObject **target_local = &GETLOCAL(next_instr->op.arg);
|
||||
if (*target_local != left) goto deoptimize;
|
||||
STAT_INC(BINARY_OP, hit);
|
||||
/* Handle `left = left + right` or `left += right` for str.
|
||||
*
|
||||
* When possible, extend `left` in place rather than
|
||||
* allocating a new PyUnicodeObject. This attempts to avoid
|
||||
* quadratic behavior when one neglects to use str.join().
|
||||
*
|
||||
* If `left` has only two references remaining (one from
|
||||
* the stack, one in the locals), DECREFing `left` leaves
|
||||
* only the locals reference, so PyUnicode_Append knows
|
||||
* that the string is safe to mutate.
|
||||
*/
|
||||
assert(Py_REFCNT(left) >= 2);
|
||||
_Py_DECREF_NO_DEALLOC(left);
|
||||
PyUnicode_Append(target_local, right);
|
||||
_Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
|
||||
if (*target_local == NULL) goto pop_2_error_tier_two;
|
||||
// The STORE_FAST is already done.
|
||||
assert(next_instr->op.code == STORE_FAST);
|
||||
SKIP_OVER(1);
|
||||
stack_pointer += -2;
|
||||
break;
|
||||
}
|
||||
|
||||
case _BINARY_SUBSCR: {
|
||||
PyObject *sub;
|
||||
PyObject *container;
|
||||
@ -690,18 +658,6 @@
|
||||
break;
|
||||
}
|
||||
|
||||
case _INTERPRETER_EXIT: {
|
||||
PyObject *retval;
|
||||
retval = stack_pointer[-1];
|
||||
assert(frame == &entry_frame);
|
||||
assert(_PyFrame_IsIncomplete(frame));
|
||||
/* Restore previous frame and return. */
|
||||
tstate->current_frame = frame->previous;
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
|
||||
return retval;
|
||||
}
|
||||
|
||||
case _POP_FRAME: {
|
||||
PyObject *retval;
|
||||
retval = stack_pointer[-1];
|
||||
@ -846,33 +802,6 @@
|
||||
|
||||
/* _INSTRUMENTED_YIELD_VALUE is not a viable micro-op for tier 2 */
|
||||
|
||||
case _YIELD_VALUE: {
|
||||
PyObject *retval;
|
||||
oparg = CURRENT_OPARG();
|
||||
retval = stack_pointer[-1];
|
||||
// NOTE: It's important that YIELD_VALUE never raises an exception!
|
||||
// The compiler treats any exception raised here as a failed close()
|
||||
// or throw() call.
|
||||
assert(frame != &entry_frame);
|
||||
frame->instr_ptr = next_instr;
|
||||
PyGenObject *gen = _PyFrame_GetGenerator(frame);
|
||||
assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1);
|
||||
assert(oparg == 0 || oparg == 1);
|
||||
gen->gi_frame_state = FRAME_SUSPENDED + oparg;
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer - 1);
|
||||
tstate->exc_info = gen->gi_exc_state.previous_item;
|
||||
gen->gi_exc_state.previous_item = NULL;
|
||||
_Py_LeaveRecursiveCallPy(tstate);
|
||||
_PyInterpreterFrame *gen_frame = frame;
|
||||
frame = tstate->current_frame = frame->previous;
|
||||
gen_frame->previous = NULL;
|
||||
_PyFrame_StackPush(frame, retval);
|
||||
/* We don't know which of these is relevant here, so keep them equal */
|
||||
assert(INLINE_CACHE_ENTRIES_SEND == INLINE_CACHE_ENTRIES_FOR_ITER);
|
||||
LOAD_IP(1 + INLINE_CACHE_ENTRIES_SEND);
|
||||
goto resume_frame;
|
||||
}
|
||||
|
||||
case _POP_EXCEPT: {
|
||||
PyObject *exc_value;
|
||||
exc_value = stack_pointer[-1];
|
||||
@ -2084,12 +2013,6 @@
|
||||
break;
|
||||
}
|
||||
|
||||
case _JUMP_FORWARD: {
|
||||
oparg = CURRENT_OPARG();
|
||||
JUMPBY(oparg);
|
||||
break;
|
||||
}
|
||||
|
||||
/* _JUMP_BACKWARD is not a viable micro-op for tier 2 */
|
||||
|
||||
/* _POP_JUMP_IF_FALSE is not a viable micro-op for tier 2 */
|
||||
@ -2111,17 +2034,6 @@
|
||||
break;
|
||||
}
|
||||
|
||||
case _JUMP_BACKWARD_NO_INTERRUPT: {
|
||||
oparg = CURRENT_OPARG();
|
||||
/* This bytecode is used in the `yield from` or `await` loop.
|
||||
* If there is an interrupt, we want it handled in the innermost
|
||||
* generator or coroutine, so we deliberately do not check it here.
|
||||
* (see bpo-30039).
|
||||
*/
|
||||
JUMPBY(-oparg);
|
||||
break;
|
||||
}
|
||||
|
||||
case _GET_LEN: {
|
||||
PyObject *obj;
|
||||
PyObject *len_o;
|
||||
@ -3060,32 +2972,6 @@
|
||||
break;
|
||||
}
|
||||
|
||||
case _CALL_LIST_APPEND: {
|
||||
PyObject **args;
|
||||
PyObject *self;
|
||||
PyObject *callable;
|
||||
oparg = CURRENT_OPARG();
|
||||
args = &stack_pointer[-oparg];
|
||||
self = stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
assert(oparg == 1);
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
if (callable != interp->callable_cache.list_append) goto deoptimize;
|
||||
assert(self != NULL);
|
||||
if (!PyList_Check(self)) goto deoptimize;
|
||||
STAT_INC(CALL, hit);
|
||||
if (_PyList_AppendTakeRef((PyListObject *)self, args[0]) < 0) {
|
||||
goto pop_1_error; // Since arg is DECREF'ed already
|
||||
}
|
||||
Py_DECREF(self);
|
||||
Py_DECREF(callable);
|
||||
STACK_SHRINK(3);
|
||||
// Skip POP_TOP
|
||||
assert(next_instr->op.code == POP_TOP);
|
||||
SKIP_OVER(1);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
case _CALL_METHOD_DESCRIPTOR_O: {
|
||||
PyObject **args;
|
||||
PyObject *self_or_null;
|
||||
@ -3307,31 +3193,6 @@
|
||||
break;
|
||||
}
|
||||
|
||||
case _RETURN_GENERATOR: {
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
if (gen == NULL) {
|
||||
GOTO_ERROR(error);
|
||||
}
|
||||
assert(EMPTY());
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
|
||||
frame->instr_ptr = next_instr;
|
||||
_PyFrame_Copy(frame, gen_frame);
|
||||
assert(frame->frame_obj == NULL);
|
||||
gen->gi_frame_state = FRAME_CREATED;
|
||||
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
|
||||
_Py_LeaveRecursiveCallPy(tstate);
|
||||
assert(frame != &entry_frame);
|
||||
_PyInterpreterFrame *prev = frame->previous;
|
||||
_PyThreadState_PopFrame(tstate, frame);
|
||||
frame = tstate->current_frame = prev;
|
||||
_PyFrame_StackPush(frame, (PyObject *)gen);
|
||||
LOAD_IP(frame->return_offset);
|
||||
goto resume_frame;
|
||||
}
|
||||
|
||||
case _BUILD_SLICE: {
|
||||
PyObject *step = NULL;
|
||||
PyObject *stop;
|
||||
|
7
Python/generated_cases.c.h
generated
7
Python/generated_cases.c.h
generated
@ -238,6 +238,7 @@
|
||||
}
|
||||
// _BINARY_OP_INPLACE_ADD_UNICODE
|
||||
{
|
||||
TIER_ONE_ONLY
|
||||
assert(next_instr->op.code == STORE_FAST);
|
||||
PyObject **target_local = &GETLOCAL(next_instr->op.arg);
|
||||
DEOPT_IF(*target_local != left, BINARY_OP);
|
||||
@ -1446,6 +1447,7 @@
|
||||
args = &stack_pointer[-oparg];
|
||||
self = stack_pointer[-1 - oparg];
|
||||
callable = stack_pointer[-2 - oparg];
|
||||
TIER_ONE_ONLY
|
||||
assert(oparg == 1);
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
DEOPT_IF(callable != interp->callable_cache.list_append, CALL);
|
||||
@ -3182,6 +3184,7 @@
|
||||
INSTRUCTION_STATS(INTERPRETER_EXIT);
|
||||
PyObject *retval;
|
||||
retval = stack_pointer[-1];
|
||||
TIER_ONE_ONLY
|
||||
assert(frame == &entry_frame);
|
||||
assert(_PyFrame_IsIncomplete(frame));
|
||||
/* Restore previous frame and return. */
|
||||
@ -3253,6 +3256,7 @@
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(JUMP_BACKWARD_NO_INTERRUPT);
|
||||
TIER_ONE_ONLY
|
||||
/* This bytecode is used in the `yield from` or `await` loop.
|
||||
* If there is an interrupt, we want it handled in the innermost
|
||||
* generator or coroutine, so we deliberately do not check it here.
|
||||
@ -3266,6 +3270,7 @@
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(JUMP_FORWARD);
|
||||
TIER_ONE_ONLY
|
||||
JUMPBY(oparg);
|
||||
DISPATCH();
|
||||
}
|
||||
@ -4793,6 +4798,7 @@
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(RETURN_GENERATOR);
|
||||
TIER_ONE_ONLY
|
||||
assert(PyFunction_Check(frame->f_funcobj));
|
||||
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
|
||||
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
|
||||
@ -5764,6 +5770,7 @@
|
||||
INSTRUCTION_STATS(YIELD_VALUE);
|
||||
PyObject *retval;
|
||||
retval = stack_pointer[-1];
|
||||
TIER_ONE_ONLY
|
||||
// NOTE: It's important that YIELD_VALUE never raises an exception!
|
||||
// The compiler treats any exception raised here as a failed close()
|
||||
// or throw() call.
|
||||
|
Loading…
Reference in New Issue
Block a user