GH-117442: Check eval-breaker at start (rather than end) of tier 2 loops (GH-118482)

This commit is contained in:
Mark Shannon 2024-05-02 13:10:31 +01:00 committed by GitHub
parent f8e088df2a
commit 67bba9dd0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 137 additions and 174 deletions

View file

@ -2410,20 +2410,21 @@ dummy_func(
tier1 inst(ENTER_EXECUTOR, (--)) {
#ifdef _Py_TIER2
int prevoparg = oparg;
CHECK_EVAL_BREAKER();
if (this_instr->op.code != ENTER_EXECUTOR ||
this_instr->op.arg != prevoparg) {
next_instr = this_instr;
DISPATCH();
}
PyCodeObject *code = _PyFrame_GetCode(frame);
_PyExecutorObject *executor = code->co_executors->executors[oparg & 255];
assert(executor->vm_data.index == INSTR_OFFSET() - 1);
assert(executor->vm_data.code == code);
assert(executor->vm_data.valid);
assert(tstate->previous_executor == NULL);
/* If the eval breaker is set then stay in tier 1.
* This avoids any potentially infinite loops
* involving _RESUME_CHECK */
if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) {
opcode = executor->vm_data.opcode;
oparg = (oparg & ~255) | executor->vm_data.oparg;
next_instr = this_instr;
DISPATCH_GOTO();
}
tstate->previous_executor = Py_None;
Py_INCREF(executor);
GOTO_TIER_TWO(executor);
@ -4111,7 +4112,6 @@ dummy_func(
#ifndef _Py_JIT
next_uop = &current_executor->trace[1];
#endif
CHECK_EVAL_BREAKER();
}
tier2 op(_SET_IP, (instr_ptr/4 --)) {
@ -4277,30 +4277,18 @@ dummy_func(
GOTO_UNWIND();
}
/* Special version of RESUME_CHECK that (when paired with _EVAL_BREAKER_EXIT)
* is safe for tier 2. Progress is guaranteed because _EVAL_BREAKER_EXIT calls
* _Py_HandlePending which clears the eval_breaker so that _TIER2_RESUME_CHECK
* will not exit if it is immediately executed again. */
/* Progress is guaranteed if we DEOPT on the eval breaker, because
* ENTER_EXECUTOR will not re-enter tier 2 with the eval breaker set. */
tier2 op(_TIER2_RESUME_CHECK, (--)) {
#if defined(__EMSCRIPTEN__)
EXIT_IF(_Py_emscripten_signal_clock == 0);
DEOPT_IF(_Py_emscripten_signal_clock == 0);
_Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING;
#endif
uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker);
EXIT_IF(eval_breaker & _PY_EVAL_EVENTS_MASK);
DEOPT_IF(eval_breaker & _PY_EVAL_EVENTS_MASK);
assert(eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
}
tier2 op(_EVAL_BREAKER_EXIT, (--)) {
_Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY();
QSBR_QUIESCENT_STATE(tstate);
if (_Py_HandlePending(tstate) != 0) {
GOTO_UNWIND();
}
EXIT_TO_TRACE();
}
// END BYTECODES //
}