Skip to content

Commit 0ffc2dd

Browse files
Fix bug where code/func get freed halfway
1 parent dc414a3 commit 0ffc2dd

File tree

5 files changed

+28
-11
lines changed

5 files changed

+28
-11
lines changed

Include/internal/pycore_interp_structs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -951,8 +951,8 @@ struct _is {
951951
_Py_CODEUNIT *jit_tracer_initial_instr;
952952
int jit_tracer_initial_stack_depth;
953953
int jit_tracer_initial_chain_depth;
954-
PyCodeObject *jit_tracer_initial_code; // Borrowed
955-
PyFunctionObject *jit_tracer_initial_func; // Borrowed
954+
PyCodeObject *jit_tracer_initial_code; // Strong
955+
PyFunctionObject *jit_tracer_initial_func; // Strong
956956
struct _PyExitData *jit_tracer_previous_exit;
957957
bool jit_completed_loop;
958958
bool jit;

Include/internal/pycore_optimizer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ _PyJIT_translate_single_bytecode_to_trace(
372372

373373
void
374374
_PyJIT_InitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_CODEUNIT *next_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit);
375+
376+
void _PyJIT_FinalizeTracing(PyThreadState *tstate);
375377
#ifdef __cplusplus
376378
}
377379
#endif

Python/ceval_macros.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,21 +141,22 @@
141141
# define LEAVE_TRACING() DISPATCH_TABLE_VAR = DISPATCH_TABLE;
142142
# define BAIL_TRACING_NO_DISPATCH() \
143143
LEAVE_TRACING(); \
144+
_PyFrame_SetStackPointer(frame, stack_pointer); \
144145
int _err = _PyOptimizer_Optimize(frame, tstate); \
146+
_PyJIT_FinalizeTracing(tstate); \
147+
stack_pointer = _PyFrame_GetStackPointer(frame); \
145148
if (_err < 0) { \
146149
JUMP_TO_LABEL(error); \
147150
}
148151
# define BAIL_TRACING() \
149152
BAIL_TRACING_NO_DISPATCH() \
150153
DISPATCH();
151154
# define RECORD_TRACE() do { \
152-
frame->instr_ptr = next_instr; \
153155
if (add_to_code_trace(tstate, frame, old_code, old_func, this_instr, next_instr, opcode, oparg, _jump_taken)) { \
154156
BAIL_TRACING(); \
155157
} \
156158
} while (0);
157159
# define RECORD_TRACE_NO_DISPATCH() do { \
158-
frame->instr_ptr = next_instr; \
159160
if (add_to_code_trace(tstate, frame, old_code, old_func, this_instr, next_instr, opcode, oparg, _jump_taken)) { \
160161
BAIL_TRACING_NO_DISPATCH(); \
161162
} \
@@ -413,6 +414,7 @@ _PyFrame_SetStackPointer(frame, stack_pointer)
413414

414415
#define TIER1_TO_TIER2(EXECUTOR) \
415416
do { \
417+
LEAVE_TRACING(); \
416418
OPT_STAT_INC(traces_executed); \
417419
next_instr = _Py_jit_entry((EXECUTOR), frame, stack_pointer, tstate); \
418420
frame = tstate->current_frame; \
@@ -428,9 +430,6 @@ do { \
428430
assert(tstate->interp->jit_tracer_code_curr_size == 2); \
429431
ENTER_TRACING(); \
430432
} \
431-
else { \
432-
LEAVE_TRACING(); \
433-
} \
434433
DISPATCH(); \
435434
} while (0)
436435

Python/generated_cases.c.h

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,18 @@ _PyOptimizer_Optimize(
129129
// side-exit chains. We can only insert the executor into the bytecode if
130130
// this is true, since a deopt won't infinitely re-enter the executor:
131131
bool progress_needed = (chain_depth % MAX_CHAIN_DEPTH) == 0;
132-
PyCodeObject *code = (PyCodeObject *)tstate->interp->jit_tracer_initial_func->func_code;
133-
assert(PyCode_Check(code));
132+
PyCodeObject *code = (PyCodeObject *)tstate->interp->jit_tracer_initial_code;
134133
_Py_CODEUNIT *start = tstate->interp->jit_tracer_initial_instr;
135134
if (progress_needed && !has_space_for_executor(code, start)) {
136135
interp->compiling = false;
137136
return 0;
138137
}
138+
// We are the only one still holding a reference to this code object that
139+
// is practically dead.
140+
if (_PyObject_IsUniquelyReferenced(code) || _PyObject_IsUniquelyReferenced(tstate->interp->jit_tracer_initial_func)) {
141+
interp->compiling = false;
142+
return 0;
143+
}
139144
_PyExecutorObject *executor;
140145
int err = uop_optimize(frame, tstate, &executor, progress_needed);
141146
if (err <= 0) {
@@ -840,15 +845,24 @@ _PyJIT_InitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _Py_
840845
tstate->interp->jit_tracer_code_curr_size = 2;
841846
tstate->interp->jit_tracer_code_max_size = UOP_MAX_TRACE_LENGTH;
842847
tstate->interp->jit_tracer_initial_instr = next_instr;
843-
tstate->interp->jit_tracer_initial_code = code;
844-
tstate->interp->jit_tracer_initial_func = _PyFrame_GetFunction(frame);
848+
tstate->interp->jit_tracer_initial_code = (PyCodeObject *)Py_NewRef(code);
849+
tstate->interp->jit_tracer_initial_func = (PyFunctionObject *)Py_NewRef(_PyFrame_GetFunction(frame));
845850
tstate->interp->jit_tracer_previous_exit = exit;
846851
memset(&tstate->interp->jit_tracer_dependencies.bits, 0, sizeof(tstate->interp->jit_tracer_dependencies.bits));
847852
tstate->interp->jit_completed_loop = false;
848853
tstate->interp->jit_tracer_initial_stack_depth = curr_stackdepth;
849854
tstate->interp->jit_tracer_initial_chain_depth = chain_depth;
850855
}
851856

857+
void
858+
_PyJIT_FinalizeTracing(PyThreadState *tstate)
859+
{
860+
Py_CLEAR(tstate->interp->jit_tracer_initial_code);
861+
Py_CLEAR(tstate->interp->jit_tracer_initial_func);
862+
tstate->interp->jit_tracer_code_curr_size = 2;
863+
}
864+
865+
852866
#undef RESERVE
853867
#undef RESERVE_RAW
854868
#undef INSTR_IP

0 commit comments

Comments
 (0)