_Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit,
int oparg, _PyExecutorObject *current_executor);
-void _PyJit_FinalizeTracing(PyThreadState *tstate);
+void _PyJit_FinalizeTracing(PyThreadState *tstate, int err);
void _PyJit_TracerFree(_PyThreadStateImpl *_tstate);
void _PyJit_Tracer_InvalidateDependency(PyThreadState *old_tstate, void *obj);
} _PyJitTracerTranslatorState;
typedef struct _PyJitTracerState {
+ bool is_tracing;
_PyJitTracerInitialState initial_state;
_PyJitTracerPreviousState prev_state;
_PyJitTracerTranslatorState translator_state;
"""), PYTHON_JIT="1")
self.assertEqual(result[0].rc, 0, result)
+ def test_143358(self):
+ # https://github.com/python/cpython/issues/143358
+
+ result = script_helper.run_python_until_end('-c', textwrap.dedent(f"""
+ def f1():
+
+ class EvilIterator:
+
+ def __init__(self):
+ self._items = [1, 2]
+ self._index = 1
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ if not len(self._items) % 13:
+ self._items.clear()
+
+ for i_loop_9279 in range(10):
+ self._items.extend([1, "", None])
+
+ if not len(self._items) % 11:
+ return 'unexpected_type_from_iterator'
+
+ if self._index >= len(self._items):
+ raise StopIteration
+
+ item = self._items[self._index]
+ self._index += 1
+ return item
+
+ evil_iter = EvilIterator()
+
+ large_num = 2**31
+ for _ in range(400):
+ try:
+ _ = [x + y for x in evil_iter for y in evil_iter if evil_iter._items.append(x) or large_num]
+ except TypeError:
+ pass
+
+ f1()
+ """), PYTHON_JIT="1", PYTHON_JIT_JUMP_BACKWARD_INITIAL_VALUE="64")
+ self.assertEqual(result[0].rc, 0, result)
+
def global_identity(x):
return x
--- /dev/null
+Protect the JIT against recursive tracing.
#else
assert(_PyErr_Occurred(tstate));
#endif
+ SAVE_STACK();
+ STOP_TRACING();
+ RELOAD_STACK();
/* Log traceback info. */
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
}
spilled label(exception_unwind) {
+ SAVE_STACK();
+ STOP_TRACING();
+ RELOAD_STACK();
/* We can't use frame->instr_ptr here, as RERAISE may have set it */
int offset = INSTR_OFFSET()-1;
int level, handler, lasti;
if (!_PyErr_Occurred(tstate) && !_is_sys_tracing) {
err = _PyOptimizer_Optimize(frame, tstate);
}
- _PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
- // Deal with backoffs
- _PyJitTracerState *tracer = _tstate->jit_tracer_state;
- assert(tracer != NULL);
- _PyExitData *exit = tracer->initial_state.exit;
- if (exit == NULL) {
- // We hold a strong reference to the code object, so the instruction won't be freed.
- if (err <= 0) {
- _Py_BackoffCounter counter = tracer->initial_state.jump_backward_instr[1].counter;
- tracer->initial_state.jump_backward_instr[1].counter = restart_backoff_counter(counter);
- }
- else {
- tracer->initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&_tstate->policy);
- }
- }
- else if (tracer->initial_state.executor->vm_data.valid) {
- // Likewise, we hold a strong reference to the executor containing this exit, so the exit is guaranteed
- // to be valid to access.
- if (err <= 0) {
- exit->temperature = restart_backoff_counter(exit->temperature);
- }
- else {
- exit->temperature = initial_temperature_backoff_counter(&_tstate->policy);
- }
- }
- _PyJit_FinalizeTracing(tstate);
+ _PyJit_FinalizeTracing(tstate, err);
return err;
}
#endif
# define LEAVE_TRACING() tracing_mode = 0
#endif
+#if _Py_TIER2
+#define STOP_TRACING() \
+ do { \
+ if (IS_JIT_TRACING()) { \
+ LEAVE_TRACING(); \
+ _PyJit_FinalizeTracing(tstate, 0); \
+ } \
+ } while (0);
+#else
+#define STOP_TRACING() ((void)(0));
+#endif
+
+
/* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */
#ifdef Py_DEBUG
#define PRE_DISPATCH_GOTO() if (frame->lltrace >= 5) { \
#else
assert(_PyErr_Occurred(tstate));
#endif
-
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ STOP_TRACING();
+ stack_pointer = _PyFrame_GetStackPointer(frame);
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
if (!_PyFrame_IsIncomplete(frame)) {
_PyFrame_SetStackPointer(frame, stack_pointer);
LABEL(exception_unwind)
{
+ STOP_TRACING();
int offset = INSTR_OFFSET()-1;
int level, handler, lasti;
int handled = get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti);
// Don't error, just go to next instruction.
return 0;
}
+ _tstate->jit_tracer_state->is_tracing = false;
}
_PyJitTracerState *tracer = _tstate->jit_tracer_state;
// A recursive trace.
- // Don't trace into the inner call because it will stomp on the previous trace, causing endless retraces.
- if (tracer->prev_state.code_curr_size > CODE_SIZE_EMPTY) {
+ if (tracer->is_tracing) {
return 0;
}
if (oparg > 0xFFFF) {
close_loop_instr[1].counter = trigger_backoff_counter();
}
_Py_BloomFilter_Init(&tracer->prev_state.dependencies);
+ tracer->is_tracing = true;
return 1;
}
Py_NO_INLINE void
-_PyJit_FinalizeTracing(PyThreadState *tstate)
+_PyJit_FinalizeTracing(PyThreadState *tstate, int err)
{
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
_PyJitTracerState *tracer = _tstate->jit_tracer_state;
+ // Deal with backoffs
+ assert(tracer != NULL);
+ _PyExitData *exit = tracer->initial_state.exit;
+ if (exit == NULL) {
+ // We hold a strong reference to the code object, so the instruction won't be freed.
+ if (err <= 0) {
+ _Py_BackoffCounter counter = tracer->initial_state.jump_backward_instr[1].counter;
+ tracer->initial_state.jump_backward_instr[1].counter = restart_backoff_counter(counter);
+ }
+ else {
+ tracer->initial_state.jump_backward_instr[1].counter = initial_jump_backoff_counter(&_tstate->policy);
+ }
+ }
+ else if (tracer->initial_state.executor->vm_data.valid) {
+ // Likewise, we hold a strong reference to the executor containing this exit, so the exit is guaranteed
+ // to be valid to access.
+ if (err <= 0) {
+ exit->temperature = restart_backoff_counter(exit->temperature);
+ }
+ else {
+ exit->temperature = initial_temperature_backoff_counter(&_tstate->policy);
+ }
+ }
Py_CLEAR(tracer->initial_state.code);
Py_CLEAR(tracer->initial_state.func);
Py_CLEAR(tracer->initial_state.executor);
Py_CLEAR(tracer->prev_state.instr_code);
tracer->prev_state.code_curr_size = CODE_SIZE_EMPTY;
tracer->prev_state.code_max_size = UOP_MAX_TRACE_LENGTH/2 - 1;
+ tracer->is_tracing = false;
}
void