Skip to content

Commit d41f4fc

Browse files
jbower-fbmeta-codesync[bot]
authored andcommitted
Fix generator exception state setup on deopt in Python 3.15
Summary: In Python 3.15, generator expressions may include bytecodes before `RETURN_GENERATOR` that can raise exceptions (e.g., `GET_ITER` on a non-iterable). When the JIT deopts due to such an exception, the interpreter expects `tstate->exc_info` to point to the generator's exception state for generator frames. This change adds code in `resumeInInterpreter()` to properly link the exception state before calling `_PyEval_EvalFrame()`. We only set this up if not already configured (to avoid conflicts with `jitgen_am_send` which may have already set it up). The interpreter's `clear_gen_frame()` handles restoring the previous exception state, so no cleanup is needed after `_PyEval_EvalFrame()` returns. Reviewed By: DinoV Differential Revision: D91188235 fbshipit-source-id: 4d3b51ab37d8d207162dc1b3f96d70c43f4d7726
1 parent 19b2af5 commit d41f4fc

1 file changed

Lines changed: 18 additions & 0 deletions

File tree

cinderx/Jit/codegen/gen_asm.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,24 @@ PyObject* resumeInInterpreter(
351351
JIT_CHECK(
352352
_Py_Instrument(frameCode(frame), tstate->interp) == 0,
353353
"Failed to instrument code on deopt");
354+
355+
// For generator frames, ensure the exception state is properly linked
356+
// before resuming in the interpreter. In Python 3.15+, generator
357+
// expressions may raise exceptions before RETURN_GENERATOR (e.g., GET_ITER
358+
// on a non-iterable). The interpreter expects tstate->exc_info to point to
359+
// the generator's exception state for generator frames.
360+
// The interpreter's clear_gen_frame() will handle restoring the previous
361+
// exception state, so we don't need to do any cleanup after
362+
// _PyEval_EvalFrame. Note: We only set this up if it's not already set
363+
// (e.g., jitgen_am_send may have already set it up before we got here).
364+
if (frame->owner == FRAME_OWNED_BY_GENERATOR) {
365+
PyGenObject* gen = _PyGen_GetGeneratorFromFrame(frame);
366+
if (tstate->exc_info != &gen->gi_exc_state) {
367+
gen->gi_exc_state.previous_item = tstate->exc_info;
368+
tstate->exc_info = &gen->gi_exc_state;
369+
}
370+
}
371+
354372
result = _PyEval_EvalFrame(tstate, frame, err_occurred);
355373

356374
frame = prev_frame;

0 commit comments

Comments
 (0)