diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/bytecodes.c | 23 | ||||
-rw-r--r-- | Python/executor_cases.c.h | 27 | ||||
-rw-r--r-- | Python/optimizer.c | 20 | ||||
-rw-r--r-- | Python/optimizer_cases.c.h | 8 |
4 files changed, 77 insertions, 1 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c index fe3d613..f688856 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4258,6 +4258,29 @@ dummy_func( } + /* 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. */ + tier2 op(_TIER2_RESUME_CHECK, (--)) { +#if defined(__EMSCRIPTEN__) + EXIT_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); + 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 // } diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 280cca1..2d9acfe 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4295,4 +4295,31 @@ break; } + case _TIER2_RESUME_CHECK: { + #if defined(__EMSCRIPTEN__) + if (_Py_emscripten_signal_clock == 0) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + _Py_emscripten_signal_clock -= Py_EMSCRIPTEN_SIGNAL_HANDLING; + #endif + uintptr_t eval_breaker = _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker); + if (eval_breaker & _PY_EVAL_EVENTS_MASK) { + UOP_STAT_INC(uopcode, miss); + JUMP_TO_JUMP_TARGET(); + } + assert(eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version)); + break; + } + + case _EVAL_BREAKER_EXIT: { + _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); + QSBR_QUIESCENT_STATE(tstate); + if (_Py_HandlePending(tstate) != 0) { + GOTO_UNWIND(); + } + EXIT_TO_TRACE(); + break; + } + #undef TIER_TWO diff --git a/Python/optimizer.c b/Python/optimizer.c index 02c9b39..fcd7d18 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -690,6 +690,12 @@ top: // Jump here after _PUSH_FRAME or likely branches break; } + case RESUME: + /* Use a special tier 2 version of RESUME_CHECK to allow traces to + * start with RESUME_CHECK */ + ADD_TO_TRACE(_TIER2_RESUME_CHECK, 0, 0, target); + break; + default: { const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode]; @@ -967,7 +973,18 @@ prepare_for_execution(_PyUOpInstruction *buffer, int length) int32_t target = (int32_t)uop_get_target(inst); if (_PyUop_Flags[opcode] & (HAS_EXIT_FLAG | HAS_DEOPT_FLAG)) { if (target != current_jump_target) { - uint16_t exit_op = (_PyUop_Flags[opcode] & HAS_EXIT_FLAG) ? _SIDE_EXIT : _DEOPT; + uint16_t exit_op; + if (_PyUop_Flags[opcode] & HAS_EXIT_FLAG) { + if (opcode == _TIER2_RESUME_CHECK) { + exit_op = _EVAL_BREAKER_EXIT; + } + else { + exit_op = _SIDE_EXIT; + } + } + else { + exit_op = _DEOPT; + } make_exit(&buffer[next_spare], exit_op, target); current_jump_target = target; current_jump = next_spare; @@ -1075,6 +1092,7 @@ sanity_check(_PyExecutorObject *executor) CHECK( opcode == _DEOPT || opcode == _SIDE_EXIT || + opcode == _EVAL_BREAKER_EXIT || opcode == _ERROR_POP_N); if (opcode == _SIDE_EXIT) { CHECK(inst->format == UOP_FORMAT_EXIT); diff --git a/Python/optimizer_cases.c.h b/Python/optimizer_cases.c.h index b196568..4102d00 100644 --- a/Python/optimizer_cases.c.h +++ b/Python/optimizer_cases.c.h @@ -2145,3 +2145,11 @@ break; } + case _TIER2_RESUME_CHECK: { + break; + } + + case _EVAL_BREAKER_EXIT: { + break; + } + |