Skip to content

gh-128563: Move labels in ceval.c to bytecodes.c #129112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions Lib/test/test_generated_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,23 @@ def run_cases_test(self, input: str, expected: str):
lines.pop(0)
while lines and lines[-1].startswith(("#", "\n")):
lines.pop(-1)
while lines and tier1_generator.INSTRUCTION_START_MARKER not in lines[0]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace this line by line processing, including the start and end comment stripping, by splitting the whole file on INSTRUCTION_START_MARKER and INSTRUCTION_START_MARKER, discarding the first and last parts.

text = temp_output.read()
_, rest = text.split(INSTRUCTION_START_MARKER)
actual, _ = rest.split(LABEL_START_MARKER)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good observation. Thanks!

lines.pop(0)
lines.pop(0)
for instruction_end_marker_index, line in enumerate(lines):
if tier1_generator.INSTRUCTION_END_MARKER in line:
break
else:
assert False, "No instruction end marker found."
for label_start_marker_index, line in enumerate(lines):
if tier1_generator.LABEL_START_MARKER in line:
break
else:
assert False, "No label start marker found."
del lines[instruction_end_marker_index:label_start_marker_index+1]
# Pop the label markers themselves
lines.pop(0)
lines.pop(-1)
actual = "".join(lines)
# if actual.strip() != expected.strip():
# print("Actual:")
Expand Down Expand Up @@ -1639,6 +1656,61 @@ def test_kill_in_wrong_order(self):
with self.assertRaises(SyntaxError):
self.run_cases_test(input, "")

def test_complex_label(self):
input = """
label(my_label) {
// Comment
do_thing()
if (complex) {
goto other_label;
}
goto other_label2;
}
"""

output = """
my_label:
{
// Comment
do_thing()
if (complex) {
goto other_label;
}
goto other_label2;
}
"""
self.run_cases_test(input, output)

def test_multiple_labels(self):
input = """
label(my_label_1) {
// Comment
do_thing1();
goto my_label_2;
}

label(my_label_2) {
// Comment
do_thing2();
goto my_label_3;
}
"""

output = """
my_label_1:
{
// Comment
do_thing1();
goto my_label_2;
}

my_label_2:
{
// Comment
do_thing2();
goto my_label_3;
}
"""

class TestGeneratedAbstractCases(unittest.TestCase):
def setUp(self) -> None:
Expand Down
121 changes: 120 additions & 1 deletion Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#define super(name) static int SUPER_##name
#define family(name, ...) static int family_##name
#define pseudo(name) static int pseudo_##name
#define label(name) name:

/* Annotations */
#define guard
Expand Down Expand Up @@ -103,7 +104,6 @@ dummy_func(
PyObject *codeobj;
PyObject *cond;
PyObject *descr;
_PyInterpreterFrame entry_frame;
PyObject *exc;
PyObject *exit;
PyObject *fget;
Expand Down Expand Up @@ -5192,6 +5192,125 @@ dummy_func(
assert(tstate->tracing || eval_breaker == FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(_PyFrame_GetCode(frame)->_co_instrumentation_version));
}

label(pop_4_error) {
STACK_SHRINK(1);
goto pop_3_error;
}

label(pop_3_error) {
STACK_SHRINK(1);
goto pop_2_error;
}

label(pop_2_error) {
STACK_SHRINK(1);
goto pop_1_error;
}

label(pop_1_error) {
STACK_SHRINK(1);
goto error;
}

label(error) {
/* Double-check exception status. */
#ifdef NDEBUG
if (!_PyErr_Occurred(tstate)) {
_PyErr_SetString(tstate, PyExc_SystemError,
"error return without exception set");
}
#else
assert(_PyErr_Occurred(tstate));
#endif

/* Log traceback info. */
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
if (!_PyFrame_IsIncomplete(frame)) {
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
if (f != NULL) {
PyTraceBack_Here(f);
}
}
_PyEval_MonitorRaise(tstate, frame, next_instr-1);
goto exception_unwind;
}

label(exception_unwind) {
/* We can't use frame->instr_ptr here, as RERAISE may have set it */
int offset = INSTR_OFFSET()-1;
int level, handler, lasti;
if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) {
// No handlers, so exit.
assert(_PyErr_Occurred(tstate));

/* Pop remaining stack entries. */
_PyStackRef *stackbase = _PyFrame_Stackbase(frame);
while (stack_pointer > stackbase) {
PyStackRef_XCLOSE(POP());
}
assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer);
monitor_unwind(tstate, frame, next_instr-1);
goto exit_unwind;
}

assert(STACK_LEVEL() >= level);
_PyStackRef *new_top = _PyFrame_Stackbase(frame) + level;
while (stack_pointer > new_top) {
PyStackRef_XCLOSE(POP());
}
if (lasti) {
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
PyObject *lasti = PyLong_FromLong(frame_lasti);
if (lasti == NULL) {
goto exception_unwind;
}
PUSH(PyStackRef_FromPyObjectSteal(lasti));
}

/* Make the raw exception data
available to the handler,
so a program can emulate the
Python main loop. */
PyObject *exc = _PyErr_GetRaisedException(tstate);
PUSH(PyStackRef_FromPyObjectSteal(exc));
next_instr = _PyFrame_GetBytecode(frame) + handler;

if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
goto exception_unwind;
}
/* Resume normal execution */
#ifdef LLTRACE
if (frame->lltrace >= 5) {
lltrace_resume_frame(frame);
}
#endif
DISPATCH();
}

label(exit_unwind) {
assert(_PyErr_Occurred(tstate));
_Py_LeaveRecursiveCallPy(tstate);
assert(frame->owner != FRAME_OWNED_BY_INTERPRETER);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying);
frame->return_offset = 0;
if (frame == &entry_frame) {
/* Restore previous frame and exit */
tstate->current_frame = frame->previous;
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
return NULL;
}
goto resume_with_error;
}

label(resume_with_error) {
next_instr = frame->instr_ptr;
stack_pointer = _PyFrame_GetStackPointer(frame);
goto error;
}
// END BYTECODES //

}
Expand Down
134 changes: 0 additions & 134 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,143 +898,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int

DISPATCH();

{
/* Start instructions */
#if !USE_COMPUTED_GOTOS
dispatch_opcode:
switch (opcode)
#endif
{

#include "generated_cases.c.h"


#if USE_COMPUTED_GOTOS
_unknown_opcode:
#else
EXTRA_CASES // From pycore_opcode_metadata.h, a 'case' for each unused opcode
#endif
/* Tell C compilers not to hold the opcode variable in the loop.
next_instr points the current instruction without TARGET(). */
opcode = next_instr->op.code;
_PyErr_Format(tstate, PyExc_SystemError,
"%U:%d: unknown opcode %d",
_PyFrame_GetCode(frame)->co_filename,
PyUnstable_InterpreterFrame_GetLine(frame),
opcode);
goto error;

} /* End instructions */

/* This should never be reached. Every opcode should end with DISPATCH()
or goto error. */
Py_UNREACHABLE();

pop_4_error:
STACK_SHRINK(1);
pop_3_error:
STACK_SHRINK(1);
pop_2_error:
STACK_SHRINK(1);
pop_1_error:
STACK_SHRINK(1);
error:
/* Double-check exception status. */
#ifdef NDEBUG
if (!_PyErr_Occurred(tstate)) {
_PyErr_SetString(tstate, PyExc_SystemError,
"error return without exception set");
}
#else
assert(_PyErr_Occurred(tstate));
#endif

/* Log traceback info. */
assert(frame != &entry_frame);
if (!_PyFrame_IsIncomplete(frame)) {
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
if (f != NULL) {
PyTraceBack_Here(f);
}
}
_PyEval_MonitorRaise(tstate, frame, next_instr-1);
exception_unwind:
{
/* We can't use frame->instr_ptr here, as RERAISE may have set it */
int offset = INSTR_OFFSET()-1;
int level, handler, lasti;
if (get_exception_handler(_PyFrame_GetCode(frame), offset, &level, &handler, &lasti) == 0) {
// No handlers, so exit.
assert(_PyErr_Occurred(tstate));

/* Pop remaining stack entries. */
_PyStackRef *stackbase = _PyFrame_Stackbase(frame);
while (stack_pointer > stackbase) {
PyStackRef_XCLOSE(POP());
}
assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer);
monitor_unwind(tstate, frame, next_instr-1);
goto exit_unwind;
}

assert(STACK_LEVEL() >= level);
_PyStackRef *new_top = _PyFrame_Stackbase(frame) + level;
while (stack_pointer > new_top) {
PyStackRef_XCLOSE(POP());
}
if (lasti) {
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
PyObject *lasti = PyLong_FromLong(frame_lasti);
if (lasti == NULL) {
goto exception_unwind;
}
PUSH(PyStackRef_FromPyObjectSteal(lasti));
}

/* Make the raw exception data
available to the handler,
so a program can emulate the
Python main loop. */
PyObject *exc = _PyErr_GetRaisedException(tstate);
PUSH(PyStackRef_FromPyObjectSteal(exc));
next_instr = _PyFrame_GetBytecode(frame) + handler;

if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
goto exception_unwind;
}
/* Resume normal execution */
#ifdef LLTRACE
if (frame->lltrace >= 5) {
lltrace_resume_frame(frame);
}
#endif
DISPATCH();
}
}

exit_unwind:
assert(_PyErr_Occurred(tstate));
_Py_LeaveRecursiveCallPy(tstate);
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
frame = tstate->current_frame = dying->previous;
_PyEval_FrameClearAndPop(tstate, dying);
frame->return_offset = 0;
if (frame == &entry_frame) {
/* Restore previous frame and exit */
tstate->current_frame = frame->previous;
tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
return NULL;
}

resume_with_error:
next_instr = frame->instr_ptr;
stack_pointer = _PyFrame_GetStackPointer(frame);
goto error;


#ifdef _Py_TIER2

// Tier 2 is also here!
Expand Down
Loading
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy