Skip to content

Commit 1a9d8c7

Browse files
authored
gh-98831: rewrite pattern matching opcodes in the instruction definition DSL (#101287)
1 parent f02fa64 commit 1a9d8c7

File tree

5 files changed

+64
-73
lines changed

5 files changed

+64
-73
lines changed

Python/bytecodes.c

+13-37
Original file line numberDiff line numberDiff line change
@@ -2092,61 +2092,37 @@ dummy_func(
20922092
PUSH(len_o);
20932093
}
20942094

2095-
// stack effect: (__0, __1 -- )
2096-
inst(MATCH_CLASS) {
2095+
inst(MATCH_CLASS, (subject, type, names -- attrs)) {
20972096
// Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
20982097
// None on failure.
2099-
PyObject *names = POP();
2100-
PyObject *type = POP();
2101-
PyObject *subject = TOP();
21022098
assert(PyTuple_CheckExact(names));
2103-
PyObject *attrs = match_class(tstate, subject, type, oparg, names);
2104-
Py_DECREF(names);
2105-
Py_DECREF(type);
2099+
attrs = match_class(tstate, subject, type, oparg, names);
2100+
DECREF_INPUTS();
21062101
if (attrs) {
2107-
// Success!
2108-
assert(PyTuple_CheckExact(attrs));
2109-
SET_TOP(attrs);
2110-
}
2111-
else if (_PyErr_Occurred(tstate)) {
2112-
// Error!
2113-
goto error;
2102+
assert(PyTuple_CheckExact(attrs)); // Success!
21142103
}
21152104
else {
2116-
// Failure!
2117-
SET_TOP(Py_NewRef(Py_None));
2105+
ERROR_IF(_PyErr_Occurred(tstate), error); // Error!
2106+
attrs = Py_NewRef(Py_None); // Failure!
21182107
}
2119-
Py_DECREF(subject);
21202108
}
21212109

2122-
// stack effect: ( -- __0)
2123-
inst(MATCH_MAPPING) {
2124-
PyObject *subject = TOP();
2110+
inst(MATCH_MAPPING, (subject -- subject, res)) {
21252111
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
2126-
PyObject *res = match ? Py_True : Py_False;
2127-
PUSH(Py_NewRef(res));
2112+
res = Py_NewRef(match ? Py_True : Py_False);
21282113
PREDICT(POP_JUMP_IF_FALSE);
21292114
}
21302115

2131-
// stack effect: ( -- __0)
2132-
inst(MATCH_SEQUENCE) {
2133-
PyObject *subject = TOP();
2116+
inst(MATCH_SEQUENCE, (subject -- subject, res)) {
21342117
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
2135-
PyObject *res = match ? Py_True : Py_False;
2136-
PUSH(Py_NewRef(res));
2118+
res = Py_NewRef(match ? Py_True : Py_False);
21372119
PREDICT(POP_JUMP_IF_FALSE);
21382120
}
21392121

2140-
// stack effect: ( -- __0)
2141-
inst(MATCH_KEYS) {
2122+
inst(MATCH_KEYS, (subject, keys -- subject, keys, values_or_none)) {
21422123
// On successful match, PUSH(values). Otherwise, PUSH(None).
2143-
PyObject *keys = TOP();
2144-
PyObject *subject = SECOND();
2145-
PyObject *values_or_none = match_keys(tstate, subject, keys);
2146-
if (values_or_none == NULL) {
2147-
goto error;
2148-
}
2149-
PUSH(values_or_none);
2124+
values_or_none = match_keys(tstate, subject, keys);
2125+
ERROR_IF(values_or_none == NULL, error);
21502126
}
21512127

21522128
// stack effect: ( -- )

Python/generated_cases.c.h

+29-28
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/opcode_metadata.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ static const struct {
133133
[JUMP_IF_TRUE_OR_POP] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
134134
[JUMP_BACKWARD_NO_INTERRUPT] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
135135
[GET_LEN] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
136-
[MATCH_CLASS] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
137-
[MATCH_MAPPING] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
138-
[MATCH_SEQUENCE] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
139-
[MATCH_KEYS] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
136+
[MATCH_CLASS] = { 3, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
137+
[MATCH_MAPPING] = { 1, 2, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
138+
[MATCH_SEQUENCE] = { 1, 2, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
139+
[MATCH_KEYS] = { 2, 3, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
140140
[GET_ITER] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
141141
[GET_YIELD_FROM_ITER] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
142142
[FOR_ITER] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },

Tools/cases_generator/generate_cases.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
)
2727
BEGIN_MARKER = "// BEGIN BYTECODES //"
2828
END_MARKER = "// END BYTECODES //"
29-
RE_PREDICTED = r"^\s*(?:PREDICT\(|GO_TO_INSTRUCTION\(|DEOPT_IF\(.*?,\s*)(\w+)\);\s*$"
29+
RE_PREDICTED = r"^\s*(?:PREDICT\(|GO_TO_INSTRUCTION\(|DEOPT_IF\(.*?,\s*)(\w+)\);\s*(?://.*)?$"
3030
UNUSED = "unused"
3131
BITS_PER_CODE_UNIT = 16
3232

@@ -354,7 +354,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None
354354
assert dedent <= 0
355355
extra = " " * -dedent
356356
for line in self.block_text:
357-
if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*$", line):
357+
if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*(?://.*)?$", line):
358358
space, cond, label = m.groups()
359359
# ERROR_IF() must pop the inputs from the stack.
360360
# The code block is responsible for DECREF()ing them.
@@ -378,7 +378,7 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None
378378
)
379379
else:
380380
out.write_raw(f"{extra}{space}if ({cond}) goto {label};\n")
381-
elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*$", line):
381+
elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line):
382382
if not self.register:
383383
space = m.group(1)
384384
for ieff in self.input_effects:
@@ -964,7 +964,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], list[str]]:
964964

965965
# Separate PREDICT(...) macros from end
966966
predictions: list[str] = []
967-
while blocklines and (m := re.match(r"^\s*PREDICT\((\w+)\);\s*$", blocklines[-1])):
967+
while blocklines and (m := re.match(r"^\s*PREDICT\((\w+)\);\s*(?://.*)?$", blocklines[-1])):
968968
predictions.insert(0, m.group(1))
969969
blocklines.pop()
970970

Tools/cases_generator/test_generator.py

+14
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,20 @@ def test_error_if_plain():
215215
"""
216216
run_cases_test(input, output)
217217

218+
def test_error_if_plain_with_comment():
219+
input = """
220+
inst(OP, (--)) {
221+
ERROR_IF(cond, label); // Comment is ok
222+
}
223+
"""
224+
output = """
225+
TARGET(OP) {
226+
if (cond) goto label;
227+
DISPATCH();
228+
}
229+
"""
230+
run_cases_test(input, output)
231+
218232
def test_error_if_pop():
219233
input = """
220234
inst(OP, (left, right -- res)) {

0 commit comments

Comments
 (0)