Skip to content

Commit 9162da2

Browse files
authored
[3.13] GH-122155: Fix cases generator to correctly compute 'peek' offset for error handling (GH-122158) (GH-122174)
1 parent 9059780 commit 9162da2

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

Lib/test/test_generated_cases.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,56 @@ def test_deopt_and_exit(self):
813813
with self.assertRaises(Exception):
814814
self.run_cases_test(input, output)
815815

816+
def test_pop_on_error_peeks(self):
817+
818+
input = """
819+
op(FIRST, (x, y -- a, b)) {
820+
a = x;
821+
b = y;
822+
}
823+
824+
op(SECOND, (a, b -- a, b)) {
825+
}
826+
827+
op(THIRD, (j, k --)) {
828+
ERROR_IF(cond, error);
829+
}
830+
831+
macro(TEST) = FIRST + SECOND + THIRD;
832+
"""
833+
output = """
834+
TARGET(TEST) {
835+
frame->instr_ptr = next_instr;
836+
next_instr += 1;
837+
INSTRUCTION_STATS(TEST);
838+
PyObject *y;
839+
PyObject *x;
840+
PyObject *a;
841+
PyObject *b;
842+
PyObject *k;
843+
PyObject *j;
844+
// FIRST
845+
y = stack_pointer[-1];
846+
x = stack_pointer[-2];
847+
{
848+
a = x;
849+
b = y;
850+
}
851+
// SECOND
852+
{
853+
}
854+
// THIRD
855+
k = b;
856+
j = a;
857+
{
858+
if (cond) goto pop_2_error;
859+
}
860+
stack_pointer += -2;
861+
DISPATCH();
862+
}
863+
"""
864+
self.run_cases_test(input, output)
865+
816866
class TestGeneratedAbstractCases(unittest.TestCase):
817867
def setUp(self) -> None:
818868
super().setUp()

Tools/cases_generator/analyzer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,13 @@ def analyze_stack(op: parser.InstDef, replace_op_arg_1: str | None = None) -> St
300300
convert_stack_item(i, replace_op_arg_1) for i in op.inputs if isinstance(i, parser.StackEffect)
301301
]
302302
outputs: list[StackItem] = [convert_stack_item(i, replace_op_arg_1) for i in op.outputs]
303+
# Mark variables with matching names at the base of the stack as "peek"
304+
modified = False
303305
for input, output in zip(inputs, outputs):
304-
if input.name == output.name:
306+
if input.name == output.name and not modified:
305307
input.peek = output.peek = True
308+
else:
309+
modified = True
306310
return StackEffect(inputs, outputs)
307311

308312

Tools/cases_generator/generators_common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def replace_error(
8484
next(tkn_iter) # RPAREN
8585
next(tkn_iter) # Semi colon
8686
out.emit(") ")
87-
c_offset = stack.peek_offset.to_c()
87+
c_offset = stack.peek_offset()
8888
try:
8989
offset = -int(c_offset)
9090
close = ";\n"

Tools/cases_generator/stack.py

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

50+
def copy(self) -> "StackOffset":
51+
return StackOffset(self.popped[:], self.pushed[:])
52+
5053
def pop(self, item: StackItem) -> None:
5154
self.popped.append(var_size(item))
5255

@@ -120,14 +123,11 @@ class Stack:
120123
def __init__(self) -> None:
121124
self.top_offset = StackOffset.empty()
122125
self.base_offset = StackOffset.empty()
123-
self.peek_offset = StackOffset.empty()
124126
self.variables: list[StackItem] = []
125127
self.defined: set[str] = set()
126128

127129
def pop(self, var: StackItem) -> str:
128130
self.top_offset.pop(var)
129-
if not var.peek:
130-
self.peek_offset.pop(var)
131131
indirect = "&" if var.is_array() else ""
132132
if self.variables:
133133
popped = self.variables.pop()
@@ -201,9 +201,16 @@ def flush(self, out: CWriter, cast_type: str = "PyObject *") -> None:
201201
self.variables = []
202202
self.base_offset.clear()
203203
self.top_offset.clear()
204-
self.peek_offset.clear()
205204
out.start_line()
206205

206+
def peek_offset(self) -> str:
207+
peek = self.base_offset.copy()
208+
for var in self.variables:
209+
if not var.peek:
210+
break
211+
peek.push(var)
212+
return peek.to_c()
213+
207214
def as_comment(self) -> str:
208215
return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */"
209216

0 commit comments

Comments
 (0)