bpo-47045: Remove f_state field (GH-31963)

* Remove the f_state field from _PyInterpreterFrame

*  Make ownership of the frame explicit, replacing the is_generator field with an owner field.
This commit is contained in:
Mark Shannon 2022-03-22 12:57:19 +00:00 committed by GitHub
parent 88872a29f1
commit 49daf6dba8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 260 additions and 220 deletions

View file

@ -1730,7 +1730,6 @@ handle_eval_breaker:
PREDICTED(RESUME_QUICK);
assert(tstate->cframe == &cframe);
assert(frame == cframe.current_frame);
frame->f_state = FRAME_EXECUTING;
if (_Py_atomic_load_relaxed(eval_breaker) && oparg < 2) {
goto handle_eval_breaker;
}
@ -2373,7 +2372,6 @@ handle_eval_breaker:
TARGET(RETURN_VALUE) {
PyObject *retval = POP();
assert(EMPTY());
frame->f_state = FRAME_RETURNED;
_PyFrame_SetStackPointer(frame, stack_pointer);
TRACE_FUNCTION_EXIT();
DTRACE_FUNCTION_EXIT();
@ -2585,7 +2583,7 @@ handle_eval_breaker:
TARGET(YIELD_VALUE) {
assert(frame->is_entry);
PyObject *retval = POP();
frame->f_state = FRAME_SUSPENDED;
_PyFrame_GetGenerator(frame)->gi_frame_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer);
TRACE_FUNCTION_EXIT();
DTRACE_FUNCTION_EXIT();
@ -4068,7 +4066,6 @@ handle_eval_breaker:
* generator or coroutine, so we deliberately do not check it here.
* (see bpo-30039).
*/
frame->f_state = FRAME_EXECUTING;
JUMPTO(oparg);
DISPATCH();
}
@ -5253,9 +5250,8 @@ handle_eval_breaker:
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
_PyFrame_Copy(frame, gen_frame);
assert(frame->frame_obj == NULL);
gen->gi_frame_valid = 1;
gen_frame->is_generator = true;
gen_frame->f_state = FRAME_CREATED;
gen->gi_frame_state = FRAME_CREATED;
gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
_Py_LeaveRecursiveCall(tstate);
if (!frame->is_entry) {
_PyInterpreterFrame *prev = frame->previous;
@ -5429,41 +5425,47 @@ handle_eval_breaker:
int instr_prev = frame->f_lasti;
frame->f_lasti = INSTR_OFFSET();
TRACING_NEXTOPARG();
if (opcode == RESUME) {
if (oparg < 2) {
CHECK_EVAL_BREAKER();
}
/* Call tracing */
TRACE_FUNCTION_ENTRY();
DTRACE_FUNCTION_ENTRY();
}
else if (frame->f_state > FRAME_CREATED) {
/* line-by-line tracing support */
if (PyDTrace_LINE_ENABLED()) {
maybe_dtrace_line(frame, &tstate->trace_info, instr_prev);
}
if (cframe.use_tracing &&
tstate->c_tracefunc != NULL && !tstate->tracing) {
int err;
/* see maybe_call_line_trace()
for expository comments */
_PyFrame_SetStackPointer(frame, stack_pointer);
err = maybe_call_line_trace(tstate->c_tracefunc,
tstate->c_traceobj,
tstate, frame, instr_prev);
if (err) {
/* trace function raised an exception */
next_instr++;
goto error;
switch(opcode) {
case COPY_FREE_VARS:
case MAKE_CELL:
case RETURN_GENERATOR:
/* Frame not fully initialized */
break;
case RESUME:
if (oparg < 2) {
CHECK_EVAL_BREAKER();
}
/* Call tracing */
TRACE_FUNCTION_ENTRY();
DTRACE_FUNCTION_ENTRY();
break;
default:
/* line-by-line tracing support */
if (PyDTrace_LINE_ENABLED()) {
maybe_dtrace_line(frame, &tstate->trace_info, instr_prev);
}
/* Reload possibly changed frame fields */
JUMPTO(frame->f_lasti);
stack_pointer = _PyFrame_GetStackPointer(frame);
frame->stacktop = -1;
}
if (cframe.use_tracing &&
tstate->c_tracefunc != NULL && !tstate->tracing) {
int err;
/* see maybe_call_line_trace()
for expository comments */
_PyFrame_SetStackPointer(frame, stack_pointer);
err = maybe_call_line_trace(tstate->c_tracefunc,
tstate->c_traceobj,
tstate, frame, instr_prev);
if (err) {
/* trace function raised an exception */
next_instr++;
goto error;
}
/* Reload possibly changed frame fields */
JUMPTO(frame->f_lasti);
stack_pointer = _PyFrame_GetStackPointer(frame);
frame->stacktop = -1;
}
}
}
TRACING_NEXTOPARG();
@ -5558,65 +5560,63 @@ error:
if (tstate->c_tracefunc != NULL) {
/* Make sure state is set to FRAME_UNWINDING for tracing */
frame->f_state = FRAME_UNWINDING;
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj,
tstate, frame);
}
exception_unwind:
frame->f_state = FRAME_UNWINDING;
/* We can't use frame->f_lasti here, as RERAISE may have set it */
int offset = INSTR_OFFSET()-1;
int level, handler, lasti;
if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) {
// No handlers, so exit.
assert(_PyErr_Occurred(tstate));
{
/* We can't use frame->f_lasti here, as RERAISE may have set it */
int offset = INSTR_OFFSET()-1;
int level, handler, lasti;
if (get_exception_handler(frame->f_code, offset, &level, &handler, &lasti) == 0) {
// No handlers, so exit.
assert(_PyErr_Occurred(tstate));
/* Pop remaining stack entries. */
PyObject **stackbase = _PyFrame_Stackbase(frame);
while (stack_pointer > stackbase) {
PyObject *o = POP();
Py_XDECREF(o);
/* Pop remaining stack entries. */
PyObject **stackbase = _PyFrame_Stackbase(frame);
while (stack_pointer > stackbase) {
PyObject *o = POP();
Py_XDECREF(o);
}
assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer);
TRACE_FUNCTION_UNWIND();
DTRACE_FUNCTION_EXIT();
goto exit_unwind;
}
assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_state = FRAME_RAISED;
TRACE_FUNCTION_UNWIND();
DTRACE_FUNCTION_EXIT();
goto exit_unwind;
}
assert(STACK_LEVEL() >= level);
PyObject **new_top = _PyFrame_Stackbase(frame) + level;
while (stack_pointer > new_top) {
PyObject *v = POP();
Py_XDECREF(v);
}
PyObject *exc, *val, *tb;
if (lasti) {
PyObject *lasti = PyLong_FromLong(frame->f_lasti);
if (lasti == NULL) {
goto exception_unwind;
assert(STACK_LEVEL() >= level);
PyObject **new_top = _PyFrame_Stackbase(frame) + level;
while (stack_pointer > new_top) {
PyObject *v = POP();
Py_XDECREF(v);
}
PUSH(lasti);
PyObject *exc, *val, *tb;
if (lasti) {
PyObject *lasti = PyLong_FromLong(frame->f_lasti);
if (lasti == NULL) {
goto exception_unwind;
}
PUSH(lasti);
}
_PyErr_Fetch(tstate, &exc, &val, &tb);
/* Make the raw exception data
available to the handler,
so a program can emulate the
Python main loop. */
_PyErr_NormalizeException(tstate, &exc, &val, &tb);
if (tb != NULL)
PyException_SetTraceback(val, tb);
else
PyException_SetTraceback(val, Py_None);
Py_XDECREF(tb);
Py_XDECREF(exc);
PUSH(val);
JUMPTO(handler);
/* Resume normal execution */
DISPATCH();
}
_PyErr_Fetch(tstate, &exc, &val, &tb);
/* Make the raw exception data
available to the handler,
so a program can emulate the
Python main loop. */
_PyErr_NormalizeException(tstate, &exc, &val, &tb);
if (tb != NULL)
PyException_SetTraceback(val, tb);
else
PyException_SetTraceback(val, Py_None);
Py_XDECREF(tb);
Py_XDECREF(exc);
PUSH(val);
JUMPTO(handler);
/* Resume normal execution */
frame->f_state = FRAME_EXECUTING;
DISPATCH();
}
exit_unwind:
@ -6180,6 +6180,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
localsarray[i] = NULL;
}
if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) {
assert(frame->owner != FRAME_OWNED_BY_GENERATOR);
_PyFrame_Clear(frame);
return NULL;
}
@ -6203,7 +6204,8 @@ static void
_PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame)
{
tstate->recursion_remaining--;
assert(frame->frame_obj == NULL || frame->frame_obj->f_owns_frame == 0);
assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
assert(frame->owner == FRAME_OWNED_BY_THREAD);
_PyFrame_Clear(frame);
tstate->recursion_remaining++;
_PyThreadState_PopFrame(tstate, frame);
@ -6681,6 +6683,8 @@ call_trace(Py_tracefunc func, PyObject *obj,
if (f == NULL) {
return -1;
}
int old_what = tstate->tracing_what;
tstate->tracing_what = what;
PyThreadState_EnterTracing(tstate);
assert (frame->f_lasti >= 0);
initialize_trace_info(&tstate->trace_info, frame);
@ -6688,6 +6692,7 @@ call_trace(Py_tracefunc func, PyObject *obj,
result = func(obj, f, what, arg);
f->f_lineno = 0;
PyThreadState_LeaveTracing(tstate);
tstate->tracing_what = old_what;
return result;
}