Skip to content

Commit 15da9c7

Browse files
Squashed commit of the following:
commit f89f147 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Sat Jan 25 11:18:43 2025 +0800 Address review commit e4a9de7 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu Jan 23 02:05:13 2025 +0800 Regen files commit 5d56130 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Thu Jan 23 02:00:44 2025 +0800 Address review by removing in test cases generator commit e1f9475 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed Jan 22 09:39:54 2025 +0800 Remove entry_frame commit 15ca6dd Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed Jan 22 09:27:37 2025 +0800 fix upstream changes commit fdd4540 Merge: 1ec8033 86c1a60 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Wed Jan 22 09:27:31 2025 +0800 Merge remote-tracking branch 'upstream/main' into labels-in-dsl commit 1ec8033 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 20:16:42 2025 +0800 Lint commit c6df7a1 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 20:14:10 2025 +0800 cleanup diff commit 63a88ab Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 20:13:12 2025 +0800 remove outdated file commit b911bb1 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 20:11:27 2025 +0800 Move labels into tier 1 generator commit af4bf1a Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 15:52:53 2025 +0800 Add to generated files commit 3ae88a5 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 09:01:39 2025 +0800 lint commit 5cccb98 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 08:58:53 2025 +0800 Fix mypy commit 2082537 Author: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue Jan 21 08:54:50 2025 +0800 Move labels in ceval.c to bytecodes.c
1 parent 1a21607 commit 15da9c7

File tree

9 files changed

+435
-155
lines changed

9 files changed

+435
-155
lines changed

Lib/test/test_generated_cases.py

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

252252
with open(self.temp_output_filename) as temp_output:
253-
lines = temp_output.readlines()
254-
while lines and lines[0].startswith(("// ", "#", " #", "\n")):
255-
lines.pop(0)
256-
while lines and lines[-1].startswith(("#", "\n")):
257-
lines.pop(-1)
258-
actual = "".join(lines)
253+
lines = temp_output.read()
254+
_, rest = lines.split(tier1_generator.INSTRUCTION_START_MARKER)
255+
instructions, labels_with_prelude_and_postlude = rest.split(tier1_generator.INSTRUCTION_END_MARKER)
256+
_, labels_with_postlude = labels_with_prelude_and_postlude.split(tier1_generator.LABEL_START_MARKER)
257+
labels, _ = labels_with_postlude.split(tier1_generator.LABEL_END_MARKER)
258+
actual = instructions + labels
259259
# if actual.strip() != expected.strip():
260260
# print("Actual:")
261261
# print(actual)
@@ -1641,6 +1641,61 @@ def test_kill_in_wrong_order(self):
16411641
with self.assertRaises(SyntaxError):
16421642
self.run_cases_test(input, "")
16431643

1644+
def test_complex_label(self):
1645+
input = """
1646+
label(my_label) {
1647+
// Comment
1648+
do_thing()
1649+
if (complex) {
1650+
goto other_label;
1651+
}
1652+
goto other_label2;
1653+
}
1654+
"""
1655+
1656+
output = """
1657+
my_label:
1658+
{
1659+
// Comment
1660+
do_thing()
1661+
if (complex) {
1662+
goto other_label;
1663+
}
1664+
goto other_label2;
1665+
}
1666+
"""
1667+
self.run_cases_test(input, output)
1668+
1669+
def test_multiple_labels(self):
1670+
input = """
1671+
label(my_label_1) {
1672+
// Comment
1673+
do_thing1();
1674+
goto my_label_2;
1675+
}
1676+
1677+
label(my_label_2) {
1678+
// Comment
1679+
do_thing2();
1680+
goto my_label_3;
1681+
}
1682+
"""
1683+
1684+
output = """
1685+
my_label_1:
1686+
{
1687+
// Comment
1688+
do_thing1();
1689+
goto my_label_2;
1690+
}
1691+
1692+
my_label_2:
1693+
{
1694+
// Comment
1695+
do_thing2();
1696+
goto my_label_3;
1697+
}
1698+
"""
16441699

16451700
class TestGeneratedTailCallErorHandlers(unittest.TestCase):
16461701
def setUp(self) -> None:

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
@@ -5193,6 +5194,125 @@ dummy_func(
51935194
assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
51945195
}
51955196

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

51985318
}

Python/ceval.c

Lines changed: 0 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -919,154 +919,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
919919
DISPATCH();
920920
#endif
921921

922-
#ifndef Py_TAIL_CALL_INTERP
923-
/* Start instructions */
924-
#if !USE_COMPUTED_GOTOS
925-
dispatch_opcode:
926-
switch (opcode)
927-
#endif
928-
{
929922
#include "generated_cases.c.h"
930923

931924

932-
#if USE_COMPUTED_GOTOS
933-
_unknown_opcode:
934-
#else
935-
EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode
936-
#endif
937-
/* Tell C compilers not to hold the opcode variable in the loop.
938-
next_instr points the current instruction without TARGET(). */
939-
opcode = next_instr->op.code;
940-
_PyErr_Format(tstate, PyExc_SystemError,
941-
"%U:%d: unknown opcode %d",
942-
_PyFrame_GetCode(frame)->co_filename,
943-
PyUnstable_InterpreterFrame_GetLine(frame),
944-
opcode);
945-
goto error;
946-
947-
} /* End instructions */
948-
949-
/* This should never be reached. Every opcode should end with DISPATCH()
950-
or goto error. */
951-
Py_UNREACHABLE();
952-
#endif
953-
TAIL_CALL_TARGET(pop_4_error):
954-
STACK_SHRINK(1);
955-
TAIL_CALL_TARGET(pop_3_error):
956-
STACK_SHRINK(1);
957-
TAIL_CALL_TARGET(pop_2_error):
958-
STACK_SHRINK(1);
959-
TAIL_CALL_TARGET(pop_1_error):
960-
STACK_SHRINK(1);
961-
TAIL_CALL_TARGET(error):
962-
/* Double-check exception status. */
963-
#ifdef NDEBUG
964-
if (!_PyErr_Occurred(tstate)) {
965-
_PyErr_SetString(tstate, PyExc_SystemError,
966-
"error return without exception set");
967-
}
968-
#else
969-
assert(_PyErr_Occurred(tstate));
970-
#endif
971-
972-
/* Log traceback info. */
973-
assert(!frame->is_entry_frame);
974-
if (!_PyFrame_IsIncomplete(frame)) {
975-
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
976-
if (f != NULL) {
977-
PyTraceBack_Here(f);
978-
}
979-
}
980-
_PyEval_MonitorRaise(tstate, frame, next_instr-1);
981-
TAIL_CALL_TARGET(exception_unwind):
982-
{
983-
/* We can't use frame->instr_ptr here, as RERAISE may have set it */
984-
int offset = INSTR_OFFSET()-1;
985-
int level, handler, lasti;
986-
if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) {
987-
// No handlers, so exit.
988-
assert(_PyErr_Occurred(tstate));
989-
990-
/* Pop remaining stack entries. */
991-
_PyStackRef *stackbase = _PyFrame_Stackbase(frame);
992-
while (stack_pointer > stackbase) {
993-
PyStackRef_XCLOSE(POP());
994-
}
995-
assert(STACK_LEVEL() == 0);
996-
_PyFrame_SetStackPointer(frame, stack_pointer);
997-
monitor_unwind(tstate, frame, next_instr-1);
998-
goto exit_unwind;
999-
}
1000-
1001-
assert(STACK_LEVEL() >= level);
1002-
_PyStackRef *new_top = _PyFrame_Stackbase(frame) + level;
1003-
while (stack_pointer > new_top) {
1004-
PyStackRef_XCLOSE(POP());
1005-
}
1006-
if (lasti) {
1007-
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
1008-
PyObject *lasti = PyLong_FromLong(frame_lasti);
1009-
if (lasti == NULL) {
1010-
goto exception_unwind;
1011-
}
1012-
PUSH(PyStackRef_FromPyObjectSteal(lasti));
1013-
}
1014-
1015-
/* Make the raw exception data
1016-
available to the handler,
1017-
so a program can emulate the
1018-
Python main loop. */
1019-
PyObject *exc = _PyErr_GetRaisedException(tstate);
1020-
PUSH(PyStackRef_FromPyObjectSteal(exc));
1021-
next_instr = _PyFrame_GetBytecode(frame) + handler;
1022-
1023-
if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
1024-
goto exception_unwind;
1025-
}
1026-
/* Resume normal execution */
1027-
#ifdef LLTRACE
1028-
if (frame->lltrace >= 5) {
1029-
lltrace_resume_frame(frame);
1030-
}
1031-
#endif
1032-
1033-
#ifdef Py_TAIL_CALL_INTERP
1034-
# ifdef IN_TAIL_CALL_INTERP
1035-
DISPATCH();
1036-
# else
1037-
# ifdef LLTRACE
1038-
return _TAIL_CALL_shim(frame, stack_pointer, tstate, next_instr, 0, 0, lltrace);
1039-
# else
1040-
return _TAIL_CALL_shim(frame, stack_pointer, tstate, next_instr, 0, 0);
1041-
# endif
1042-
# endif
1043-
#else
1044-
DISPATCH();
1045-
#endif
1046-
}
1047-
1048-
TAIL_CALL_TARGET(exit_unwind):
1049-
assert(_PyErr_Occurred(tstate));
1050-
_Py_LeaveRecursiveCallPy(tstate);
1051-
assert(!frame->is_entry_frame);
1052-
// GH-99729: We need to unlink the frame *before* clearing it:
1053-
_PyInterpreterFrame *dying = frame;
1054-
frame = tstate->current_frame = dying->previous;
1055-
_PyEval_FrameClearAndPop(tstate, dying);
1056-
frame->return_offset = 0;
1057-
if (frame->is_entry_frame) {
1058-
/* Restore previous frame and exit */
1059-
tstate->current_frame = frame->previous;
1060-
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
1061-
return NULL;
1062-
}
1063-
1064-
TAIL_CALL_TARGET(resume_with_error):
1065-
next_instr = frame->instr_ptr;
1066-
stack_pointer = _PyFrame_GetStackPointer(frame);
1067-
goto error;
1068-
1069-
/* END_BASE_INTERPRETER */
1070925
#ifdef _Py_TIER2
1071926

1072927
// Tier 2 is also here!

0 commit comments

Comments
 (0)