summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Python/bytecodes.c50
-rw-r--r--Python/generated_cases.c.h57
-rw-r--r--Python/opcode_metadata.h8
-rw-r--r--Tools/cases_generator/generate_cases.py8
-rw-r--r--Tools/cases_generator/test_generator.py14
5 files changed, 64 insertions, 73 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index ac54791..d3e242b 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2092,61 +2092,37 @@ dummy_func(
PUSH(len_o);
}
- // stack effect: (__0, __1 -- )
- inst(MATCH_CLASS) {
+ inst(MATCH_CLASS, (subject, type, names -- attrs)) {
// Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
// None on failure.
- PyObject *names = POP();
- PyObject *type = POP();
- PyObject *subject = TOP();
assert(PyTuple_CheckExact(names));
- PyObject *attrs = match_class(tstate, subject, type, oparg, names);
- Py_DECREF(names);
- Py_DECREF(type);
+ attrs = match_class(tstate, subject, type, oparg, names);
+ DECREF_INPUTS();
if (attrs) {
- // Success!
- assert(PyTuple_CheckExact(attrs));
- SET_TOP(attrs);
- }
- else if (_PyErr_Occurred(tstate)) {
- // Error!
- goto error;
+ assert(PyTuple_CheckExact(attrs)); // Success!
}
else {
- // Failure!
- SET_TOP(Py_NewRef(Py_None));
+ ERROR_IF(_PyErr_Occurred(tstate), error); // Error!
+ attrs = Py_NewRef(Py_None); // Failure!
}
- Py_DECREF(subject);
}
- // stack effect: ( -- __0)
- inst(MATCH_MAPPING) {
- PyObject *subject = TOP();
+ inst(MATCH_MAPPING, (subject -- subject, res)) {
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
- PyObject *res = match ? Py_True : Py_False;
- PUSH(Py_NewRef(res));
+ res = Py_NewRef(match ? Py_True : Py_False);
PREDICT(POP_JUMP_IF_FALSE);
}
- // stack effect: ( -- __0)
- inst(MATCH_SEQUENCE) {
- PyObject *subject = TOP();
+ inst(MATCH_SEQUENCE, (subject -- subject, res)) {
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
- PyObject *res = match ? Py_True : Py_False;
- PUSH(Py_NewRef(res));
+ res = Py_NewRef(match ? Py_True : Py_False);
PREDICT(POP_JUMP_IF_FALSE);
}
- // stack effect: ( -- __0)
- inst(MATCH_KEYS) {
+ inst(MATCH_KEYS, (subject, keys -- subject, keys, values_or_none)) {
// On successful match, PUSH(values). Otherwise, PUSH(None).
- PyObject *keys = TOP();
- PyObject *subject = SECOND();
- PyObject *values_or_none = match_keys(tstate, subject, keys);
- if (values_or_none == NULL) {
- goto error;
- }
- PUSH(values_or_none);
+ values_or_none = match_keys(tstate, subject, keys);
+ ERROR_IF(values_or_none == NULL, error);
}
// stack effect: ( -- )
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 5dcc8ee..7d3396a 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2479,59 +2479,60 @@
}
TARGET(MATCH_CLASS) {
+ PyObject *names = PEEK(1);
+ PyObject *type = PEEK(2);
+ PyObject *subject = PEEK(3);
+ PyObject *attrs;
// Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
// None on failure.
- PyObject *names = POP();
- PyObject *type = POP();
- PyObject *subject = TOP();
assert(PyTuple_CheckExact(names));
- PyObject *attrs = match_class(tstate, subject, type, oparg, names);
- Py_DECREF(names);
+ attrs = match_class(tstate, subject, type, oparg, names);
+ Py_DECREF(subject);
Py_DECREF(type);
+ Py_DECREF(names);
if (attrs) {
- // Success!
- assert(PyTuple_CheckExact(attrs));
- SET_TOP(attrs);
- }
- else if (_PyErr_Occurred(tstate)) {
- // Error!
- goto error;
+ assert(PyTuple_CheckExact(attrs)); // Success!
}
else {
- // Failure!
- SET_TOP(Py_NewRef(Py_None));
+ if (_PyErr_Occurred(tstate)) goto pop_3_error;
+ attrs = Py_NewRef(Py_None); // Failure!
}
- Py_DECREF(subject);
+ STACK_SHRINK(2);
+ POKE(1, attrs);
DISPATCH();
}
TARGET(MATCH_MAPPING) {
- PyObject *subject = TOP();
+ PyObject *subject = PEEK(1);
+ PyObject *res;
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
- PyObject *res = match ? Py_True : Py_False;
- PUSH(Py_NewRef(res));
+ res = Py_NewRef(match ? Py_True : Py_False);
+ STACK_GROW(1);
+ POKE(1, res);
PREDICT(POP_JUMP_IF_FALSE);
DISPATCH();
}
TARGET(MATCH_SEQUENCE) {
- PyObject *subject = TOP();
+ PyObject *subject = PEEK(1);
+ PyObject *res;
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
- PyObject *res = match ? Py_True : Py_False;
- PUSH(Py_NewRef(res));
+ res = Py_NewRef(match ? Py_True : Py_False);
+ STACK_GROW(1);
+ POKE(1, res);
PREDICT(POP_JUMP_IF_FALSE);
DISPATCH();
}
TARGET(MATCH_KEYS) {
+ PyObject *keys = PEEK(1);
+ PyObject *subject = PEEK(2);
+ PyObject *values_or_none;
// On successful match, PUSH(values). Otherwise, PUSH(None).
- PyObject *keys = TOP();
- PyObject *subject = SECOND();
- PyObject *values_or_none = match_keys(tstate, subject, keys);
- if (values_or_none == NULL) {
- goto error;
- }
- PUSH(values_or_none);
+ values_or_none = match_keys(tstate, subject, keys);
+ if (values_or_none == NULL) goto error;
+ STACK_GROW(1);
+ POKE(1, values_or_none);
DISPATCH();
}
diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h
index 1fb0acc..f9c6401 100644
--- a/Python/opcode_metadata.h
+++ b/Python/opcode_metadata.h
@@ -133,10 +133,10 @@ static const struct {
[JUMP_IF_TRUE_OR_POP] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[JUMP_BACKWARD_NO_INTERRUPT] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[GET_LEN] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
- [MATCH_CLASS] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
- [MATCH_MAPPING] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
- [MATCH_SEQUENCE] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
- [MATCH_KEYS] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
+ [MATCH_CLASS] = { 3, 1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
+ [MATCH_MAPPING] = { 1, 2, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
+ [MATCH_SEQUENCE] = { 1, 2, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
+ [MATCH_KEYS] = { 2, 3, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
[GET_ITER] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
[GET_YIELD_FROM_ITER] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
[FOR_ITER] = { -1, -1, DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py
index 90f101a..429c9d3 100644
--- a/Tools/cases_generator/generate_cases.py
+++ b/Tools/cases_generator/generate_cases.py
@@ -26,7 +26,7 @@ DEFAULT_METADATA_OUTPUT = os.path.relpath(
)
BEGIN_MARKER = "// BEGIN BYTECODES //"
END_MARKER = "// END BYTECODES //"
-RE_PREDICTED = r"^\s*(?:PREDICT\(|GO_TO_INSTRUCTION\(|DEOPT_IF\(.*?,\s*)(\w+)\);\s*$"
+RE_PREDICTED = r"^\s*(?:PREDICT\(|GO_TO_INSTRUCTION\(|DEOPT_IF\(.*?,\s*)(\w+)\);\s*(?://.*)?$"
UNUSED = "unused"
BITS_PER_CODE_UNIT = 16
@@ -354,7 +354,7 @@ class Instruction:
assert dedent <= 0
extra = " " * -dedent
for line in self.block_text:
- if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*$", line):
+ if m := re.match(r"(\s*)ERROR_IF\((.+), (\w+)\);\s*(?://.*)?$", line):
space, cond, label = m.groups()
# ERROR_IF() must pop the inputs from the stack.
# The code block is responsible for DECREF()ing them.
@@ -378,7 +378,7 @@ class Instruction:
)
else:
out.write_raw(f"{extra}{space}if ({cond}) goto {label};\n")
- elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*$", line):
+ elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*(?://.*)?$", line):
if not self.register:
space = m.group(1)
for ieff in self.input_effects:
@@ -964,7 +964,7 @@ def extract_block_text(block: parser.Block) -> tuple[list[str], list[str]]:
# Separate PREDICT(...) macros from end
predictions: list[str] = []
- while blocklines and (m := re.match(r"^\s*PREDICT\((\w+)\);\s*$", blocklines[-1])):
+ while blocklines and (m := re.match(r"^\s*PREDICT\((\w+)\);\s*(?://.*)?$", blocklines[-1])):
predictions.insert(0, m.group(1))
blocklines.pop()
diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py
index ae0c1e2..c59aae8 100644
--- a/Tools/cases_generator/test_generator.py
+++ b/Tools/cases_generator/test_generator.py
@@ -215,6 +215,20 @@ def test_error_if_plain():
"""
run_cases_test(input, output)
+def test_error_if_plain_with_comment():
+ input = """
+ inst(OP, (--)) {
+ ERROR_IF(cond, label); // Comment is ok
+ }
+ """
+ output = """
+ TARGET(OP) {
+ if (cond) goto label;
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
def test_error_if_pop():
input = """
inst(OP, (left, right -- res)) {