mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-128563: Move labels in ceval.c to bytecodes.c (GH-129112)
This commit is contained in:
parent
7d275611f6
commit
87fb8b198c
9 changed files with 435 additions and 145 deletions
|
@ -281,12 +281,12 @@ class TestGeneratedCases(unittest.TestCase):
|
|||
)
|
||||
|
||||
with open(self.temp_output_filename) as temp_output:
|
||||
lines = temp_output.readlines()
|
||||
while lines and lines[0].startswith(("// ", "#", " #", "\n")):
|
||||
lines.pop(0)
|
||||
while lines and lines[-1].startswith(("#", "\n")):
|
||||
lines.pop(-1)
|
||||
actual = "".join(lines)
|
||||
lines = temp_output.read()
|
||||
_, rest = lines.split(tier1_generator.INSTRUCTION_START_MARKER)
|
||||
instructions, labels_with_prelude_and_postlude = rest.split(tier1_generator.INSTRUCTION_END_MARKER)
|
||||
_, labels_with_postlude = labels_with_prelude_and_postlude.split(tier1_generator.LABEL_START_MARKER)
|
||||
labels, _ = labels_with_postlude.split(tier1_generator.LABEL_END_MARKER)
|
||||
actual = instructions + labels
|
||||
# if actual.strip() != expected.strip():
|
||||
# print("Actual:")
|
||||
# print(actual)
|
||||
|
@ -1756,6 +1756,61 @@ class TestGeneratedCases(unittest.TestCase):
|
|||
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:
|
||||
|
|
|
@ -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
|
||||
|
@ -103,7 +104,6 @@ dummy_func(
|
|||
PyObject *codeobj;
|
||||
PyObject *cond;
|
||||
PyObject *descr;
|
||||
_PyInterpreterFrame entry_frame;
|
||||
PyObject *exc;
|
||||
PyObject *exit;
|
||||
PyObject *fget;
|
||||
|
@ -5167,6 +5167,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->owner == FRAME_OWNED_BY_INTERPRETER) {
|
||||
/* 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 //
|
||||
|
||||
}
|
||||
|
|
134
Python/ceval.c
134
Python/ceval.c
|
@ -882,143 +882,9 @@ resume_frame:
|
|||
|
||||
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!
|
||||
|
|
156
Python/generated_cases.c.h
generated
156
Python/generated_cases.c.h
generated
|
@ -8,6 +8,13 @@
|
|||
#endif
|
||||
#define TIER_ONE 1
|
||||
|
||||
#if !USE_COMPUTED_GOTOS
|
||||
dispatch_opcode:
|
||||
switch (opcode)
|
||||
#endif
|
||||
{
|
||||
/* BEGIN INSTRUCTIONS */
|
||||
|
||||
|
||||
TARGET(BINARY_OP) {
|
||||
frame->instr_ptr = next_instr;
|
||||
|
@ -8421,4 +8428,153 @@
|
|||
assert(WITHIN_STACK_BOUNDS());
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
/* END INSTRUCTIONS */
|
||||
#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;
|
||||
|
||||
}
|
||||
|
||||
/* This should never be reached. Every opcode should end with DISPATCH()
|
||||
or goto error. */
|
||||
Py_UNREACHABLE();
|
||||
/* BEGIN LABELS */
|
||||
|
||||
pop_4_error:
|
||||
{
|
||||
STACK_SHRINK(1);
|
||||
goto pop_3_error;
|
||||
}
|
||||
|
||||
pop_3_error:
|
||||
{
|
||||
STACK_SHRINK(1);
|
||||
goto pop_2_error;
|
||||
}
|
||||
|
||||
pop_2_error:
|
||||
{
|
||||
STACK_SHRINK(1);
|
||||
goto pop_1_error;
|
||||
}
|
||||
|
||||
pop_1_error:
|
||||
{
|
||||
STACK_SHRINK(1);
|
||||
goto error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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->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->owner == FRAME_OWNED_BY_INTERPRETER) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
resume_with_error:
|
||||
{
|
||||
next_instr = frame->instr_ptr;
|
||||
stack_pointer = _PyFrame_GetStackPointer(frame);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* END LABELS */
|
||||
#undef TIER_ONE
|
||||
|
|
|
@ -258,6 +258,12 @@ class Instruction:
|
|||
return False
|
||||
|
||||
|
||||
@dataclass
|
||||
class Label:
|
||||
name: str
|
||||
body: list[lexer.Token]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PseudoInstruction:
|
||||
name: str
|
||||
|
@ -291,6 +297,7 @@ class Analysis:
|
|||
uops: dict[str, Uop]
|
||||
families: dict[str, Family]
|
||||
pseudos: dict[str, PseudoInstruction]
|
||||
labels: dict[str, Label]
|
||||
opmap: dict[str, int]
|
||||
have_arg: int
|
||||
min_instrumented: int
|
||||
|
@ -1014,6 +1021,13 @@ def add_pseudo(
|
|||
)
|
||||
|
||||
|
||||
def add_label(
|
||||
label: parser.LabelDef,
|
||||
labels: dict[str, Label],
|
||||
) -> None:
|
||||
labels[label.name] = Label(label.name, label.block.tokens)
|
||||
|
||||
|
||||
def assign_opcodes(
|
||||
instructions: dict[str, Instruction],
|
||||
families: dict[str, Family],
|
||||
|
@ -1132,6 +1146,7 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis:
|
|||
uops: dict[str, Uop] = {}
|
||||
families: dict[str, Family] = {}
|
||||
pseudos: dict[str, PseudoInstruction] = {}
|
||||
labels: dict[str, Label] = {}
|
||||
for node in forest:
|
||||
match node:
|
||||
case parser.InstDef(name):
|
||||
|
@ -1146,6 +1161,8 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis:
|
|||
pass
|
||||
case parser.Pseudo():
|
||||
pass
|
||||
case parser.LabelDef():
|
||||
pass
|
||||
case _:
|
||||
assert False
|
||||
for node in forest:
|
||||
|
@ -1157,6 +1174,8 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis:
|
|||
add_family(node, instructions, families)
|
||||
case parser.Pseudo():
|
||||
add_pseudo(node, instructions, pseudos)
|
||||
case parser.LabelDef():
|
||||
add_label(node, labels)
|
||||
case _:
|
||||
pass
|
||||
for uop in uops.values():
|
||||
|
@ -1182,7 +1201,7 @@ def analyze_forest(forest: list[parser.AstNode]) -> Analysis:
|
|||
families["BINARY_OP"].members.append(inst)
|
||||
opmap, first_arg, min_instrumented = assign_opcodes(instructions, families, pseudos)
|
||||
return Analysis(
|
||||
instructions, uops, families, pseudos, opmap, first_arg, min_instrumented
|
||||
instructions, uops, families, pseudos, labels, opmap, first_arg, min_instrumented
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -213,6 +213,9 @@ kwds.append(OP)
|
|||
# A macro in the DSL
|
||||
MACRO = "MACRO"
|
||||
kwds.append(MACRO)
|
||||
# A label in the DSL
|
||||
LABEL = "LABEL"
|
||||
kwds.append(LABEL)
|
||||
keywords = {name.lower(): name for name in kwds}
|
||||
|
||||
ANNOTATION = "ANNOTATION"
|
||||
|
|
|
@ -3,6 +3,7 @@ from parsing import ( # noqa: F401
|
|||
Macro,
|
||||
Pseudo,
|
||||
Family,
|
||||
LabelDef,
|
||||
Parser,
|
||||
Context,
|
||||
CacheEffect,
|
||||
|
|
|
@ -150,8 +150,13 @@ class Pseudo(Node):
|
|||
targets: list[str] # opcodes this can be replaced by
|
||||
as_sequence: bool
|
||||
|
||||
@dataclass
|
||||
class LabelDef(Node):
|
||||
name: str
|
||||
block: Block
|
||||
|
||||
AstNode = InstDef | Macro | Pseudo | Family
|
||||
|
||||
AstNode = InstDef | Macro | Pseudo | Family | LabelDef
|
||||
|
||||
|
||||
class Parser(PLexer):
|
||||
|
@ -165,6 +170,18 @@ class Parser(PLexer):
|
|||
return pseudo
|
||||
if inst := self.inst_def():
|
||||
return inst
|
||||
if label := self.label_def():
|
||||
return label
|
||||
return None
|
||||
|
||||
@contextual
|
||||
def label_def(self) -> LabelDef | None:
|
||||
if self.expect(lx.LABEL):
|
||||
if self.expect(lx.LPAREN):
|
||||
if tkn := self.expect(lx.IDENTIFIER):
|
||||
if self.expect(lx.RPAREN):
|
||||
if block := self.block():
|
||||
return LabelDef(tkn.text, block)
|
||||
return None
|
||||
|
||||
@contextual
|
||||
|
|
|
@ -32,6 +32,10 @@ DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h"
|
|||
|
||||
|
||||
FOOTER = "#undef TIER_ONE\n"
|
||||
INSTRUCTION_START_MARKER = "/* BEGIN INSTRUCTIONS */"
|
||||
INSTRUCTION_END_MARKER = "/* END INSTRUCTIONS */"
|
||||
LABEL_START_MARKER = "/* BEGIN LABELS */"
|
||||
LABEL_END_MARKER = "/* END LABELS */"
|
||||
|
||||
|
||||
def declare_variable(var: StackItem, out: CWriter) -> None:
|
||||
|
@ -133,13 +137,64 @@ def generate_tier1(
|
|||
) -> None:
|
||||
write_header(__file__, filenames, outfile)
|
||||
outfile.write(
|
||||
"""
|
||||
f"""
|
||||
#ifdef TIER_TWO
|
||||
#error "This file is for Tier 1 only"
|
||||
#endif
|
||||
#define TIER_ONE 1
|
||||
|
||||
#if !USE_COMPUTED_GOTOS
|
||||
dispatch_opcode:
|
||||
switch (opcode)
|
||||
#endif
|
||||
{{
|
||||
{INSTRUCTION_START_MARKER}
|
||||
"""
|
||||
)
|
||||
generate_tier1_cases(analysis, outfile, lines)
|
||||
outfile.write(f"""
|
||||
{INSTRUCTION_END_MARKER}
|
||||
#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;
|
||||
|
||||
}}
|
||||
|
||||
/* This should never be reached. Every opcode should end with DISPATCH()
|
||||
or goto error. */
|
||||
Py_UNREACHABLE();
|
||||
{LABEL_START_MARKER}
|
||||
""")
|
||||
generate_tier1_labels(analysis, outfile, lines)
|
||||
outfile.write(f"{LABEL_END_MARKER}\n")
|
||||
outfile.write(FOOTER)
|
||||
|
||||
def generate_tier1_labels(
|
||||
analysis: Analysis, outfile: TextIO, lines: bool
|
||||
) -> None:
|
||||
out = CWriter(outfile, 2, lines)
|
||||
out.emit("\n")
|
||||
for name, label in analysis.labels.items():
|
||||
out.emit(f"{name}:\n")
|
||||
for tkn in label.body:
|
||||
out.emit(tkn)
|
||||
out.emit("\n")
|
||||
out.emit("\n")
|
||||
|
||||
def generate_tier1_cases(
|
||||
analysis: Analysis, outfile: TextIO, lines: bool
|
||||
) -> None:
|
||||
out = CWriter(outfile, 2, lines)
|
||||
emitter = Emitter(out)
|
||||
out.emit("\n")
|
||||
|
@ -185,7 +240,6 @@ def generate_tier1(
|
|||
out.start_line()
|
||||
out.emit("}")
|
||||
out.emit("\n")
|
||||
outfile.write(FOOTER)
|
||||
|
||||
|
||||
arg_parser = argparse.ArgumentParser(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue