Skip to content

Commit 2082537

Browse files
Move labels in ceval.c to bytecodes.c
1 parent 38c3cf6 commit 2082537

File tree

11 files changed

+581
-108
lines changed

11 files changed

+581
-108
lines changed

Lib/test/test_generated_cases.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def skip_if_different_mount_drives():
3636
import parser
3737
from stack import Local, Stack
3838
import tier1_generator
39+
import labels_generator
3940
import opcode_metadata_generator
4041
import optimizer_generator
4142

@@ -1757,6 +1758,111 @@ def test_kill_in_wrong_order(self):
17571758
self.run_cases_test(input, "")
17581759

17591760

1761+
class TestGeneratedLabels(unittest.TestCase):
1762+
def setUp(self) -> None:
1763+
super().setUp()
1764+
self.maxDiff = None
1765+
1766+
self.temp_dir = tempfile.gettempdir()
1767+
self.temp_input_filename = os.path.join(self.temp_dir, "input.txt")
1768+
self.temp_output_filename = os.path.join(self.temp_dir, "output.txt")
1769+
self.temp_metadata_filename = os.path.join(self.temp_dir, "metadata.txt")
1770+
self.temp_pymetadata_filename = os.path.join(self.temp_dir, "pymetadata.txt")
1771+
self.temp_executor_filename = os.path.join(self.temp_dir, "executor.txt")
1772+
1773+
def tearDown(self) -> None:
1774+
for filename in [
1775+
self.temp_input_filename,
1776+
self.temp_output_filename,
1777+
self.temp_metadata_filename,
1778+
self.temp_pymetadata_filename,
1779+
self.temp_executor_filename,
1780+
]:
1781+
try:
1782+
os.remove(filename)
1783+
except Exception:
1784+
pass
1785+
super().tearDown()
1786+
1787+
def run_cases_test(self, input: str, expected: str):
1788+
with open(self.temp_input_filename, "w+") as temp_input:
1789+
temp_input.write(parser.BEGIN_MARKER)
1790+
temp_input.write(input)
1791+
temp_input.write(parser.END_MARKER)
1792+
temp_input.flush()
1793+
1794+
with handle_stderr():
1795+
labels_generator.generate_labels_from_files(
1796+
[self.temp_input_filename], self.temp_output_filename
1797+
)
1798+
1799+
with open(self.temp_output_filename) as temp_output:
1800+
lines = temp_output.readlines()
1801+
while lines and lines[0].startswith(("// ", "#", " #", "\n")):
1802+
lines.pop(0)
1803+
while lines and lines[-1].startswith(("#", "\n")):
1804+
lines.pop(-1)
1805+
actual = "".join(lines)
1806+
1807+
self.assertEqual(actual.strip(), expected.strip())
1808+
1809+
def test_complex_label(self):
1810+
input = """
1811+
label(my_label) {
1812+
// Comment
1813+
do_thing()
1814+
if (complex) {
1815+
goto other_label;
1816+
}
1817+
goto other_label2;
1818+
}
1819+
"""
1820+
1821+
output = """
1822+
my_label:
1823+
{
1824+
// Comment
1825+
do_thing()
1826+
if (complex) {
1827+
goto other_label;
1828+
}
1829+
goto other_label2;
1830+
}
1831+
"""
1832+
self.run_cases_test(input, output)
1833+
1834+
def test_multiple_labels(self):
1835+
input = """
1836+
label(my_label_1) {
1837+
// Comment
1838+
do_thing1();
1839+
goto my_label_2;
1840+
}
1841+
1842+
label(my_label_2) {
1843+
// Comment
1844+
do_thing2();
1845+
goto my_label_3;
1846+
}
1847+
"""
1848+
1849+
output = """
1850+
my_label_1:
1851+
{
1852+
// Comment
1853+
do_thing1();
1854+
goto my_label_2;
1855+
}
1856+
1857+
my_label_2:
1858+
{
1859+
// Comment
1860+
do_thing2();
1861+
goto my_label_3;
1862+
}
1863+
"""
1864+
self.run_cases_test(input, output)
1865+
17601866
class TestGeneratedAbstractCases(unittest.TestCase):
17611867
def setUp(self) -> None:
17621868
super().setUp()

Makefile.pre.in

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1985,7 +1985,7 @@ Objects/mimalloc/page.o: $(srcdir)/Objects/mimalloc/page-queue.c
19851985
.PHONY: regen-cases
19861986
regen-cases: \
19871987
regen-opcode-ids regen-opcode-targets regen-uop-ids regen-opcode-metadata-py \
1988-
regen-generated-cases regen-executor-cases regen-optimizer-cases \
1988+
regen-generated-cases regen-generated-labels regen-executor-cases regen-optimizer-cases \
19891989
regen-opcode-metadata regen-uop-metadata
19901990

19911991
.PHONY: regen-opcode-ids
@@ -2018,6 +2018,13 @@ regen-generated-cases:
20182018
-o $(srcdir)/Python/generated_cases.c.h.new $(srcdir)/Python/bytecodes.c
20192019
$(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new
20202020

2021+
.PHONY: regen-generated-labels
2022+
regen-generated-labels:
2023+
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/labels_generator.py \
2024+
-o $(srcdir)/Python/generated_labels.c.h.new $(srcdir)/Python/bytecodes.c
2025+
$(UPDATE_FILE) $(srcdir)/Python/generated_labels.c.h $(srcdir)/Python/generated_labels.c.h.new
2026+
2027+
20212028
.PHONY: regen-executor-cases
20222029
regen-executor-cases:
20232030
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/cases_generator/tier2_generator.py \

PCbuild/regen.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@
100100
WorkingDirectory="$(PySourcePath)" />
101101
<Exec Command="$(PythonForBuild) Tools\cases_generator\tier1_generator.py Python\bytecodes.c"
102102
WorkingDirectory="$(PySourcePath)" />
103+
<Exec Command="$(PythonForBuild) Tools\cases_generator\labels_generator.py Python\bytecodes.c"
104+
WorkingDirectory="$(PySourcePath)" />
103105
<Exec Command="$(PythonForBuild) Tools\cases_generator\tier2_generator.py Python\bytecodes.c"
104106
WorkingDirectory="$(PySourcePath)" />
105107
<Exec Command="$(PythonForBuild) Tools\cases_generator\optimizer_generator.py Python\optimizer_bytecodes.c Python\bytecodes.c"

Python/bytecodes.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#define super(name) static int SUPER_##name
5454
#define family(name, ...) static int family_##name
5555
#define pseudo(name) static int pseudo_##name
56+
#define label(name) name:
5657

5758
/* Annotations */
5859
#define guard
@@ -5166,6 +5167,125 @@ dummy_func(
51665167
assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
51675168
}
51685169

5170+
label(pop_4_error) {
5171+
STACK_SHRINK(1);
5172+
goto pop_3_error;
5173+
}
5174+
5175+
label(pop_3_error) {
5176+
STACK_SHRINK(1);
5177+
goto pop_2_error;
5178+
}
5179+
5180+
label(pop_2_error) {
5181+
STACK_SHRINK(1);
5182+
goto pop_1_error;
5183+
}
5184+
5185+
label(pop_1_error) {
5186+
STACK_SHRINK(1);
5187+
goto error;
5188+
}
5189+
5190+
label(error) {
5191+
/* Double-check exception status. */
5192+
#ifdef NDEBUG
5193+
if (!_PyErr_Occurred(tstate)) {
5194+
_PyErr_SetString(tstate, PyExc_SystemError,
5195+
"error return without exception set");
5196+
}
5197+
#else
5198+
assert(_PyErr_Occurred(tstate));
5199+
#endif
5200+
5201+
/* Log traceback info. */
5202+
assert(frame != &entry_frame);
5203+
if (!_PyFrame_IsIncomplete(frame)) {
5204+
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
5205+
if (f != NULL) {
5206+
PyTraceBack_Here(f);
5207+
}
5208+
}
5209+
_PyEval_MonitorRaise(tstate, frame, next_instr-1);
5210+
goto exception_unwind;
5211+
}
5212+
5213+
label(exception_unwind) {
5214+
/* We can't use frame->instr_ptr here, as RERAISE may have set it */
5215+
int offset = INSTR_OFFSET()-1;
5216+
int level, handler, lasti;
5217+
if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) {
5218+
// No handlers, so exit.
5219+
assert(_PyErr_Occurred(tstate));
5220+
5221+
/* Pop remaining stack entries. */
5222+
_PyStackRef *stackbase = _PyFrame_Stackbase(frame);
5223+
while (stack_pointer > stackbase) {
5224+
PyStackRef_XCLOSE(POP());
5225+
}
5226+
assert(STACK_LEVEL() == 0);
5227+
_PyFrame_SetStackPointer(frame, stack_pointer);
5228+
monitor_unwind(tstate, frame, next_instr-1);
5229+
goto exit_unwind;
5230+
}
5231+
5232+
assert(STACK_LEVEL() >= level);
5233+
_PyStackRef *new_top = _PyFrame_Stackbase(frame) + level;
5234+
while (stack_pointer > new_top) {
5235+
PyStackRef_XCLOSE(POP());
5236+
}
5237+
if (lasti) {
5238+
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
5239+
PyObject *lasti = PyLong_FromLong(frame_lasti);
5240+
if (lasti == NULL) {
5241+
goto exception_unwind;
5242+
}
5243+
PUSH(PyStackRef_FromPyObjectSteal(lasti));
5244+
}
5245+
5246+
/* Make the raw exception data
5247+
available to the handler,
5248+
so a program can emulate the
5249+
Python main loop. */
5250+
PyObject *exc = _PyErr_GetRaisedException(tstate);
5251+
PUSH(PyStackRef_FromPyObjectSteal(exc));
5252+
next_instr = _PyFrame_GetBytecode(frame) + handler;
5253+
5254+
if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
5255+
goto exception_unwind;
5256+
}
5257+
/* Resume normal execution */
5258+
#ifdef LLTRACE
5259+
if (lltrace >= 5) {
5260+
lltrace_resume_frame(frame);
5261+
}
5262+
#endif
5263+
DISPATCH();
5264+
}
5265+
5266+
label(exit_unwind) {
5267+
assert(_PyErr_Occurred(tstate));
5268+
_Py_LeaveRecursiveCallPy(tstate);
5269+
assert(frame != &entry_frame);
5270+
// GH-99729: We need to unlink the frame *before* clearing it:
5271+
_PyInterpreterFrame *dying = frame;
5272+
frame = tstate->current_frame = dying->previous;
5273+
_PyEval_FrameClearAndPop(tstate, dying);
5274+
frame->return_offset = 0;
5275+
if (frame == &entry_frame) {
5276+
/* Restore previous frame and exit */
5277+
tstate->current_frame = frame->previous;
5278+
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
5279+
return NULL;
5280+
}
5281+
goto resume_with_error;
5282+
}
5283+
5284+
label(resume_with_error) {
5285+
next_instr = frame->instr_ptr;
5286+
stack_pointer = _PyFrame_GetStackPointer(frame);
5287+
goto error;
5288+
}
51695289
// END BYTECODES //
51705290

51715291
}

0 commit comments

Comments
 (0)