GH-96421: Insert shim frame on entry to interpreter (GH-96319)

* Adds EXIT_INTERPRETER instruction to exit PyEval_EvalDefault()

* Simplifies RETURN_VALUE, YIELD_VALUE and RETURN_GENERATOR instructions as they no longer need to check for entry frames.
This commit is contained in:
Mark Shannon 2022-11-10 04:34:57 -08:00 committed by GitHub
parent dbf2faf579
commit 1e197e63e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 450 additions and 346 deletions

View file

@ -611,6 +611,20 @@
goto error;
}
TARGET(INTERPRETER_EXIT) {
assert(frame == &entry_frame);
assert(_PyFrame_IsIncomplete(frame));
PyObject *retval = POP();
assert(EMPTY());
/* Restore previous cframe and return. */
tstate->cframe = cframe.previous;
tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
assert(!_PyErr_Occurred(tstate));
_Py_LeaveRecursiveCallTstate(tstate);
return retval;
}
TARGET(RETURN_VALUE) {
PyObject *retval = POP();
assert(EMPTY());
@ -618,23 +632,10 @@
TRACE_FUNCTION_EXIT();
DTRACE_FUNCTION_EXIT();
_Py_LeaveRecursiveCallPy(tstate);
if (!frame->is_entry) {
frame = cframe.current_frame = pop_frame(tstate, frame);
_PyFrame_StackPush(frame, retval);
goto resume_frame;
}
_Py_LeaveRecursiveCallTstate(tstate);
if (frame->owner == FRAME_OWNED_BY_GENERATOR) {
PyGenObject *gen = _PyFrame_GetGenerator(frame);
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
}
/* Restore previous cframe and return. */
tstate->cframe = cframe.previous;
tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
assert(!_PyErr_Occurred(tstate));
return retval;
assert(frame != &entry_frame);
frame = cframe.current_frame = pop_frame(tstate, frame);
_PyFrame_StackPush(frame, retval);
goto resume_frame;
}
TARGET(GET_AITER) {
@ -768,6 +769,7 @@
}
TARGET(SEND) {
assert(frame != &entry_frame);
assert(STACK_LEVEL() >= 2);
PyObject *v = POP();
PyObject *receiver = TOP();
@ -832,6 +834,7 @@
// The compiler treats any exception raised here as a failed close()
// or throw() call.
assert(oparg == STACK_LEVEL());
assert(frame != &entry_frame);
PyObject *retval = POP();
PyGenObject *gen = _PyFrame_GetGenerator(frame);
gen->gi_frame_state = FRAME_SUSPENDED;
@ -841,19 +844,12 @@
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
if (!frame->is_entry) {
frame = cframe.current_frame = frame->previous;
frame->prev_instr -= frame->yield_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
}
_Py_LeaveRecursiveCallTstate(tstate);
/* Restore previous cframe and return. */
tstate->cframe = cframe.previous;
tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
assert(!_PyErr_Occurred(tstate));
return retval;
_PyInterpreterFrame *gen_frame = frame;
frame = cframe.current_frame = frame->previous;
gen_frame->previous = NULL;
frame->prev_instr -= frame->yield_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
}
TARGET(POP_EXCEPT) {
@ -868,7 +864,7 @@
if (oparg) {
PyObject *lasti = PEEK(oparg + 1);
if (PyLong_Check(lasti)) {
frame->prev_instr = first_instr + PyLong_AsLong(lasti);
frame->prev_instr = _PyCode_CODE(frame->f_code) + PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate));
}
else {
@ -2690,7 +2686,6 @@
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
gen_frame->previous = frame;
gen_frame->is_entry = false;
frame = cframe.current_frame = gen_frame;
goto start_frame;
}
@ -2919,9 +2914,9 @@
}
TARGET(KW_NAMES) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
assert(oparg < PyTuple_GET_SIZE(consts));
call_shape.kwnames = GETITEM(consts, oparg);
kwnames = GETITEM(consts, oparg);
DISPATCH();
}
@ -2934,7 +2929,7 @@
int nargs = oparg + is_meth;
PyObject *callable = PEEK(nargs + 1);
next_instr--;
_Py_Specialize_Call(callable, next_instr, nargs, call_shape.kwnames);
_Py_Specialize_Call(callable, next_instr, nargs, kwnames);
DISPATCH_SAME_OPARG();
}
STAT_INC(CALL, deferred);
@ -2963,9 +2958,9 @@
STACK_SHRINK(total_args);
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
tstate, (PyFunctionObject *)function, locals,
stack_pointer, positional_args, call_shape.kwnames
stack_pointer, positional_args, kwnames
);
call_shape.kwnames = NULL;
kwnames = NULL;
STACK_SHRINK(2-is_meth);
// The frame has stolen all the arguments from the stack,
// so there is no need to clean them up.
@ -2985,15 +2980,15 @@
if (cframe.use_tracing) {
res = trace_call_function(
tstate, function, stack_pointer-total_args,
positional_args, call_shape.kwnames);
positional_args, kwnames);
}
else {
res = PyObject_Vectorcall(
function, stack_pointer-total_args,
positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
call_shape.kwnames);
kwnames);
}
call_shape.kwnames = NULL;
kwnames = NULL;
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(function);
/* Clear the stack */
@ -3013,7 +3008,7 @@
TARGET(CALL_PY_EXACT_ARGS) {
PREDICTED(CALL_PY_EXACT_ARGS);
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
DEOPT_IF(tstate->interp->eval_frame, CALL);
_PyCallCache *cache = (_PyCallCache *)next_instr;
int is_meth = is_method(stack_pointer, oparg);
@ -3045,7 +3040,7 @@
}
TARGET(CALL_PY_WITH_DEFAULTS) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
DEOPT_IF(tstate->interp->eval_frame, CALL);
_PyCallCache *cache = (_PyCallCache *)next_instr;
int is_meth = is_method(stack_pointer, oparg);
@ -3084,7 +3079,7 @@
}
TARGET(CALL_NO_KW_TYPE_1) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
assert(cframe.use_tracing == 0);
assert(oparg == 1);
DEOPT_IF(is_method(stack_pointer, 1), CALL);
@ -3102,7 +3097,7 @@
}
TARGET(CALL_NO_KW_STR_1) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
assert(cframe.use_tracing == 0);
assert(oparg == 1);
DEOPT_IF(is_method(stack_pointer, 1), CALL);
@ -3124,7 +3119,7 @@
}
TARGET(CALL_NO_KW_TUPLE_1) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
assert(oparg == 1);
DEOPT_IF(is_method(stack_pointer, 1), CALL);
PyObject *callable = PEEK(2);
@ -3156,8 +3151,8 @@
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
STACK_SHRINK(total_args);
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer,
total_args-kwnames_len, call_shape.kwnames);
call_shape.kwnames = NULL;
total_args-kwnames_len, kwnames);
kwnames = NULL;
/* Free the arguments. */
for (int i = 0; i < total_args; i++) {
Py_DECREF(stack_pointer[i]);
@ -3175,7 +3170,7 @@
TARGET(CALL_NO_KW_BUILTIN_O) {
assert(cframe.use_tracing == 0);
/* Builtin METH_O functions */
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
int is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
DEOPT_IF(total_args != 1, CALL);
@ -3209,7 +3204,7 @@
TARGET(CALL_NO_KW_BUILTIN_FAST) {
assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL functions, without keywords */
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
int is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
@ -3266,10 +3261,10 @@
PyCFunction_GET_SELF(callable),
stack_pointer,
total_args - KWNAMES_LEN(),
call_shape.kwnames
kwnames
);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
call_shape.kwnames = NULL;
kwnames = NULL;
/* Free the arguments. */
for (int i = 0; i < total_args; i++) {
@ -3287,7 +3282,7 @@
TARGET(CALL_NO_KW_LEN) {
assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
/* len(o) */
int is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
@ -3317,7 +3312,7 @@
TARGET(CALL_NO_KW_ISINSTANCE) {
assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
/* isinstance(o, o2) */
int is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
@ -3350,7 +3345,7 @@
TARGET(CALL_NO_KW_LIST_APPEND) {
assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
assert(oparg == 1);
PyObject *callable = PEEK(3);
PyInterpreterState *interp = _PyInterpreterState_GET();
@ -3372,7 +3367,7 @@
}
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
int is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
PyMethodDescrObject *callable =
@ -3425,9 +3420,9 @@
_PyCFunctionFastWithKeywords cfunc =
(_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
PyObject *res = cfunc(self, stack_pointer, nargs - KWNAMES_LEN(),
call_shape.kwnames);
kwnames);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
call_shape.kwnames = NULL;
kwnames = NULL;
/* Free the arguments. */
for (int i = 0; i < nargs; i++) {
@ -3445,7 +3440,7 @@
}
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
assert(oparg == 0 || oparg == 1);
int is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
@ -3479,7 +3474,7 @@
}
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
assert(call_shape.kwnames == NULL);
assert(kwnames == NULL);
int is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
PyMethodDescrObject *callable =
@ -3597,25 +3592,12 @@
gen->gi_frame_state = FRAME_CREATED;
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCallPy(tstate);
if (!frame->is_entry) {
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
frame = cframe.current_frame = prev;
_PyFrame_StackPush(frame, (PyObject *)gen);
goto resume_frame;
}
_Py_LeaveRecursiveCallTstate(tstate);
/* Make sure that frame is in a valid state */
frame->stacktop = 0;
frame->f_locals = NULL;
Py_INCREF(frame->f_funcobj);
Py_INCREF(frame->f_code);
/* Restore previous cframe and return. */
tstate->cframe = cframe.previous;
tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
assert(!_PyErr_Occurred(tstate));
return (PyObject *)gen;
assert(frame != &entry_frame);
_PyInterpreterFrame *prev = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
frame = cframe.current_frame = prev;
_PyFrame_StackPush(frame, (PyObject *)gen);
goto resume_frame;
}
TARGET(BUILD_SLICE) {