Skip to content

bpo-45637: Store the frame pointer in the cframe #29267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ typedef struct _cframe {
* accessed outside of their lifetime.
*/
int use_tracing;
/* Pointer to the currently executing frame (it can be NULL) */
struct _interpreter_frame *current_frame;
struct _cframe *previous;
} CFrame;

Expand Down Expand Up @@ -77,8 +79,6 @@ struct _ts {
struct _ts *next;
PyInterpreterState *interp;

/* Borrowed reference to the current frame (it can be NULL) */
struct _interpreter_frame *frame;
int recursion_depth;
int recursion_headroom; /* Allow 50 more calls to handle any errors. */
int stackcheck_counter;
Expand Down
2 changes: 1 addition & 1 deletion Modules/_tracemalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ traceback_get_frames(traceback_t *traceback)
return;
}

InterpreterFrame *pyframe = tstate->frame;
InterpreterFrame *pyframe = tstate->cframe->current_frame;
for (; pyframe != NULL;) {
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
Expand Down
2 changes: 1 addition & 1 deletion Modules/_xxsubinterpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1839,7 +1839,7 @@ _is_running(PyInterpreterState *interp)
}

assert(!PyErr_Occurred());
InterpreterFrame *frame = tstate->frame;
InterpreterFrame *frame = tstate->cframe->current_frame;
if (frame == NULL) {
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1788,7 +1788,7 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate)
*/
_Py_atomic_store(&is_tripped, 0);

InterpreterFrame *frame = tstate->frame;
InterpreterFrame *frame = tstate->cframe->current_frame;
signal_state_t *state = &signal_global_state;
for (int i = 1; i < NSIG; i++) {
if (!_Py_atomic_load_relaxed(&Handlers[i].tripped)) {
Expand Down
10 changes: 5 additions & 5 deletions Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
Py_INCREF(result);
_PyFrame_StackPush(frame, result);

frame->previous = tstate->frame;
frame->previous = tstate->cframe->current_frame;

gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
Expand All @@ -207,7 +207,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;

assert(tstate->frame == frame->previous);
assert(tstate->cframe->current_frame == frame->previous);
/* Don't keep the reference to previous any longer than necessary. It
* may keep a chain of frames alive or it could create a reference
* cycle. */
Expand Down Expand Up @@ -435,17 +435,17 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
will be reported correctly to the user. */
/* XXX We should probably be updating the current frame
somewhere in ceval.c. */
InterpreterFrame *prev = tstate->frame;
InterpreterFrame *prev = tstate->cframe->current_frame;
frame->previous = prev;
tstate->frame = frame;
tstate->cframe->current_frame = frame;
/* Close the generator that we are currently iterating with
'yield from' or awaiting on with 'await'. */
PyFrameState state = gen->gi_xframe->f_state;
gen->gi_xframe->f_state = FRAME_EXECUTING;
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
typ, val, tb);
gen->gi_xframe->f_state = state;
tstate->frame = prev;
tstate->cframe->current_frame = prev;
frame->previous = NULL;
} else {
/* `yf` is an iterator or a coroutine-like object. */
Expand Down
47 changes: 24 additions & 23 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1561,16 +1561,18 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
tstate->cframe = &cframe;

assert(frame->depth == 0);
/* push frame */
tstate->frame = frame;
/* Push frame */
frame->previous = prev_cframe->current_frame;
cframe.current_frame = frame;

start_frame:
if (_Py_EnterRecursiveCall(tstate, "")) {
tstate->recursion_depth++;
goto exit_eval_frame;
}

assert(frame == tstate->frame);
assert(tstate->cframe == &cframe);
assert(frame == cframe.current_frame);

if (cframe.use_tracing) {
if (trace_function_entry(tstate, frame)) {
Expand Down Expand Up @@ -4641,8 +4643,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
goto error;
}
_PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame;
cframe.current_frame = frame = new_frame;
new_frame->depth = frame->depth + 1;
tstate->frame = frame = new_frame;
goto start_frame;
}
}
Expand Down Expand Up @@ -4723,9 +4726,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
STACK_SHRINK(1);
Py_DECREF(func);
_PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = tstate->frame;
new_frame->previous = frame;
frame = cframe.current_frame = new_frame;
new_frame->depth = frame->depth + 1;
tstate->frame = frame = new_frame;
goto start_frame;
}

Expand Down Expand Up @@ -5258,23 +5261,24 @@ MISS_WITH_OPARG_COUNTER(BINARY_MULTIPLY)
_Py_LeaveRecursiveCall(tstate);

if (frame->depth) {
_PyFrame_StackPush(frame->previous, retval);
cframe.current_frame = frame->previous;
_PyFrame_StackPush(cframe.current_frame, retval);
if (_PyEvalFrameClearAndPop(tstate, frame)) {
retval = NULL;
}
frame = tstate->frame;
frame = cframe.current_frame;
if (retval == NULL) {
assert(_PyErr_Occurred(tstate));
throwflag = 1;
}
retval = NULL;
goto resume_frame;
}
tstate->frame = frame->previous;

/* Restore previous cframe */
/* Restore previous cframe. */
tstate->cframe = cframe.previous;
tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
return _Py_CheckFunctionResult(tstate, NULL, retval, __func__);
}

Expand Down Expand Up @@ -5891,8 +5895,6 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
_PyFrame_Clear(frame, 0);
return NULL;
}
frame->previous = tstate->frame;
tstate->frame = frame;
return frame;
}

Expand All @@ -5906,7 +5908,6 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame)
return -1;
}
--tstate->recursion_depth;
tstate->frame = frame->previous;
_PyThreadState_PopFrame(tstate, frame);
return 0;
}
Expand Down Expand Up @@ -6518,17 +6519,17 @@ InterpreterFrame *
_PyEval_GetFrame(void)
{
PyThreadState *tstate = _PyThreadState_GET();
return tstate->frame;
return tstate->cframe->current_frame;
}

PyFrameObject *
PyEval_GetFrame(void)
{
PyThreadState *tstate = _PyThreadState_GET();
if (tstate->frame == NULL) {
if (tstate->cframe->current_frame == NULL) {
return NULL;
}
PyFrameObject *f = _PyFrame_GetFrameObject(tstate->frame);
PyFrameObject *f = _PyFrame_GetFrameObject(tstate->cframe->current_frame);
if (f == NULL) {
PyErr_Clear();
}
Expand All @@ -6538,7 +6539,7 @@ PyEval_GetFrame(void)
PyObject *
_PyEval_GetBuiltins(PyThreadState *tstate)
{
InterpreterFrame *frame = tstate->frame;
InterpreterFrame *frame = tstate->cframe->current_frame;
if (frame != NULL) {
return frame->f_builtins;
}
Expand Down Expand Up @@ -6571,7 +6572,7 @@ PyObject *
PyEval_GetLocals(void)
{
PyThreadState *tstate = _PyThreadState_GET();
InterpreterFrame *current_frame = tstate->frame;
InterpreterFrame *current_frame = tstate->cframe->current_frame;
if (current_frame == NULL) {
_PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist");
return NULL;
Expand All @@ -6590,7 +6591,7 @@ PyObject *
PyEval_GetGlobals(void)
{
PyThreadState *tstate = _PyThreadState_GET();
InterpreterFrame *current_frame = tstate->frame;
InterpreterFrame *current_frame = tstate->cframe->current_frame;
if (current_frame == NULL) {
return NULL;
}
Expand All @@ -6601,7 +6602,7 @@ int
PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
{
PyThreadState *tstate = _PyThreadState_GET();
InterpreterFrame *current_frame = tstate->frame;
InterpreterFrame *current_frame = tstate->cframe->current_frame;
int result = cf->cf_flags != 0;

if (current_frame != NULL) {
Expand Down Expand Up @@ -6651,7 +6652,7 @@ PyEval_GetFuncDesc(PyObject *func)
#define C_TRACE(x, call) \
if (use_tracing && tstate->c_profilefunc) { \
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
tstate, tstate->frame, \
tstate, tstate->cframe->current_frame, \
PyTrace_C_CALL, func)) { \
x = NULL; \
} \
Expand All @@ -6661,13 +6662,13 @@ if (use_tracing && tstate->c_profilefunc) { \
if (x == NULL) { \
call_trace_protected(tstate->c_profilefunc, \
tstate->c_profileobj, \
tstate, tstate->frame, \
tstate, tstate->cframe->current_frame, \
PyTrace_C_EXCEPTION, func); \
/* XXX should pass (type, value, tb) */ \
} else { \
if (call_trace(tstate->c_profilefunc, \
tstate->c_profileobj, \
tstate, tstate->frame, \
tstate, tstate->cframe->current_frame, \
PyTrace_C_RETURN, func)) { \
Py_DECREF(x); \
x = NULL; \
Expand Down
2 changes: 1 addition & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -2031,7 +2031,7 @@ Py_EndInterpreter(PyThreadState *tstate)
if (tstate != _PyThreadState_GET()) {
Py_FatalError("thread is not current");
}
if (tstate->frame != NULL) {
if (tstate->cframe->current_frame != NULL) {
Py_FatalError("thread still has a frame");
}
interp->finalizing = 1;
Expand Down
10 changes: 5 additions & 5 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,12 +636,12 @@ new_threadstate(PyInterpreterState *interp, int init)

tstate->interp = interp;

tstate->frame = NULL;
tstate->recursion_depth = 0;
tstate->recursion_headroom = 0;
tstate->stackcheck_counter = 0;
tstate->tracing = 0;
tstate->root_cframe.use_tracing = 0;
tstate->root_cframe.current_frame = NULL;
tstate->cframe = &tstate->root_cframe;
tstate->gilstate_counter = 0;
tstate->async_exc = NULL;
Expand Down Expand Up @@ -861,7 +861,7 @@ PyThreadState_Clear(PyThreadState *tstate)
{
int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose;

if (verbose && tstate->frame != NULL) {
if (verbose && tstate->cframe->current_frame != NULL) {
/* bpo-20526: After the main thread calls
_PyRuntimeState_SetFinalizing() in Py_FinalizeEx(), threads must
exit when trying to take the GIL. If a thread exit in the middle of
Expand Down Expand Up @@ -1134,10 +1134,10 @@ PyFrameObject*
PyThreadState_GetFrame(PyThreadState *tstate)
{
assert(tstate != NULL);
if (tstate->frame == NULL) {
if (tstate->cframe->current_frame == NULL) {
return NULL;
}
PyFrameObject *frame = _PyFrame_GetFrameObject(tstate->frame);
PyFrameObject *frame = _PyFrame_GetFrameObject(tstate->cframe->current_frame);
if (frame == NULL) {
PyErr_Clear();
}
Expand Down Expand Up @@ -1277,7 +1277,7 @@ _PyThread_CurrentFrames(void)
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
PyThreadState *t;
for (t = i->tstate_head; t != NULL; t = t->next) {
InterpreterFrame *frame = t->frame;
InterpreterFrame *frame = t->cframe->current_frame;
if (frame == NULL) {
continue;
}
Expand Down
2 changes: 1 addition & 1 deletion Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1813,7 +1813,7 @@ sys__getframe_impl(PyObject *module, int depth)
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
{
PyThreadState *tstate = _PyThreadState_GET();
InterpreterFrame *frame = tstate->frame;
InterpreterFrame *frame = tstate->cframe->current_frame;

if (_PySys_Audit(tstate, "sys._getframe", NULL) < 0) {
return NULL;
Expand Down
2 changes: 1 addition & 1 deletion Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
PUTS(fd, "Stack (most recent call first):\n");
}

frame = tstate->frame;
frame = tstate->cframe->current_frame;
if (frame == NULL) {
PUTS(fd, " <no Python frame>\n");
return;
Expand Down