Skip to content

Commit 85397f7

Browse files
markshannonaisk
authored andcommitted
pythonGH-108866: Guarantee forward progress in executors. (pythonGH-113006)
1 parent b9a31a1 commit 85397f7

File tree

7 files changed

+19
-21
lines changed

7 files changed

+19
-21
lines changed

Include/cpython/optimizer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ typedef struct {
3232
typedef struct _PyExecutorObject {
3333
PyObject_VAR_HEAD
3434
/* WARNING: execute consumes a reference to self. This is necessary to allow executors to tail call into each other. */
35-
struct _PyInterpreterFrame *(*execute)(struct _PyExecutorObject *self, struct _PyInterpreterFrame *frame, PyObject **stack_pointer);
35+
_Py_CODEUNIT *(*execute)(struct _PyExecutorObject *self, struct _PyInterpreterFrame *frame, PyObject **stack_pointer);
3636
_PyVMData vm_data; /* Used by the VM, but opaque to the optimizer */
3737
/* Data needed by the executor goes here, but is opaque to the VM */
3838
} _PyExecutorObject;

Include/internal/pycore_opcode_metadata.h

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

Include/internal/pycore_uops.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ typedef struct {
2424
_PyUOpInstruction trace[1];
2525
} _PyUOpExecutorObject;
2626

27-
_PyInterpreterFrame *_PyUOpExecute(
27+
_Py_CODEUNIT *_PyUOpExecute(
2828
_PyExecutorObject *executor,
2929
_PyInterpreterFrame *frame,
3030
PyObject **stack_pointer);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Change the API and contract of ``_PyExecutorObject`` to return the
2+
next_instr pointer, instead of the frame, and to always execute at least one
3+
instruction.

Python/bytecodes.c

+4-7
Original file line numberDiff line numberDiff line change
@@ -2352,20 +2352,17 @@ dummy_func(
23522352

23532353
PyCodeObject *code = _PyFrame_GetCode(frame);
23542354
_PyExecutorObject *executor = (_PyExecutorObject *)code->co_executors->executors[oparg&255];
2355-
int original_oparg = executor->vm_data.oparg | (oparg & 0xfffff00);
2356-
JUMPBY(1-original_oparg);
2357-
frame->instr_ptr = next_instr;
23582355
Py_INCREF(executor);
23592356
if (executor->execute == _PyUOpExecute) {
23602357
current_executor = (_PyUOpExecutorObject *)executor;
23612358
GOTO_TIER_TWO();
23622359
}
2363-
frame = executor->execute(executor, frame, stack_pointer);
2364-
if (frame == NULL) {
2365-
frame = tstate->current_frame;
2360+
next_instr = executor->execute(executor, frame, stack_pointer);
2361+
frame = tstate->current_frame;
2362+
if (next_instr == NULL) {
23662363
goto resume_with_error;
23672364
}
2368-
goto enter_tier_one;
2365+
stack_pointer = _PyFrame_GetStackPointer(frame);
23692366
}
23702367

23712368
replaced op(_POP_JUMP_IF_FALSE, (unused/1, cond -- )) {

Python/generated_cases.c.h

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

Python/optimizer.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ _PyOptimizer_BackEdge(_PyInterpreterFrame *frame, _Py_CODEUNIT *src, _Py_CODEUNI
167167
}
168168
_PyOptimizerObject *opt = interp->optimizer;
169169
_PyExecutorObject *executor = NULL;
170+
/* Start optimizing at the destination to guarantee forward progress */
170171
int err = opt->optimize(opt, code, dest, &executor, (int)(stack_pointer - _PyFrame_Stackbase(frame)));
171172
if (err <= 0) {
172173
assert(executor == NULL);
@@ -247,14 +248,13 @@ PyTypeObject _PyCounterExecutor_Type = {
247248
.tp_methods = executor_methods,
248249
};
249250

250-
static _PyInterpreterFrame *
251+
static _Py_CODEUNIT *
251252
counter_execute(_PyExecutorObject *self, _PyInterpreterFrame *frame, PyObject **stack_pointer)
252253
{
253254
((_PyCounterExecutorObject *)self)->optimizer->count++;
254255
_PyFrame_SetStackPointer(frame, stack_pointer);
255-
frame->instr_ptr = ((_PyCounterExecutorObject *)self)->next_instr;
256256
Py_DECREF(self);
257-
return frame;
257+
return ((_PyCounterExecutorObject *)self)->next_instr;
258258
}
259259

260260
static int
@@ -891,7 +891,7 @@ uop_optimize(
891891
/* Dummy execute() function for UOp Executor.
892892
* The actual implementation is inlined in ceval.c,
893893
* in _PyEval_EvalFrameDefault(). */
894-
_PyInterpreterFrame *
894+
_Py_CODEUNIT *
895895
_PyUOpExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer)
896896
{
897897
Py_FatalError("Tier 2 is now inlined into Tier 1");

0 commit comments

Comments
 (0)