Skip to content

Commit 878cfb2

Browse files
committed
Fix up details including rejecting use of stack_pointer when spilled
1 parent 0ab3cfe commit 878cfb2

File tree

6 files changed

+53
-29
lines changed

6 files changed

+53
-29
lines changed

Include/internal/pycore_optimizer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ extern int _Py_uop_frame_pop(JitOptContext *ctx);
282282

283283
PyAPI_FUNC(PyObject *) _Py_uop_symbols_test(PyObject *self, PyObject *ignored);
284284

285-
PyAPI_FUNC(int) _PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyStackRef *stack_pointer, _PyExecutorObject **exec_ptr, int chain_depth);
285+
PyAPI_FUNC(int) _PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, _PyExecutorObject **exec_ptr, int chain_depth);
286286

287287
static inline int is_terminator(const _PyUOpInstruction *uop)
288288
{

Python/bytecodes.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2808,7 +2808,7 @@ dummy_func(
28082808
start--;
28092809
}
28102810
_PyExecutorObject *executor;
2811-
int optimized = _PyOptimizer_Optimize(frame, start, stack_pointer, &executor, 0);
2811+
int optimized = _PyOptimizer_Optimize(frame, start, &executor, 0);
28122812
if (optimized <= 0) {
28132813
this_instr[1].counter = restart_backoff_counter(counter);
28142814
ERROR_IF(optimized < 0, error);
@@ -5021,7 +5021,7 @@ dummy_func(
50215021
}
50225022
else {
50235023
int chain_depth = current_executor->vm_data.chain_depth + 1;
5024-
int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, chain_depth);
5024+
int optimized = _PyOptimizer_Optimize(frame, target, &executor, chain_depth);
50255025
if (optimized <= 0) {
50265026
exit->temperature = restart_backoff_counter(temperature);
50275027
if (optimized < 0) {
@@ -5122,7 +5122,7 @@ dummy_func(
51225122
exit->temperature = advance_backoff_counter(exit->temperature);
51235123
GOTO_TIER_ONE(target);
51245124
}
5125-
int optimized = _PyOptimizer_Optimize(frame, target, stack_pointer, &executor, 0);
5125+
int optimized = _PyOptimizer_Optimize(frame, target, &executor, 0);
51265126
if (optimized <= 0) {
51275127
exit->temperature = restart_backoff_counter(exit->temperature);
51285128
if (optimized < 0) {
@@ -5208,7 +5208,6 @@ dummy_func(
52085208
}
52095209

52105210
label(error) {
5211-
SAVE_STACK();
52125211
/* Double-check exception status. */
52135212
#ifdef NDEBUG
52145213
if (!_PyErr_Occurred(tstate)) {
@@ -5239,38 +5238,37 @@ dummy_func(
52395238
if (handled == 0) {
52405239
// No handlers, so exit.
52415240
assert(_PyErr_Occurred(tstate));
5242-
52435241
/* Pop remaining stack entries. */
52445242
_PyStackRef *stackbase = _PyFrame_Stackbase(frame);
5245-
while (stack_pointer > stackbase) {
5246-
PyStackRef_XCLOSE(POP());
5243+
while (frame->stackpointer > stackbase) {
5244+
_PyStackRef ref = _PyFrame_StackPop(frame);
5245+
PyStackRef_XCLOSE(ref);
52475246
}
5248-
assert(STACK_LEVEL() == 0);
5249-
_PyFrame_SetStackPointer(frame, stack_pointer);
52505247
monitor_unwind(tstate, frame, next_instr-1);
52515248
goto exit_unwind;
52525249
}
5253-
52545250
assert(STACK_LEVEL() >= level);
52555251
_PyStackRef *new_top = _PyFrame_Stackbase(frame) + level;
5256-
while (stack_pointer > new_top) {
5257-
PyStackRef_XCLOSE(POP());
5252+
assert(frame->stackpointer >= new_top);
5253+
while (frame->stackpointer > new_top) {
5254+
_PyStackRef ref = _PyFrame_StackPop(frame);
5255+
PyStackRef_XCLOSE(ref);
52585256
}
52595257
if (lasti) {
52605258
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
52615259
PyObject *lasti = PyLong_FromLong(frame_lasti);
52625260
if (lasti == NULL) {
52635261
goto exception_unwind;
52645262
}
5265-
PUSH(PyStackRef_FromPyObjectSteal(lasti));
5263+
_PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(lasti));
52665264
}
52675265

52685266
/* Make the raw exception data
52695267
available to the handler,
52705268
so a program can emulate the
52715269
Python main loop. */
52725270
PyObject *exc = _PyErr_GetRaisedException(tstate);
5273-
PUSH(PyStackRef_FromPyObjectSteal(exc));
5271+
_PyFrame_StackPush(frame, PyStackRef_FromPyObjectSteal(exc));
52745272
next_instr = _PyFrame_GetBytecode(frame) + handler;
52755273

52765274
int err = monitor_handled(tstate, frame, next_instr, exc);

Python/executor_cases.c.h

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

Python/generated_cases.c.h

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

Python/optimizer.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ uop_optimize(_PyInterpreterFrame *frame, _Py_CODEUNIT *instr,
105105
int
106106
_PyOptimizer_Optimize(
107107
_PyInterpreterFrame *frame, _Py_CODEUNIT *start,
108-
_PyStackRef *stack_pointer, _PyExecutorObject **executor_ptr, int chain_depth)
108+
_PyExecutorObject **executor_ptr, int chain_depth)
109109
{
110+
_PyStackRef *stack_pointer = frame->stackpointer;
110111
assert(_PyInterpreterState_GET()->jit);
111112
// The first executor in a chain and the MAX_CHAIN_DEPTH'th executor *must*
112113
// make progress in order to avoid infinite loops or excessively-long

Tools/cases_generator/generators_common.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ def __init__(self, out: CWriter, labels: dict[str, Label]):
129129
"INSTRUCTION_SIZE": self.instruction_size,
130130
"POP_INPUT": self.pop_input,
131131
"GO_TO_INSTRUCTION": self.go_to_instruction,
132+
"stack_pointer": self.stack_pointer,
132133
}
133134
self.out = out
134135
self.labels = labels
@@ -141,6 +142,8 @@ def dispatch(
141142
storage: Storage,
142143
inst: Instruction | None,
143144
) -> bool:
145+
if storage.spilled:
146+
raise analysis_error("stack_pointer needs reloading before dispatch", tkn)
144147
self.emit(tkn)
145148
return False
146149

@@ -402,6 +405,19 @@ def go_to_instruction(
402405
self.emit(f"goto PREDICTED_{name.text};\n")
403406
return True
404407

408+
def stack_pointer(
409+
self,
410+
tkn: Token,
411+
tkn_iter: TokenIterator,
412+
uop: CodeSection,
413+
storage: Storage,
414+
inst: Instruction | None,
415+
) -> bool:
416+
if storage.spilled:
417+
raise analysis_error("stack_pointer is invalid when stack is spilled to memory", tkn)
418+
self.emit(tkn)
419+
return True
420+
405421
def goto_label(self, goto: Token, label: Token, storage: Storage) -> None:
406422
if label.text not in self.labels:
407423
print(self.labels.keys())
@@ -411,7 +427,7 @@ def goto_label(self, goto: Token, label: Token, storage: Storage) -> None:
411427
if not storage.spilled:
412428
self.emit_save(storage)
413429
elif storage.spilled:
414-
raise analysis_error("Cannot goto spilled label without saving the stack", goto)
430+
raise analysis_error("Cannot jump from spilled label without reloading the stack pointer", goto)
415431
self.out.emit(goto)
416432
self.out.emit(label)
417433

0 commit comments

Comments
 (0)