Skip to content

bpo-43760: Streamline dispatch sequence for machines without computed gotos. #25244

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
Apr 8, 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
113 changes: 52 additions & 61 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1264,6 +1264,23 @@ eval_frame_handle_pending(PyThreadState *tstate)
-fno-crossjumping).
*/

/* Use macros rather than inline functions, to make it as clear as possible
* to the C compiler that the tracing check is a simple test then branch.
* We want to be sure that the compiler knows this before it generates
* the CFG.
*/
#ifdef LLTRACE
#define OR_LLTRACE || lltrace
#else
#define OR_LLTRACE
#endif

#ifdef WITH_DTRACE
#define OR_DTRACE_LINE || PyDTrace_LINE_ENABLED()
#else
#define OR_DTRACE_LINE
#endif

#ifdef DYNAMIC_EXECUTION_PROFILE
#undef USE_COMPUTED_GOTOS
#define USE_COMPUTED_GOTOS 0
Expand All @@ -1282,37 +1299,22 @@ eval_frame_handle_pending(PyThreadState *tstate)
#endif

#if USE_COMPUTED_GOTOS
#define TARGET(op) \
op: \
TARGET_##op

#ifdef LLTRACE
#define DISPATCH() \
{ \
if (!lltrace && !_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
} \
goto fast_next_opcode; \
}
#define TARGET(op) op: TARGET_##op
#define DISPATCH_GOTO() goto *opcode_targets[opcode]
#else
#define TARGET(op) op
#define DISPATCH_GOTO() goto dispatch_opcode
#endif

#define DISPATCH() \
{ \
if (!_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
goto *opcode_targets[opcode]; \
if (_Py_TracingPossible(ceval2) OR_DTRACE_LINE OR_LLTRACE) { \
goto tracing_dispatch; \
} \
goto fast_next_opcode; \
f->f_lasti = INSTR_OFFSET(); \
NEXTOPARG(); \
DISPATCH_GOTO(); \
}
#endif

#else
#define TARGET(op) op
#define DISPATCH() goto fast_next_opcode

#endif

#define CHECK_EVAL_BREAKER() \
if (_Py_atomic_load_relaxed(eval_breaker)) { \
Expand Down Expand Up @@ -1598,14 +1600,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
_Py_atomic_int * const eval_breaker = &ceval2->eval_breaker;
PyCodeObject *co;

/* when tracing we set things up so that

not (instr_lb <= current_bytecode_offset < instr_ub)

is true when the line being executed has changed. The
initial values are such as to make this false the first
time it is tested. */

const _Py_CODEUNIT *first_instr;
PyObject *names;
PyObject *consts;
Expand All @@ -1620,7 +1614,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
}

PyTraceInfo trace_info;
/* Mark trace_info as initialized */
/* Mark trace_info as uninitialized */
trace_info.code = NULL;

/* push frame */
Expand Down Expand Up @@ -1754,10 +1748,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)

if (_Py_atomic_load_relaxed(eval_breaker)) {
opcode = _Py_OPCODE(*next_instr);
if (opcode == SETUP_FINALLY ||
opcode == SETUP_WITH ||
opcode == BEFORE_ASYNC_WITH ||
opcode == YIELD_FROM) {
if (opcode != SETUP_FINALLY &&
opcode != SETUP_WITH &&
opcode != BEFORE_ASYNC_WITH &&
opcode != YIELD_FROM) {
/* Few cases where we skip running signal handlers and other
pending calls:
- If we're about to enter the 'with:'. It will prevent
Expand All @@ -1774,16 +1768,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
running the signal handler and raising KeyboardInterrupt
(see bpo-30039).
*/
goto fast_next_opcode;
}

if (eval_frame_handle_pending(tstate) != 0) {
goto error;
}
if (eval_frame_handle_pending(tstate) != 0) {
goto error;
}
}
}

fast_next_opcode:
tracing_dispatch:
f->f_lasti = INSTR_OFFSET();
NEXTOPARG();

if (PyDTrace_LINE_ENABLED())
maybe_dtrace_line(f, &trace_info);
Expand All @@ -1805,23 +1798,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
JUMPTO(f->f_lasti);
stack_pointer = f->f_valuestack+f->f_stackdepth;
f->f_stackdepth = -1;
if (err)
if (err) {
/* trace function raised an exception */
goto error;
}
NEXTOPARG();
}

/* Extract opcode and argument */

NEXTOPARG();
dispatch_opcode:
#ifdef DYNAMIC_EXECUTION_PROFILE
#ifdef DXPAIRS
dxpairs[lastopcode][opcode]++;
lastopcode = opcode;
#endif
dxp[opcode]++;
#endif

#ifdef LLTRACE
/* Instruction tracing */

Expand All @@ -1837,11 +1820,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
}
#endif

dispatch_opcode:
#ifdef DYNAMIC_EXECUTION_PROFILE
#ifdef DXPAIRS
dxpairs[lastopcode][opcode]++;
lastopcode = opcode;
#endif
dxp[opcode]++;
#endif

switch (opcode) {

/* BEWARE!
It is essential that any operation that fails must goto error
and that all operation that succeed call [FAST_]DISPATCH() ! */
and that all operation that succeed call DISPATCH() ! */

case TARGET(NOP): {
DISPATCH();
Expand Down Expand Up @@ -5427,7 +5419,6 @@ unpack_iterable(PyThreadState *tstate, PyObject *v,
return 0;
}


#ifdef LLTRACE
static int
prtrace(PyThreadState *tstate, PyObject *v, const char *str)
Expand Down