mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
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:
parent
dbf2faf579
commit
1e197e63e2
24 changed files with 450 additions and 346 deletions
138
Python/generated_cases.c.h
generated
138
Python/generated_cases.c.h
generated
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue