bpo-44878: _PyEval_EvalFrameDefault readability improvements (GH-27725)

* Move a few variable declarations to point of definition.

* Factor out tracing of function entry into helper function.
This commit is contained in:
Mark Shannon 2021-08-11 11:47:52 +01:00 committed by GitHub
parent 1841c70f2b
commit 3f3d5dcac3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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)
{
@ -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;
@ -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)) {
@ -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.
@ -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
@ -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) {