Skip to content

Commit a9d56e3

Browse files
authored
GH-122155: Track local variables between pops and pushes in cases generator (GH-122286)
1 parent 46f5a4f commit a9d56e3

13 files changed

+463
-159
lines changed

Include/internal/pycore_opcode_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_generated_cases.py

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def skip_if_different_mount_drives():
3131
with test_tools.imports_under_tool("cases_generator"):
3232
from analyzer import StackItem
3333
import parser
34-
from stack import Stack
34+
from stack import Local, Stack
3535
import tier1_generator
3636
import optimizer_generator
3737

@@ -60,9 +60,9 @@ def test_effect_sizes(self):
6060
stack.pop(y)
6161
stack.pop(x)
6262
for out in outputs:
63-
stack.push(out)
64-
self.assertEqual(stack.base_offset.to_c(), "-1 - oparg*2 - oparg")
65-
self.assertEqual(stack.top_offset.to_c(), "1 - oparg*2 - oparg + oparg*4")
63+
stack.push(Local.local(out))
64+
self.assertEqual(stack.base_offset.to_c(), "-1 - oparg - oparg*2")
65+
self.assertEqual(stack.top_offset.to_c(), "1 - oparg - oparg*2 + oparg*4")
6666

6767

6868
class TestGeneratedCases(unittest.TestCase):
@@ -602,7 +602,11 @@ def test_array_error_if(self):
602602
frame->instr_ptr = next_instr;
603603
next_instr += 1;
604604
INSTRUCTION_STATS(OP);
605-
if (oparg == 0) { stack_pointer += -1 - oparg; goto somewhere; }
605+
if (oparg == 0) {
606+
stack_pointer += -1 - oparg;
607+
assert(WITHIN_STACK_BOUNDS());
608+
goto somewhere;
609+
}
606610
stack_pointer += -1 - oparg;
607611
assert(WITHIN_STACK_BOUNDS());
608612
DISPATCH();
@@ -908,19 +912,17 @@ def test_used_unused_used(self):
908912
next_instr += 1;
909913
INSTRUCTION_STATS(TEST);
910914
_PyStackRef w;
911-
_PyStackRef x;
912915
_PyStackRef y;
913916
// FIRST
914917
w = stack_pointer[-1];
915918
{
916919
use(w);
917920
}
918921
// SECOND
919-
x = w;
920922
{
921923
}
922924
// THIRD
923-
y = x;
925+
y = w;
924926
{
925927
use(y);
926928
}
@@ -1024,6 +1026,7 @@ def test_pop_on_error_peeks(self):
10241026
}
10251027
10261028
op(THIRD, (j, k --)) {
1029+
j,k; // Mark j and k as used
10271030
ERROR_IF(cond, error);
10281031
}
10291032
@@ -1054,6 +1057,7 @@ def test_pop_on_error_peeks(self):
10541057
k = b;
10551058
j = a;
10561059
{
1060+
j,k; // Mark j and k as used
10571061
if (cond) goto pop_2_error;
10581062
}
10591063
stack_pointer += -2;
@@ -1063,6 +1067,51 @@ def test_pop_on_error_peeks(self):
10631067
"""
10641068
self.run_cases_test(input, output)
10651069

1070+
def test_push_then_error(self):
1071+
1072+
input = """
1073+
op(FIRST, ( -- a)) {
1074+
a = 1;
1075+
}
1076+
1077+
op(SECOND, (a -- a, b)) {
1078+
b = 1;
1079+
ERROR_IF(cond, error);
1080+
}
1081+
1082+
macro(TEST) = FIRST + SECOND;
1083+
"""
1084+
1085+
output = """
1086+
TARGET(TEST) {
1087+
frame->instr_ptr = next_instr;
1088+
next_instr += 1;
1089+
INSTRUCTION_STATS(TEST);
1090+
_PyStackRef a;
1091+
_PyStackRef b;
1092+
// FIRST
1093+
{
1094+
a = 1;
1095+
}
1096+
// SECOND
1097+
{
1098+
b = 1;
1099+
if (cond) {
1100+
stack_pointer[0] = a;
1101+
stack_pointer += 1;
1102+
assert(WITHIN_STACK_BOUNDS());
1103+
goto error;
1104+
}
1105+
}
1106+
stack_pointer[0] = a;
1107+
stack_pointer[1] = b;
1108+
stack_pointer += 2;
1109+
assert(WITHIN_STACK_BOUNDS());
1110+
DISPATCH();
1111+
}
1112+
"""
1113+
self.run_cases_test(input, output)
1114+
10661115

10671116
class TestGeneratedAbstractCases(unittest.TestCase):
10681117
def setUp(self) -> None:

Python/bytecodes.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1357,8 +1357,8 @@ dummy_func(
13571357
(void)counter;
13581358
}
13591359

1360-
op(_UNPACK_SEQUENCE, (seq -- unused[oparg])) {
1361-
_PyStackRef *top = stack_pointer + oparg - 1;
1360+
op(_UNPACK_SEQUENCE, (seq -- output[oparg])) {
1361+
_PyStackRef *top = output + oparg;
13621362
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg, -1, top);
13631363
DECREF_INPUTS();
13641364
ERROR_IF(res == 0, error);
@@ -1401,9 +1401,8 @@ dummy_func(
14011401
DECREF_INPUTS();
14021402
}
14031403

1404-
inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) {
1405-
int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
1406-
_PyStackRef *top = stack_pointer + totalargs - 1;
1404+
inst(UNPACK_EX, (seq -- left[oparg & 0xFF], unused, right[oparg >> 8])) {
1405+
_PyStackRef *top = right + (oparg >> 8);
14071406
int res = _PyEval_UnpackIterableStackRef(tstate, seq, oparg & 0xFF, oparg >> 8, top);
14081407
DECREF_INPUTS();
14091408
ERROR_IF(res == 0, error);

Python/executor_cases.c.h

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

0 commit comments

Comments
 (0)