[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 },
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);
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 {
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);
// 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;
}
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;
_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;
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 {
}
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();
}
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;
}
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");
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
"PyStackRef_Unwrap",
"_PyLong_CheckExactAndCompact",
"_PyExecutor_FromExit",
- "_PyJit_InitializeTracing",
+ "_PyJit_TryInitializeTracing",
)