GH-104584: Don't call executors from JUMP_BACKWARD (GH-109347)

This commit is contained in:
Brandt Bucher 2023-09-13 10:26:50 -07:00 committed by GitHub
parent 22e65eecaa
commit 6c13e13b13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 23 additions and 40 deletions

View file

@ -40,7 +40,7 @@ PyAPI_FUNC(_PyOptimizerObject *) PyUnstable_GetOptimizer(void);
PyAPI_FUNC(_PyExecutorObject *) PyUnstable_GetExecutor(PyCodeObject *code, int offset); PyAPI_FUNC(_PyExecutorObject *) PyUnstable_GetExecutor(PyCodeObject *code, int offset);
struct _PyInterpreterFrame * int
_PyOptimizer_BackEdge(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer); _PyOptimizer_BackEdge(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer);
extern _PyOptimizerObject _PyOptimizer_Default; extern _PyOptimizerObject _PyOptimizer_Default;

View file

@ -2242,21 +2242,17 @@ dummy_func(
here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER); here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER);
if (here[1].cache > tstate->interp->optimizer_backedge_threshold && if (here[1].cache > tstate->interp->optimizer_backedge_threshold &&
// Double-check that the opcode isn't instrumented or something: // Double-check that the opcode isn't instrumented or something:
here->op.code == JUMP_BACKWARD && here->op.code == JUMP_BACKWARD)
// _PyOptimizer_BackEdge is going to change frame->prev_instr,
// which breaks line event calculations:
next_instr->op.code != INSTRUMENTED_LINE
)
{ {
OBJECT_STAT_INC(optimization_attempts); OBJECT_STAT_INC(optimization_attempts);
frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer); int optimized = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
if (frame == NULL) { ERROR_IF(optimized < 0, error);
frame = tstate->current_frame; if (optimized) {
goto resume_with_error; // Rewind and enter the executor:
assert(here->op.code == ENTER_EXECUTOR);
next_instr = here;
} }
assert(frame == tstate->current_frame); here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) - 1);
here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);
goto resume_frame;
} }
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
} }

View file

@ -2945,21 +2945,17 @@
here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER); here[1].cache += (1 << OPTIMIZER_BITS_IN_COUNTER);
if (here[1].cache > tstate->interp->optimizer_backedge_threshold && if (here[1].cache > tstate->interp->optimizer_backedge_threshold &&
// Double-check that the opcode isn't instrumented or something: // Double-check that the opcode isn't instrumented or something:
here->op.code == JUMP_BACKWARD && here->op.code == JUMP_BACKWARD)
// _PyOptimizer_BackEdge is going to change frame->prev_instr,
// which breaks line event calculations:
next_instr->op.code != INSTRUMENTED_LINE
)
{ {
OBJECT_STAT_INC(optimization_attempts); OBJECT_STAT_INC(optimization_attempts);
frame = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer); int optimized = _PyOptimizer_BackEdge(frame, here, next_instr, stack_pointer);
if (frame == NULL) { if (optimized < 0) goto error;
frame = tstate->current_frame; if (optimized) {
goto resume_with_error; // Rewind and enter the executor:
assert(here->op.code == ENTER_EXECUTOR);
next_instr = here;
} }
assert(frame == tstate->current_frame); here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) - 1);
here[1].cache &= ((1 << OPTIMIZER_BITS_IN_COUNTER) -1);
goto resume_frame;
} }
#endif /* ENABLE_SPECIALIZATION */ #endif /* ENABLE_SPECIALIZATION */
DISPATCH(); DISPATCH();

View file

@ -154,7 +154,7 @@ PyUnstable_SetOptimizer(_PyOptimizerObject *optimizer)
Py_DECREF(old); Py_DECREF(old);
} }
_PyInterpreterFrame * int
_PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer) _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNIT *dest, PyObject **stack_pointer)
{ {
assert(src->op.code == JUMP_BACKWARD); assert(src->op.code == JUMP_BACKWARD);
@ -162,18 +162,14 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
assert(PyCode_Check(code)); assert(PyCode_Check(code));
PyInterpreterState *interp = _PyInterpreterState_GET(); PyInterpreterState *interp = _PyInterpreterState_GET();
if (!has_space_for_executor(code, src)) { if (!has_space_for_executor(code, src)) {
goto jump_to_destination; return 0;
} }
_PyOptimizerObject *opt = interp->optimizer; _PyOptimizerObject *opt = interp->optimizer;
_PyExecutorObject *executor = NULL; _PyExecutorObject *executor = NULL;
int err = opt->optimize(opt, code, dest, &executor, (int)(stack_pointer - _PyFrame_Stackbase(frame))); int err = opt->optimize(opt, code, dest, &executor, (int)(stack_pointer - _PyFrame_Stackbase(frame)));
if (err <= 0) { if (err <= 0) {
assert(executor == NULL); assert(executor == NULL);
if (err < 0) { return err;
_PyFrame_SetStackPointer(frame, stack_pointer);
return NULL;
}
goto jump_to_destination;
} }
int index = get_index_for_executor(code, src); int index = get_index_for_executor(code, src);
if (index < 0) { if (index < 0) {
@ -184,16 +180,11 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
* it might get confused by the executor disappearing, * it might get confused by the executor disappearing,
* but there is not much we can do about that here. */ * but there is not much we can do about that here. */
Py_DECREF(executor); Py_DECREF(executor);
goto jump_to_destination; return 0;
} }
insert_executor(code, src, index, executor); insert_executor(code, src, index, executor);
assert(frame->prev_instr == src); Py_DECREF(executor);
frame->prev_instr = dest - 1; return 1;
return executor->execute(executor, frame, stack_pointer);
jump_to_destination:
frame->prev_instr = dest - 1;
_PyFrame_SetStackPointer(frame, stack_pointer);
return frame;
} }
_PyExecutorObject * _PyExecutorObject *