Skip to content

Commit 624bda7

Browse files
authored
GH-122155: Fix cases generator to correctly compute 'peek' offset for error handling (GH-122158)
1 parent 498cb6d commit 624bda7

File tree

4 files changed

+68
-6
lines changed

4 files changed

+68
-6
lines changed

Lib/test/test_generated_cases.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,57 @@ def test_flush(self):
10121012
"""
10131013
self.run_cases_test(input, output)
10141014

1015+
def test_pop_on_error_peeks(self):
1016+
1017+
input = """
1018+
op(FIRST, (x, y -- a, b)) {
1019+
a = x;
1020+
b = y;
1021+
}
1022+
1023+
op(SECOND, (a, b -- a, b)) {
1024+
}
1025+
1026+
op(THIRD, (j, k --)) {
1027+
ERROR_IF(cond, error);
1028+
}
1029+
1030+
macro(TEST) = FIRST + SECOND + THIRD;
1031+
"""
1032+
output = """
1033+
TARGET(TEST) {
1034+
frame->instr_ptr = next_instr;
1035+
next_instr += 1;
1036+
INSTRUCTION_STATS(TEST);
1037+
_PyStackRef x;
1038+
_PyStackRef y;
1039+
_PyStackRef a;
1040+
_PyStackRef b;
1041+
_PyStackRef j;
1042+
_PyStackRef k;
1043+
// FIRST
1044+
y = stack_pointer[-1];
1045+
x = stack_pointer[-2];
1046+
{
1047+
a = x;
1048+
b = y;
1049+
}
1050+
// SECOND
1051+
{
1052+
}
1053+
// THIRD
1054+
k = b;
1055+
j = a;
1056+
{
1057+
if (cond) goto pop_2_error;
1058+
}
1059+
stack_pointer += -2;
1060+
assert(WITHIN_STACK_BOUNDS());
1061+
DISPATCH();
1062+
}
1063+
"""
1064+
self.run_cases_test(input, output)
1065+
10151066

10161067
class TestGeneratedAbstractCases(unittest.TestCase):
10171068
def setUp(self) -> None:

Tools/cases_generator/analyzer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,13 @@ def analyze_stack(op: parser.InstDef | parser.Pseudo, replace_op_arg_1: str | No
317317
convert_stack_item(i, replace_op_arg_1) for i in op.inputs if isinstance(i, parser.StackEffect)
318318
]
319319
outputs: list[StackItem] = [convert_stack_item(i, replace_op_arg_1) for i in op.outputs]
320+
# Mark variables with matching names at the base of the stack as "peek"
321+
modified = False
320322
for input, output in zip(inputs, outputs):
321-
if input.name == output.name:
323+
if input.name == output.name and not modified:
322324
input.peek = output.peek = True
325+
else:
326+
modified = True
323327
if isinstance(op, parser.InstDef):
324328
output_names = [out.name for out in outputs]
325329
for input in inputs:

Tools/cases_generator/generators_common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def replace_error(
9292
next(tkn_iter) # RPAREN
9393
next(tkn_iter) # Semi colon
9494
out.emit(") ")
95-
c_offset = stack.peek_offset.to_c()
95+
c_offset = stack.peek_offset()
9696
try:
9797
offset = -int(c_offset)
9898
close = ";\n"

Tools/cases_generator/stack.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ class StackOffset:
4949
def empty() -> "StackOffset":
5050
return StackOffset([], [])
5151

52+
def copy(self) -> "StackOffset":
53+
return StackOffset(self.popped[:], self.pushed[:])
54+
5255
def pop(self, item: StackItem) -> None:
5356
self.popped.append(var_size(item))
5457

@@ -122,14 +125,11 @@ class Stack:
122125
def __init__(self) -> None:
123126
self.top_offset = StackOffset.empty()
124127
self.base_offset = StackOffset.empty()
125-
self.peek_offset = StackOffset.empty()
126128
self.variables: list[StackItem] = []
127129
self.defined: set[str] = set()
128130

129131
def pop(self, var: StackItem, extract_bits: bool = False) -> str:
130132
self.top_offset.pop(var)
131-
if not var.peek:
132-
self.peek_offset.pop(var)
133133
indirect = "&" if var.is_array() else ""
134134
if self.variables:
135135
popped = self.variables.pop()
@@ -210,9 +210,16 @@ def flush(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool =
210210
self.variables = []
211211
self.base_offset.clear()
212212
self.top_offset.clear()
213-
self.peek_offset.clear()
214213
out.start_line()
215214

215+
def peek_offset(self) -> str:
216+
peek = self.base_offset.copy()
217+
for var in self.variables:
218+
if not var.peek:
219+
break
220+
peek.push(var)
221+
return peek.to_c()
222+
216223
def as_comment(self) -> str:
217224
return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */"
218225

0 commit comments

Comments
 (0)