@@ -1264,6 +1264,23 @@ eval_frame_handle_pending(PyThreadState *tstate)
12641264 -fno-crossjumping).
12651265*/
12661266
1267+ /* Use macros rather than inline functions, to make it as clear as possible
1268+ * to the C compiler that the tracing check is a simple test then branch.
1269+ * We want to be sure that the compiler knows this before it generates
1270+ * the CFG.
1271+ */
1272+ #ifdef LLTRACE
1273+ #define OR_LLTRACE || lltrace
1274+ #else
1275+ #define OR_LLTRACE
1276+ #endif
1277+
1278+ #ifdef WITH_DTRACE
1279+ #define OR_DTRACE_LINE || PyDTrace_LINE_ENABLED()
1280+ #else
1281+ #define OR_DTRACE_LINE
1282+ #endif
1283+
12671284#ifdef DYNAMIC_EXECUTION_PROFILE
12681285#undef USE_COMPUTED_GOTOS
12691286#define USE_COMPUTED_GOTOS 0
@@ -1285,34 +1302,21 @@ eval_frame_handle_pending(PyThreadState *tstate)
12851302#define TARGET (op ) \
12861303 op: \
12871304 TARGET_##op
1288-
1289- #ifdef LLTRACE
1290- #define DISPATCH () \
1291- { \
1292- if (!lltrace && !_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
1293- f->f_lasti = INSTR_OFFSET(); \
1294- NEXTOPARG(); \
1295- goto *opcode_targets[opcode]; \
1296- } \
1297- goto fast_next_opcode; \
1298- }
1305+ #define DISPATCH_GOTO goto *opcode_targets[opcode];
12991306#else
1307+ #define TARGET (op ) op
1308+ #define DISPATCH_GOTO goto dispatch_opcode;
1309+ #endif
1310+
13001311#define DISPATCH () \
13011312 { \
1302- if (!_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
1303- f->f_lasti = INSTR_OFFSET(); \
1304- NEXTOPARG(); \
1305- goto *opcode_targets[opcode]; \
1313+ if (_Py_TracingPossible(ceval2) OR_DTRACE_LINE OR_LLTRACE) { \
1314+ goto tracing_dispatch; \
13061315 } \
1307- goto fast_next_opcode; \
1316+ f->f_lasti = INSTR_OFFSET(); \
1317+ NEXTOPARG(); \
1318+ DISPATCH_GOTO \
13081319 }
1309- #endif
1310-
1311- #else
1312- #define TARGET (op ) op
1313- #define DISPATCH () goto fast_next_opcode
1314-
1315- #endif
13161320
13171321#define CHECK_EVAL_BREAKER () \
13181322 if (_Py_atomic_load_relaxed(eval_breaker)) { \
@@ -1590,22 +1594,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
15901594#endif
15911595 PyObject * * stack_pointer ; /* Next free slot in value stack */
15921596 const _Py_CODEUNIT * next_instr ;
1593- int opcode ; /* Current opcode */
1597+ uint8_t opcode ; /* Current opcode */
15941598 int oparg ; /* Current opcode argument, if any */
15951599 PyObject * * fastlocals , * * freevars ;
15961600 PyObject * retval = NULL ; /* Return value */
15971601 struct _ceval_state * const ceval2 = & tstate -> interp -> ceval ;
15981602 _Py_atomic_int * const eval_breaker = & ceval2 -> eval_breaker ;
15991603 PyCodeObject * co ;
16001604
1601- /* when tracing we set things up so that
1602-
1603- not (instr_lb <= current_bytecode_offset < instr_ub)
1604-
1605- is true when the line being executed has changed. The
1606- initial values are such as to make this false the first
1607- time it is tested. */
1608-
16091605 const _Py_CODEUNIT * first_instr ;
16101606 PyObject * names ;
16111607 PyObject * consts ;
@@ -1620,7 +1616,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
16201616 }
16211617
16221618 PyTraceInfo trace_info ;
1623- /* Mark trace_info as initialized */
1619+ /* Mark trace_info as uninitialized */
16241620 trace_info .code = NULL ;
16251621
16261622 /* push frame */
@@ -1754,10 +1750,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
17541750
17551751 if (_Py_atomic_load_relaxed (eval_breaker )) {
17561752 opcode = _Py_OPCODE (* next_instr );
1757- if (opcode == SETUP_FINALLY ||
1758- opcode == SETUP_WITH ||
1759- opcode == BEFORE_ASYNC_WITH ||
1760- opcode = = YIELD_FROM ) {
1753+ if (opcode != SETUP_FINALLY &&
1754+ opcode != SETUP_WITH &&
1755+ opcode != BEFORE_ASYNC_WITH &&
1756+ opcode ! = YIELD_FROM ) {
17611757 /* Few cases where we skip running signal handlers and other
17621758 pending calls:
17631759 - If we're about to enter the 'with:'. It will prevent
@@ -1774,16 +1770,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
17741770 running the signal handler and raising KeyboardInterrupt
17751771 (see bpo-30039).
17761772 */
1777- goto fast_next_opcode ;
1778- }
1779-
1780- if (eval_frame_handle_pending (tstate ) != 0 ) {
1781- goto error ;
1782- }
1773+ if (eval_frame_handle_pending (tstate ) != 0 ) {
1774+ goto error ;
1775+ }
1776+ }
17831777 }
17841778
1785- fast_next_opcode :
1779+ tracing_dispatch :
17861780 f -> f_lasti = INSTR_OFFSET ();
1781+ NEXTOPARG ();
17871782
17881783 if (PyDTrace_LINE_ENABLED ())
17891784 maybe_dtrace_line (f , & trace_info );
@@ -1801,27 +1796,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
18011796 tstate -> c_traceobj ,
18021797 tstate , f ,
18031798 & trace_info );
1799+ if (err ) {
1800+ /* trace function raised an exception */
1801+ goto error ;
1802+ }
18041803 /* Reload possibly changed frame fields */
18051804 JUMPTO (f -> f_lasti );
18061805 stack_pointer = f -> f_valuestack + f -> f_stackdepth ;
18071806 f -> f_stackdepth = -1 ;
1808- if (err )
1809- /* trace function raised an exception */
1810- goto error ;
1807+ NEXTOPARG ();
18111808 }
18121809
1813- /* Extract opcode and argument */
1814-
1815- NEXTOPARG ();
1816- dispatch_opcode :
1817- #ifdef DYNAMIC_EXECUTION_PROFILE
1818- #ifdef DXPAIRS
1819- dxpairs [lastopcode ][opcode ]++ ;
1820- lastopcode = opcode ;
1821- #endif
1822- dxp [opcode ]++ ;
1823- #endif
1824-
18251810#ifdef LLTRACE
18261811 /* Instruction tracing */
18271812
@@ -1837,11 +1822,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
18371822 }
18381823#endif
18391824
1825+ dispatch_opcode :
1826+ #ifdef DYNAMIC_EXECUTION_PROFILE
1827+ #ifdef DXPAIRS
1828+ dxpairs [lastopcode ][opcode ]++ ;
1829+ lastopcode = opcode ;
1830+ #endif
1831+ dxp [opcode ]++ ;
1832+ #endif
1833+
18401834 switch (opcode ) {
18411835
18421836 /* BEWARE!
18431837 It is essential that any operation that fails must goto error
1844- and that all operation that succeed call [FAST_] DISPATCH() ! */
1838+ and that all operation that succeed call DISPATCH() ! */
18451839
18461840 case TARGET (NOP ): {
18471841 DISPATCH ();
@@ -5427,7 +5421,6 @@ unpack_iterable(PyThreadState *tstate, PyObject *v,
54275421 return 0 ;
54285422}
54295423
5430-
54315424#ifdef LLTRACE
54325425static int
54335426prtrace (PyThreadState * tstate , PyObject * v , const char * str )
0 commit comments