Skip to content

bpo-44878: Further ceval entry cleanup #27725

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 3 commits into from
Aug 11, 2021
Merged
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
100 changes: 49 additions & 51 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,45 @@ eval_frame_handle_pending(PyThreadState *tstate)
#define BUILTINS() frame->f_builtins
#define LOCALS() frame->f_locals

static int
trace_function_entry(PyThreadState *tstate, InterpreterFrame *frame)
{
if (tstate->c_tracefunc != NULL) {
/* tstate->c_tracefunc, if defined, is a
function that will be called on *every* entry
to a code block. Its return value, if not
None, is a function that will be called at
the start of each executed line of code.
(Actually, the function must return itself
in order to continue tracing.) The trace
functions are called with three arguments:
a pointer to the current frame, a string
indicating why the function is called, and
an argument which depends on the situation.
The global trace function is also called
whenever an exception is detected. */
if (call_trace_protected(tstate->c_tracefunc,
tstate->c_traceobj,
tstate, frame,
PyTrace_CALL, Py_None)) {
/* Trace function raised an error */
return -1;
}
}
if (tstate->c_profilefunc != NULL) {
/* Similar for c_profilefunc, except it needn't
return itself and isn't called for "line" events */
if (call_trace_protected(tstate->c_profilefunc,
tstate->c_profileobj,
tstate, frame,
PyTrace_CALL, Py_None)) {
/* Profile function raised an error */
return -1;
}
}
return 0;
}

PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag)
{
Expand All @@ -1405,22 +1444,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
#ifdef DXPAIRS
int lastopcode = 0;
#endif
PyObject **stack_pointer; /* Next free slot in value stack */
_Py_CODEUNIT *next_instr;
int opcode; /* Current opcode */
int oparg; /* Current opcode argument, if any */
PyObject **localsplus;
PyObject *retval = NULL; /* Return value */
_Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker;
PyCodeObject *co;

_Py_CODEUNIT *first_instr;
PyObject *names;
PyObject *consts;

#ifdef LLTRACE
_Py_IDENTIFIER(__ltrace__);
#endif

if (_Py_EnterRecursiveCall(tstate, "")) {
return NULL;
Expand All @@ -1439,47 +1466,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr

/* push frame */
tstate->frame = frame;
co = frame->f_code;

if (cframe.use_tracing) {
if (tstate->c_tracefunc != NULL) {
/* tstate->c_tracefunc, if defined, is a
function that will be called on *every* entry
to a code block. Its return value, if not
None, is a function that will be called at
the start of each executed line of code.
(Actually, the function must return itself
in order to continue tracing.) The trace
functions are called with three arguments:
a pointer to the current frame, a string
indicating why the function is called, and
an argument which depends on the situation.
The global trace function is also called
whenever an exception is detected. */
if (call_trace_protected(tstate->c_tracefunc,
tstate->c_traceobj,
tstate, frame,
PyTrace_CALL, Py_None)) {
/* Trace function raised an error */
goto exit_eval_frame;
}
}
if (tstate->c_profilefunc != NULL) {
/* Similar for c_profilefunc, except it needn't
return itself and isn't called for "line" events */
if (call_trace_protected(tstate->c_profilefunc,
tstate->c_profileobj,
tstate, frame,
PyTrace_CALL, Py_None)) {
/* Profile function raised an error */
goto exit_eval_frame;
}
if (trace_function_entry(tstate, frame)) {
goto exit_eval_frame;
}
}

if (PyDTrace_FUNCTION_ENTRY_ENABLED())
dtrace_function_entry(frame);

PyCodeObject *co = frame->f_code;
/* Increment the warmup counter and quicken if warm enough
* _Py_Quicken is idempotent so we don't worry about overflow */
if (!PyCodeObject_IsWarmedUp(co)) {
Expand All @@ -1492,10 +1489,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
}


names = co->co_names;
consts = co->co_consts;
localsplus = _PyFrame_GetLocalsArray(frame);
first_instr = co->co_firstinstr;
PyObject *names = co->co_names;
PyObject *consts = co->co_consts;
PyObject **localsplus = _PyFrame_GetLocalsArray(frame);
_Py_CODEUNIT *first_instr = co->co_firstinstr;
/*
frame->f_lasti refers to the index of the last instruction,
unless it's -1 in which case next_instr should be first_instr.
Expand All @@ -1512,8 +1509,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
to the beginning of the combined pair.)
*/
assert(frame->f_lasti >= -1);
next_instr = first_instr + frame->f_lasti + 1;
stack_pointer = frame->stack + frame->stackdepth;
_Py_CODEUNIT *next_instr = first_instr + frame->f_lasti + 1;
PyObject **stack_pointer = frame->stack + frame->stackdepth;
/* Set stackdepth to -1.
* Update when returning or calling trace function.
Having f_stackdepth <= 0 ensures that invalid
Expand All @@ -1524,6 +1521,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
frame->f_state = FRAME_EXECUTING;

#ifdef LLTRACE
_Py_IDENTIFIER(__ltrace__);
{
int r = _PyDict_ContainsId(GLOBALS(), &PyId___ltrace__);
if (r < 0) {
Expand Down