bpo-43760: Streamline dispatch sequence for machines without computed… · python/cpython@28d28e0
@@ -1264,6 +1264,23 @@ eval_frame_handle_pending(PyThreadState *tstate)
12641264 -fno-crossjumping).
12651265*/
126612661267+/* 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
@@ -1282,37 +1299,22 @@ eval_frame_handle_pending(PyThreadState *tstate)
12821299#endif
1283130012841301#if USE_COMPUTED_GOTOS
1285-#define TARGET(op) \
1286- op: \
1287- 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- }
1302+#define TARGET(op) op: TARGET_##op
1303+#define DISPATCH_GOTO() goto *opcode_targets[opcode]
12991304#else
1305+#define TARGET(op) op
1306+#define DISPATCH_GOTO() goto dispatch_opcode
1307+#endif
1308+13001309#define DISPATCH() \
13011310 { \
1302- if (!_Py_TracingPossible(ceval2) && !PyDTrace_LINE_ENABLED()) { \
1303- f->f_lasti = INSTR_OFFSET(); \
1304- NEXTOPARG(); \
1305- goto *opcode_targets[opcode]; \
1311+ if (_Py_TracingPossible(ceval2) OR_DTRACE_LINE OR_LLTRACE) { \
1312+ goto tracing_dispatch; \
13061313 } \
1307- goto fast_next_opcode; \
1314+ f->f_lasti = INSTR_OFFSET(); \
1315+ NEXTOPARG(); \
1316+ DISPATCH_GOTO(); \
13081317 }
1309-#endif
1310-1311-#else
1312-#define TARGET(op) op
1313-#define DISPATCH() goto fast_next_opcode
1314-1315-#endif
1316131813171319#define CHECK_EVAL_BREAKER() \
13181320 if (_Py_atomic_load_relaxed(eval_breaker)) { \
@@ -1598,14 +1600,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
15981600_Py_atomic_int * const eval_breaker = &ceval2->eval_breaker;
15991601PyCodeObject *co;
160016021601-/* 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-16091603const _Py_CODEUNIT *first_instr;
16101604PyObject *names;
16111605PyObject *consts;
@@ -1620,7 +1614,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
16201614 }
1621161516221616PyTraceInfo trace_info;
1623-/* Mark trace_info as initialized */
1617+/* Mark trace_info as uninitialized */
16241618trace_info.code = NULL;
1625161916261620/* push frame */
@@ -1754,10 +1748,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
1754174817551749if (_Py_atomic_load_relaxed(eval_breaker)) {
17561750opcode = _Py_OPCODE(*next_instr);
1757-if (opcode == SETUP_FINALLY ||
1758-opcode == SETUP_WITH ||
1759-opcode == BEFORE_ASYNC_WITH ||
1760-opcode == YIELD_FROM) {
1751+if (opcode != SETUP_FINALLY &&
1752+opcode != SETUP_WITH &&
1753+opcode != BEFORE_ASYNC_WITH &&
1754+opcode != YIELD_FROM) {
17611755/* Few cases where we skip running signal handlers and other
17621756 pending calls:
17631757 - If we're about to enter the 'with:'. It will prevent
@@ -1774,16 +1768,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
17741768 running the signal handler and raising KeyboardInterrupt
17751769 (see bpo-30039).
17761770 */
1777- goto fast_next_opcode;
1778- }
1779-1780-if (eval_frame_handle_pending(tstate) != 0) {
1781- goto error;
1782- }
1771+if (eval_frame_handle_pending(tstate) != 0) {
1772+ goto error;
1773+ }
1774+ }
17831775 }
178417761785-fast_next_opcode:
1777+tracing_dispatch:
17861778f->f_lasti = INSTR_OFFSET();
1779+NEXTOPARG();
1787178017881781if (PyDTrace_LINE_ENABLED())
17891782maybe_dtrace_line(f, &trace_info);
@@ -1805,23 +1798,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
18051798JUMPTO(f->f_lasti);
18061799stack_pointer = f->f_valuestack+f->f_stackdepth;
18071800f->f_stackdepth = -1;
1808-if (err)
1801+if (err) {
18091802/* trace function raised an exception */
18101803 goto error;
1804+ }
1805+NEXTOPARG();
18111806 }
181218071813-/* 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-18251808#ifdef LLTRACE
18261809/* Instruction tracing */
18271810@@ -1837,11 +1820,20 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
18371820 }
18381821#endif
183918221823+dispatch_opcode:
1824+#ifdef DYNAMIC_EXECUTION_PROFILE
1825+#ifdef DXPAIRS
1826+dxpairs[lastopcode][opcode]++;
1827+lastopcode = opcode;
1828+#endif
1829+dxp[opcode]++;
1830+#endif
1831+18401832switch (opcode) {
1841183318421834/* BEWARE!
18431835 It is essential that any operation that fails must goto error
1844- and that all operation that succeed call [FAST_]DISPATCH() ! */
1836+ and that all operation that succeed call DISPATCH() ! */
1845183718461838case TARGET(NOP): {
18471839DISPATCH();
@@ -5427,7 +5419,6 @@ unpack_iterable(PyThreadState *tstate, PyObject *v,
54275419return 0;
54285420}
542954215430-54315422#ifdef LLTRACE
54325423static int
54335424prtrace(PyThreadState *tstate, PyObject *v, const char *str)