Skip to content

Commit 87fb8b1

Browse files
gh-128563: Move labels in ceval.c to bytecodes.c (GH-129112)
1 parent 7d27561 commit 87fb8b1

File tree

9 files changed

+435
-145
lines changed

9 files changed

+435
-145
lines changed

Lib/test/test_generated_cases.py

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -281,12 +281,12 @@ def run_cases_test(self, input: str, expected: str):
281281
)
282282

283283
with open(self.temp_output_filename) as temp_output:
284-
lines = temp_output.readlines()
285-
while lines and lines[0].startswith(("// ", "#", " #", "\n")):
286-
lines.pop(0)
287-
while lines and lines[-1].startswith(("#", "\n")):
288-
lines.pop(-1)
289-
actual = "".join(lines)
284+
lines = temp_output.read()
285+
_, rest = lines.split(tier1_generator.INSTRUCTION_START_MARKER)
286+
instructions, labels_with_prelude_and_postlude = rest.split(tier1_generator.INSTRUCTION_END_MARKER)
287+
_, labels_with_postlude = labels_with_prelude_and_postlude.split(tier1_generator.LABEL_START_MARKER)
288+
labels, _ = labels_with_postlude.split(tier1_generator.LABEL_END_MARKER)
289+
actual = instructions + labels
290290
# if actual.strip() != expected.strip():
291291
# print("Actual:")
292292
# print(actual)
@@ -1756,6 +1756,61 @@ def test_kill_in_wrong_order(self):
17561756
with self.assertRaises(SyntaxError):
17571757
self.run_cases_test(input, "")
17581758

1759+
def test_complex_label(self):
1760+
input = """
1761+
label(my_label) {
1762+
// Comment
1763+
do_thing()
1764+
if (complex) {
1765+
goto other_label;
1766+
}
1767+
goto other_label2;
1768+
}
1769+
"""
1770+
1771+
output = """
1772+
my_label:
1773+
{
1774+
// Comment
1775+
do_thing()
1776+
if (complex) {
1777+
goto other_label;
1778+
}
1779+
goto other_label2;
1780+
}
1781+
"""
1782+
self.run_cases_test(input, output)
1783+
1784+
def test_multiple_labels(self):
1785+
input = """
1786+
label(my_label_1) {
1787+
// Comment
1788+
do_thing1();
1789+
goto my_label_2;
1790+
}
1791+
1792+
label(my_label_2) {
1793+
// Comment
1794+
do_thing2();
1795+
goto my_label_3;
1796+
}
1797+
"""
1798+
1799+
output = """
1800+
my_label_1:
1801+
{
1802+
// Comment
1803+
do_thing1();
1804+
goto my_label_2;
1805+
}
1806+
1807+
my_label_2:
1808+
{
1809+
// Comment
1810+
do_thing2();
1811+
goto my_label_3;
1812+
}
1813+
"""
17591814

17601815
class TestGeneratedAbstractCases(unittest.TestCase):
17611816
def setUp(self) -> None:

Python/bytecodes.c

Lines changed: 120 additions & 1 deletion
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
@@ -103,7 +104,6 @@ dummy_func(
103104
PyObject *codeobj;
104105
PyObject *cond;
105106
PyObject *descr;
106-
_PyInterpreterFrame entry_frame;
107107
PyObject *exc;
108108
PyObject *exit;
109109
PyObject *fget;
@@ -5167,6 +5167,125 @@ dummy_func(
51675167
assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
51685168
}
51695169

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->owner != FRAME_OWNED_BY_INTERPRETER);
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 (frame->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->owner != FRAME_OWNED_BY_INTERPRETER);
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->owner == FRAME_OWNED_BY_INTERPRETER) {
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+
}
51705289
// END BYTECODES //
51715290

51725291
}

Python/ceval.c

Lines changed: 0 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -882,143 +882,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
882882

883883
DISPATCH();
884884

885-
{
886-
/* Start instructions */
887-
#if !USE_COMPUTED_GOTOS
888-
dispatch_opcode:
889-
switch (opcode)
890-
#endif
891-
{
892-
893885
#include "generated_cases.c.h"
894886

895887

896-
#if USE_COMPUTED_GOTOS
897-
_unknown_opcode:
898-
#else
899-
EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode
900-
#endif
901-
/* Tell C compilers not to hold the opcode variable in the loop.
902-
next_instr points the current instruction without TARGET(). */
903-
opcode = next_instr->op.code;
904-
_PyErr_Format(tstate, PyExc_SystemError,
905-
"%U:%d: unknown opcode %d",
906-
_PyFrame_GetCode(frame)->co_filename,
907-
PyUnstable_InterpreterFrame_GetLine(frame),
908-
opcode);
909-
goto error;
910-
911-
} /* End instructions */
912-
913-
/* This should never be reached. Every opcode should end with DISPATCH()
914-
or goto error. */
915-
Py_UNREACHABLE();
916-
917-
pop_4_error:
918-
STACK_SHRINK(1);
919-
pop_3_error:
920-
STACK_SHRINK(1);
921-
pop_2_error:
922-
STACK_SHRINK(1);
923-
pop_1_error:
924-
STACK_SHRINK(1);
925-
error:
926-
/* Double-check exception status. */
927-
#ifdef NDEBUG
928-
if (!_PyErr_Occurred(tstate)) {
929-
_PyErr_SetString(tstate, PyExc_SystemError,
930-
"error return without exception set");
931-
}
932-
#else
933-
assert(_PyErr_Occurred(tstate));
934-
#endif
935-
936-
/* Log traceback info. */
937-
assert(frame != &entry_frame);
938-
if (!_PyFrame_IsIncomplete(frame)) {
939-
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
940-
if (f != NULL) {
941-
PyTraceBack_Here(f);
942-
}
943-
}
944-
_PyEval_MonitorRaise(tstate, frame, next_instr-1);
945-
exception_unwind:
946-
{
947-
/* We can't use frame->instr_ptr here, as RERAISE may have set it */
948-
int offset = INSTR_OFFSET()-1;
949-
int level, handler, lasti;
950-
if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) {
951-
// No handlers, so exit.
952-
assert(_PyErr_Occurred(tstate));
953-
954-
/* Pop remaining stack entries. */
955-
_PyStackRef *stackbase = _PyFrame_Stackbase(frame);
956-
while (stack_pointer > stackbase) {
957-
PyStackRef_XCLOSE(POP());
958-
}
959-
assert(STACK_LEVEL() == 0);
960-
_PyFrame_SetStackPointer(frame, stack_pointer);
961-
monitor_unwind(tstate, frame, next_instr-1);
962-
goto exit_unwind;
963-
}
964-
965-
assert(STACK_LEVEL() >= level);
966-
_PyStackRef *new_top = _PyFrame_Stackbase(frame) + level;
967-
while (stack_pointer > new_top) {
968-
PyStackRef_XCLOSE(POP());
969-
}
970-
if (lasti) {
971-
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
972-
PyObject *lasti = PyLong_FromLong(frame_lasti);
973-
if (lasti == NULL) {
974-
goto exception_unwind;
975-
}
976-
PUSH(PyStackRef_FromPyObjectSteal(lasti));
977-
}
978-
979-
/* Make the raw exception data
980-
available to the handler,
981-
so a program can emulate the
982-
Python main loop. */
983-
PyObject *exc = _PyErr_GetRaisedException(tstate);
984-
PUSH(PyStackRef_FromPyObjectSteal(exc));
985-
next_instr = _PyFrame_GetBytecode(frame) + handler;
986-
987-
if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
988-
goto exception_unwind;
989-
}
990-
/* Resume normal execution */
991-
#ifdef LLTRACE
992-
if (frame->lltrace >= 5) {
993-
lltrace_resume_frame(frame);
994-
}
995-
#endif
996-
DISPATCH();
997-
}
998-
}
999-
1000-
exit_unwind:
1001-
assert(_PyErr_Occurred(tstate));
1002-
_Py_LeaveRecursiveCallPy(tstate);
1003-
assert(frame != &entry_frame);
1004-
// GH-99729: We need to unlink the frame *before* clearing it:
1005-
_PyInterpreterFrame *dying = frame;
1006-
frame = tstate->current_frame = dying->previous;
1007-
_PyEval_FrameClearAndPop(tstate, dying);
1008-
frame->return_offset = 0;
1009-
if (frame == &entry_frame) {
1010-
/* Restore previous frame and exit */
1011-
tstate->current_frame = frame->previous;
1012-
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
1013-
return NULL;
1014-
}
1015-
1016-
resume_with_error:
1017-
next_instr = frame->instr_ptr;
1018-
stack_pointer = _PyFrame_GetStackPointer(frame);
1019-
goto error;
1020-
1021-
1022888
#ifdef _Py_TIER2
1023889

1024890
// Tier 2 is also here!

0 commit comments

Comments
 (0)