mirror of https://github.com/python/cpython
[3.13] GH-122155: Fix cases generator to correctly compute 'peek' offset for error handling (GH-122158) (GH-122174)
This commit is contained in:
parent
9059780987
commit
9162da254a
|
@ -813,6 +813,56 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
self.run_cases_test(input, output)
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
|
def test_pop_on_error_peeks(self):
|
||||||
|
|
||||||
|
input = """
|
||||||
|
op(FIRST, (x, y -- a, b)) {
|
||||||
|
a = x;
|
||||||
|
b = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
op(SECOND, (a, b -- a, b)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
op(THIRD, (j, k --)) {
|
||||||
|
ERROR_IF(cond, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
macro(TEST) = FIRST + SECOND + THIRD;
|
||||||
|
"""
|
||||||
|
output = """
|
||||||
|
TARGET(TEST) {
|
||||||
|
frame->instr_ptr = next_instr;
|
||||||
|
next_instr += 1;
|
||||||
|
INSTRUCTION_STATS(TEST);
|
||||||
|
PyObject *y;
|
||||||
|
PyObject *x;
|
||||||
|
PyObject *a;
|
||||||
|
PyObject *b;
|
||||||
|
PyObject *k;
|
||||||
|
PyObject *j;
|
||||||
|
// FIRST
|
||||||
|
y = stack_pointer[-1];
|
||||||
|
x = stack_pointer[-2];
|
||||||
|
{
|
||||||
|
a = x;
|
||||||
|
b = y;
|
||||||
|
}
|
||||||
|
// SECOND
|
||||||
|
{
|
||||||
|
}
|
||||||
|
// THIRD
|
||||||
|
k = b;
|
||||||
|
j = a;
|
||||||
|
{
|
||||||
|
if (cond) goto pop_2_error;
|
||||||
|
}
|
||||||
|
stack_pointer += -2;
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
class TestGeneratedAbstractCases(unittest.TestCase):
|
class TestGeneratedAbstractCases(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
|
@ -300,9 +300,13 @@ def analyze_stack(op: parser.InstDef, replace_op_arg_1: str | None = None) -> St
|
||||||
convert_stack_item(i, replace_op_arg_1) for i in op.inputs if isinstance(i, parser.StackEffect)
|
convert_stack_item(i, replace_op_arg_1) for i in op.inputs if isinstance(i, parser.StackEffect)
|
||||||
]
|
]
|
||||||
outputs: list[StackItem] = [convert_stack_item(i, replace_op_arg_1) for i in op.outputs]
|
outputs: list[StackItem] = [convert_stack_item(i, replace_op_arg_1) for i in op.outputs]
|
||||||
|
# Mark variables with matching names at the base of the stack as "peek"
|
||||||
|
modified = False
|
||||||
for input, output in zip(inputs, outputs):
|
for input, output in zip(inputs, outputs):
|
||||||
if input.name == output.name:
|
if input.name == output.name and not modified:
|
||||||
input.peek = output.peek = True
|
input.peek = output.peek = True
|
||||||
|
else:
|
||||||
|
modified = True
|
||||||
return StackEffect(inputs, outputs)
|
return StackEffect(inputs, outputs)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ def replace_error(
|
||||||
next(tkn_iter) # RPAREN
|
next(tkn_iter) # RPAREN
|
||||||
next(tkn_iter) # Semi colon
|
next(tkn_iter) # Semi colon
|
||||||
out.emit(") ")
|
out.emit(") ")
|
||||||
c_offset = stack.peek_offset.to_c()
|
c_offset = stack.peek_offset()
|
||||||
try:
|
try:
|
||||||
offset = -int(c_offset)
|
offset = -int(c_offset)
|
||||||
close = ";\n"
|
close = ";\n"
|
||||||
|
|
|
@ -47,6 +47,9 @@ class StackOffset:
|
||||||
def empty() -> "StackOffset":
|
def empty() -> "StackOffset":
|
||||||
return StackOffset([], [])
|
return StackOffset([], [])
|
||||||
|
|
||||||
|
def copy(self) -> "StackOffset":
|
||||||
|
return StackOffset(self.popped[:], self.pushed[:])
|
||||||
|
|
||||||
def pop(self, item: StackItem) -> None:
|
def pop(self, item: StackItem) -> None:
|
||||||
self.popped.append(var_size(item))
|
self.popped.append(var_size(item))
|
||||||
|
|
||||||
|
@ -120,14 +123,11 @@ class Stack:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.top_offset = StackOffset.empty()
|
self.top_offset = StackOffset.empty()
|
||||||
self.base_offset = StackOffset.empty()
|
self.base_offset = StackOffset.empty()
|
||||||
self.peek_offset = StackOffset.empty()
|
|
||||||
self.variables: list[StackItem] = []
|
self.variables: list[StackItem] = []
|
||||||
self.defined: set[str] = set()
|
self.defined: set[str] = set()
|
||||||
|
|
||||||
def pop(self, var: StackItem) -> str:
|
def pop(self, var: StackItem) -> str:
|
||||||
self.top_offset.pop(var)
|
self.top_offset.pop(var)
|
||||||
if not var.peek:
|
|
||||||
self.peek_offset.pop(var)
|
|
||||||
indirect = "&" if var.is_array() else ""
|
indirect = "&" if var.is_array() else ""
|
||||||
if self.variables:
|
if self.variables:
|
||||||
popped = self.variables.pop()
|
popped = self.variables.pop()
|
||||||
|
@ -201,9 +201,16 @@ class Stack:
|
||||||
self.variables = []
|
self.variables = []
|
||||||
self.base_offset.clear()
|
self.base_offset.clear()
|
||||||
self.top_offset.clear()
|
self.top_offset.clear()
|
||||||
self.peek_offset.clear()
|
|
||||||
out.start_line()
|
out.start_line()
|
||||||
|
|
||||||
|
def peek_offset(self) -> str:
|
||||||
|
peek = self.base_offset.copy()
|
||||||
|
for var in self.variables:
|
||||||
|
if not var.peek:
|
||||||
|
break
|
||||||
|
peek.push(var)
|
||||||
|
return peek.to_c()
|
||||||
|
|
||||||
def as_comment(self) -> str:
|
def as_comment(self) -> str:
|
||||||
return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */"
|
return f"/* Variables: {[v.name for v in self.variables]}. Base offset: {self.base_offset.to_c()}. Top offset: {self.top_offset.to_c()} */"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue