Skip to content

Commit 003ba71

Browse files
authored
gh-104584: Fix error handling from backedge optimization (#106484)
When `_PyOptimizer_BackEdge` returns `NULL`, we should restore `next_instr` (and `stack_pointer`). To accomplish this we should jump to `resume_with_error` instead of just `error`. The problem this causes is subtle -- the only repro I have is in PR gh-106393, at commit d7df54b. But the fix is real (as shown later in that PR). While we're at it, also improve the debug output: the offsets at which traces are identified are now measured in bytes, and always show the start offset. This makes it easier to correlate executor calls with optimizer calls, and either with `dis` output. <!-- gh-issue-number: gh-104584 --> * Issue: gh-104584 <!-- /gh-issue-number -->
1 parent 56353b1 commit 003ba71

File tree

4 files changed

+15
-11
lines changed

4 files changed

+15
-11
lines changed

Python/bytecodes.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2234,7 +2234,7 @@ dummy_func(
22342234
frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
22352235
if (frame == NULL) {
22362236
frame = cframe.current_frame;
2237-
goto error;
2237+
goto resume_with_error;
22382238
}
22392239
assert(frame == cframe.current_frame);
22402240
here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);

Python/ceval.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -2737,11 +2737,11 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
27372737
#endif
27382738

27392739
DPRINTF(3,
2740-
"Entering _PyUopExecute for %s (%s:%d) at offset %ld\n",
2740+
"Entering _PyUopExecute for %s (%s:%d) at byte offset %ld\n",
27412741
PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_qualname),
27422742
PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename),
27432743
_PyFrame_GetCode(frame)->co_firstlineno,
2744-
(long)(frame->prev_instr + 1 -
2744+
2 * (long)(frame->prev_instr + 1 -
27452745
(_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive));
27462746

27472747
PyThreadState *tstate = _PyThreadState_GET();

Python/generated_cases.c.h

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer.c

+11-7
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
181181
}
182182
insert_executor(code, src, index, executor);
183183
assert(frame->prev_instr == src);
184+
frame->prev_instr = dest - 1;
184185
return executor->execute(executor, frame, stack_pointer);
185186
jump_to_destination:
186187
frame->prev_instr = dest - 1;
@@ -201,7 +202,7 @@ PyUnstable_GetExecutor(PyCodeObject *code, int offset)
201202
}
202203
i += _PyInstruction_GetLength(code, i);
203204
}
204-
PyErr_SetString(PyExc_ValueError, "no executor at given offset");
205+
PyErr_SetString(PyExc_ValueError, "no executor at given byte offset");
205206
return NULL;
206207
}
207208

@@ -373,6 +374,9 @@ translate_bytecode_to_trace(
373374
_PyUOpInstruction *trace,
374375
int max_length)
375376
{
377+
#ifdef Py_DEBUG
378+
_Py_CODEUNIT *initial_instr = instr;
379+
#endif
376380
int trace_length = 0;
377381

378382
#ifdef Py_DEBUG
@@ -398,11 +402,11 @@ translate_bytecode_to_trace(
398402
trace_length++;
399403

400404
DPRINTF(4,
401-
"Optimizing %s (%s:%d) at offset %ld\n",
405+
"Optimizing %s (%s:%d) at byte offset %ld\n",
402406
PyUnicode_AsUTF8(code->co_qualname),
403407
PyUnicode_AsUTF8(code->co_filename),
404408
code->co_firstlineno,
405-
(long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive));
409+
2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive));
406410

407411
for (;;) {
408412
ADD_TO_TRACE(SAVE_IP, (int)(instr - (_Py_CODEUNIT *)code->co_code_adaptive));
@@ -492,21 +496,21 @@ translate_bytecode_to_trace(
492496
if (trace_length > 3) {
493497
ADD_TO_TRACE(EXIT_TRACE, 0);
494498
DPRINTF(1,
495-
"Created a trace for %s (%s:%d) at offset %ld -- length %d\n",
499+
"Created a trace for %s (%s:%d) at byte offset %ld -- length %d\n",
496500
PyUnicode_AsUTF8(code->co_qualname),
497501
PyUnicode_AsUTF8(code->co_filename),
498502
code->co_firstlineno,
499-
(long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive),
503+
2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive),
500504
trace_length);
501505
return trace_length;
502506
}
503507
else {
504508
DPRINTF(4,
505-
"No trace for %s (%s:%d) at offset %ld\n",
509+
"No trace for %s (%s:%d) at byte offset %ld\n",
506510
PyUnicode_AsUTF8(code->co_qualname),
507511
PyUnicode_AsUTF8(code->co_filename),
508512
code->co_firstlineno,
509-
(long)(instr - (_Py_CODEUNIT *)code->co_code_adaptive));
513+
2 * (long)(initial_instr - (_Py_CODEUNIT *)code->co_code_adaptive));
510514
}
511515
return 0;
512516

0 commit comments

Comments
 (0)