]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Stop recursive traces
authorKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Mon, 27 Oct 2025 14:22:05 +0000 (14:22 +0000)
committerKen Jin <28750310+Fidget-Spinner@users.noreply.github.com>
Mon, 27 Oct 2025 14:22:05 +0000 (14:22 +0000)
Include/internal/pycore_opcode_metadata.h
Include/internal/pycore_optimizer.h
Python/bytecodes.c
Python/executor_cases.c.h
Python/generated_cases.c.h
Python/optimizer.c
Tools/cases_generator/analyzer.py

index 2bb915ad62b17f1a85720a116a95fe4976ad166e..f72c0412bc6f82a4a86d1937ba467fc933f851b7 100644 (file)
@@ -1146,7 +1146,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
     [END_ASYNC_FOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
     [END_FOR] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG },
     [END_SEND] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_PURE_FLAG },
-    [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
+    [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
     [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
     [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
     [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
index 7c542e322ecbc2bcf74ad47b759403b91ba48ac5..ff829adbc2eed43eb2987f1fd81d71239828e728 100644 (file)
@@ -361,8 +361,8 @@ extern void _Py_ClearExecutorDeletionList(PyInterpreterState *interp);
 
 int _PyJit_translate_single_bytecode_to_trace(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr);
 
-void
-_PyJit_InitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame,
+int
+_PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame,
     _Py_CODEUNIT *curr_instr, _Py_CODEUNIT *insert_exec_instr,
     _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit, int oparg);
 
index 0328cd3ef9693b884594ced5b5f688f0cab4be7d..9cd32bf63e756dd2b3750a6e9bc6aac1f8dd31a1 100644 (file)
@@ -2972,8 +2972,10 @@ dummy_func(
                         oparg >>= 8;
                         insert_exec_at--;
                     }
-                    _PyJit_InitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg);
-                    ENTER_TRACING();
+                    int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg);
+                    if (succ) {
+                        ENTER_TRACING();
+                    }
                 }
             }
             else {
@@ -3019,6 +3021,15 @@ dummy_func(
 
         tier1 inst(ENTER_EXECUTOR, (--)) {
             #ifdef _Py_TIER2
+            // We want to end any current trace here, before we possibly need
+            // to start tracing new ones due to recursive traces in any inner C functions
+            // in tier2 code.
+            if (IS_JIT_TRACING()) {
+                _PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr);
+                LEAVE_TRACING();
+                int err = bail_tracing_and_jit(tstate, frame);
+                ERROR_IF(err < 0);
+            }
             PyCodeObject *code = _PyFrame_GetCode(frame);
             _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             assert(executor->vm_data.index == INSTR_OFFSET() - 1);
@@ -5428,9 +5439,12 @@ dummy_func(
                 // Note: it's safe to use target->op.arg here instead of the oparg given by EXTENDED_ARG.
                 // The invariant in the optimizer is the deopt target always points back to the first EXTENDED_ARG.
                 // So setting it to anything else is wrong.
-                _PyJit_InitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg);
+                int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg);
                 exit->temperature = initial_temperature_backoff_counter();
-                GOTO_TIER_ONE_CONTINUE_TRACING(target);
+                if (succ) {
+                    GOTO_TIER_ONE_CONTINUE_TRACING(target);
+                }
+                GOTO_TIER_ONE(target);
             }
             assert(tstate->jit_exit == exit);
             exit->executor = executor;
@@ -5636,7 +5650,9 @@ dummy_func(
             }
             tstate->interp->jit_state.specialize_counter = 0;
             PyCodeObject *prev_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame));
-            Py_SETREF(tstate->interp->jit_state.prev_instr_code, prev_code);
+            if (tstate->interp->jit_state.prev_instr_code != prev_code) {
+                Py_SETREF(tstate->interp->jit_state.prev_instr_code, prev_code);
+            }
 
             tstate->interp->jit_state.prev_instr_frame = frame;
             tstate->interp->jit_state.prev_instr_oparg = oparg;
index fafaa7bd12bbb59b04a6a5b6602d4c68a8d0a166..b81b0300da05fea7b4ac2e3d7005dcb788c11f69 100644 (file)
                 _PyExecutorObject *previous_executor = _PyExecutor_FromExit(exit);
                 assert(tstate->current_executor == (PyObject *)previous_executor);
                 int chain_depth = previous_executor->vm_data.chain_depth + 1;
-                _PyJit_InitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg);
+                int succ = _PyJit_TryInitializeTracing(tstate, frame, target, target, target, STACK_LEVEL(), chain_depth, exit, target->op.arg);
                 exit->temperature = initial_temperature_backoff_counter();
-                GOTO_TIER_ONE_CONTINUE_TRACING(target);
+                if (succ) {
+                    GOTO_TIER_ONE_CONTINUE_TRACING(target);
+                }
+                GOTO_TIER_ONE(target);
             }
             assert(tstate->jit_exit == exit);
             exit->executor = executor;
index d9fea0e4ae57673a4a420626885f8ff6fa1c58ac..e9d5a611ccd6e06ff3808cef8cf142722fd6a779 100644 (file)
             INSTRUCTION_STATS(ENTER_EXECUTOR);
             opcode = ENTER_EXECUTOR;
             #ifdef _Py_TIER2
+
+            if (IS_JIT_TRACING()) {
+                _PyFrame_SetStackPointer(frame, stack_pointer);
+                _PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr);
+                stack_pointer = _PyFrame_GetStackPointer(frame);
+                LEAVE_TRACING();
+                _PyFrame_SetStackPointer(frame, stack_pointer);
+                int err = bail_tracing_and_jit(tstate, frame);
+                stack_pointer = _PyFrame_GetStackPointer(frame);
+                if (err < 0) {
+                    JUMP_TO_LABEL(error);
+                }
+            }
             PyCodeObject *code = _PyFrame_GetCode(frame);
             _PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
             assert(executor->vm_data.index == INSTR_OFFSET() - 1);
                             oparg >>= 8;
                             insert_exec_at--;
                         }
-                        _PyJit_InitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg);
-                        ENTER_TRACING();
+                        int succ = _PyJit_TryInitializeTracing(tstate, frame, this_instr, insert_exec_at, next_instr, STACK_LEVEL(), 0, NULL, oparg);
+                        if (succ) {
+                            ENTER_TRACING();
+                        }
                     }
                 }
                 else {
@@ -12342,9 +12357,11 @@ JUMP_TO_LABEL(error);
             }
             tstate->interp->jit_state.specialize_counter = 0;
             PyCodeObject *prev_code = (PyCodeObject *)Py_NewRef(_PyFrame_GetCode(frame));
-            _PyFrame_SetStackPointer(frame, stack_pointer);
-            Py_SETREF(tstate->interp->jit_state.prev_instr_code, prev_code);
-            stack_pointer = _PyFrame_GetStackPointer(frame);
+            if (tstate->interp->jit_state.prev_instr_code != prev_code) {
+                _PyFrame_SetStackPointer(frame, stack_pointer);
+                Py_SETREF(tstate->interp->jit_state.prev_instr_code, prev_code);
+                stack_pointer = _PyFrame_GetStackPointer(frame);
+            }
             tstate->interp->jit_state.prev_instr_frame = frame;
             tstate->interp->jit_state.prev_instr_oparg = oparg;
             tstate->interp->jit_state.prev_instr_stacklevel = STACK_LEVEL();
index da9247cd139ca4c567edc4d7121deed1fa00e9ba..05ab91fd543535af1d22ad5dcb507bba2bb61850 100644 (file)
@@ -619,6 +619,11 @@ _PyJit_translate_single_bytecode_to_trace(
     }
 
     if (opcode == ENTER_EXECUTOR) {
+        int is_first_instr = tstate->interp->jit_state.close_loop_instr == next_instr || tstate->interp->jit_state.insert_exec_instr == next_instr;
+        if (is_first_instr && tstate->interp->jit_state.code_curr_size > 5) {
+            ADD_TO_TRACE(_JUMP_TO_TOP, 0, 0, 0);
+            goto done;
+        }
         goto full;
     }
 
@@ -925,9 +930,15 @@ full:
     return 0;
 }
 
-void
-_PyJit_InitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *curr_instr, _Py_CODEUNIT *insert_exec_instr, _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit, int oparg)
+// Returns 0 for do not enter tracing, 1 on enter tracing.
+int
+_PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *curr_instr, _Py_CODEUNIT *insert_exec_instr, _Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit, int oparg)
 {
+    // A recursive trace.
+    // Don't trace into the inner call because it will stomp on the previous trace, causing endless retraces.
+    if (tstate->interp->jit_state.code_curr_size > 2) {
+        return 0;
+    }
     PyCodeObject *code = _PyFrame_GetCode(frame);
 #ifdef Py_DEBUG
     char *python_lltrace = Py_GETENV("PYTHON_LLTRACE");
@@ -965,6 +976,7 @@ _PyJit_InitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_
     tstate->interp->jit_state.dynamic_jump_taken = false;
     tstate->interp->jit_state.prev_instr_is_super = false;
     _Py_BloomFilter_Init(&tstate->interp->jit_state.dependencies);
+    return 1;
 }
 
 void
index b206a0a4b985d34a016c777cffd172c4857c468e..b66e2f0ab0d203d52b325206fd6a64f964081d9e 100644 (file)
@@ -699,7 +699,7 @@ NON_ESCAPING_FUNCTIONS = (
     "PyStackRef_Unwrap",
     "_PyLong_CheckExactAndCompact",
     "_PyExecutor_FromExit",
-    "_PyJit_InitializeTracing",
+    "_PyJit_TryInitializeTracing",
 )