diff options
author | Brandt Bucher <brandt@python.org> | 2021-10-27 09:45:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-27 09:45:35 (GMT) |
commit | 82a662e5216a9b3969054c540a759a9493468510 (patch) | |
tree | 51bf9b433828dfd6d58f172097cf06202b54df9a /Python/compile.c | |
parent | 19a6c41e56f129a67e2a3c96464ba893a97236f7 (diff) | |
download | cpython-82a662e5216a9b3969054c540a759a9493468510.zip cpython-82a662e5216a9b3969054c540a759a9493468510.tar.gz cpython-82a662e5216a9b3969054c540a759a9493468510.tar.bz2 |
bpo-44511: Improve the bytecode for class and mapping patterns (GH-26922)
* Refactor mapping patterns and speed up class patterns.
* Simplify MATCH_KEYS and MATCH_CLASS.
* Add COPY opcode.
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/Python/compile.c b/Python/compile.c index 0c025ac..28b5c07 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1248,18 +1248,17 @@ stack_effect(int opcode, int oparg, int jump) case DICT_MERGE: case DICT_UPDATE: return -1; - case COPY_DICT_WITHOUT_KEYS: - return 0; case MATCH_CLASS: - return -1; + return -2; case GET_LEN: case MATCH_MAPPING: case MATCH_SEQUENCE: - return 1; case MATCH_KEYS: - return 2; + return 1; case ROT_N: return 0; + case COPY: + return 1; default: return PY_INVALID_STACK_EFFECT; } @@ -6118,10 +6117,16 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) } ADDOP_LOAD_CONST_NEW(c, attr_names); ADDOP_I(c, MATCH_CLASS, nargs); - // TOS is now a tuple of (nargs + nattrs) attributes. Preserve it: + ADDOP(c, DUP_TOP); + ADDOP_LOAD_CONST(c, Py_None); + ADDOP_I(c, IS_OP, 1); + // TOS is now a tuple of (nargs + nattrs) attributes (or None): pc->on_top++; RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + ADDOP_I(c, UNPACK_SEQUENCE, nargs + nattrs); + pc->on_top += nargs + nattrs - 1; for (i = 0; i < nargs + nattrs; i++) { + pc->on_top--; pattern_ty pattern; if (i < nargs) { // Positional: @@ -6132,17 +6137,12 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) pattern = asdl_seq_GET(kwd_patterns, i - nargs); } if (WILDCARD_CHECK(pattern)) { + ADDOP(c, POP_TOP); continue; } - // Get the i-th attribute, and match it against the i-th pattern: - ADDOP(c, DUP_TOP); - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); - ADDOP(c, BINARY_SUBSCR); RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); } // Success! Pop the tuple of attributes: - pc->on_top--; - ADDOP(c, POP_TOP); return 1; } @@ -6183,7 +6183,7 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) return compiler_error(c, "too many sub-patterns in mapping pattern"); } // Collect all of the keys into a tuple for MATCH_KEYS and - // COPY_DICT_WITHOUT_KEYS. They can either be dotted names or literals: + // **rest. They can either be dotted names or literals: // Maintaining a set of Constant_kind kind keys allows us to raise a // SyntaxError in the case of duplicates. @@ -6235,35 +6235,45 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) ADDOP(c, MATCH_KEYS); // There's now a tuple of keys and a tuple of values on top of the subject: pc->on_top += 2; + ADDOP(c, DUP_TOP); + ADDOP_LOAD_CONST(c, Py_None); + ADDOP_I(c, IS_OP, 1); RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); // So far so good. Use that tuple of values on the stack to match // sub-patterns against: + ADDOP_I(c, UNPACK_SEQUENCE, size); + pc->on_top += size - 1; for (Py_ssize_t i = 0; i < size; i++) { + pc->on_top--; pattern_ty pattern = asdl_seq_GET(patterns, i); - if (WILDCARD_CHECK(pattern)) { - continue; - } - ADDOP(c, DUP_TOP); - ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); - ADDOP(c, BINARY_SUBSCR); RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); } - // If we get this far, it's a match! We're done with the tuple of values, - // and whatever happens next should consume the tuple of keys underneath it: + // If we get this far, it's a match! Whatever happens next should consume + // the tuple of keys and the subject: pc->on_top -= 2; - ADDOP(c, POP_TOP); if (star_target) { - // If we have a starred name, bind a dict of remaining items to it: - ADDOP(c, COPY_DICT_WITHOUT_KEYS); + // If we have a starred name, bind a dict of remaining items to it (this may + // seem a bit inefficient, but keys is rarely big enough to actually impact + // runtime): + // rest = dict(TOS1) + // for key in TOS: + // del rest[key] + ADDOP_I(c, BUILD_MAP, 0); // [subject, keys, empty] + ADDOP(c, ROT_THREE); // [empty, subject, keys] + ADDOP(c, ROT_TWO); // [empty, keys, subject] + ADDOP_I(c, DICT_UPDATE, 2); // [copy, keys] + ADDOP_I(c, UNPACK_SEQUENCE, size); // [copy, keys...] + while (size) { + ADDOP_I(c, COPY, 1 + size--); // [copy, keys..., copy] + ADDOP(c, ROT_TWO); // [copy, keys..., copy, key] + ADDOP(c, DELETE_SUBSCR); // [copy, keys...] + } RETURN_IF_FALSE(pattern_helper_store_name(c, star_target, pc)); } else { - // Otherwise, we don't care about this tuple of keys anymore: - ADDOP(c, POP_TOP); + ADDOP(c, POP_TOP); // Tuple of keys. + ADDOP(c, POP_TOP); // Subject. } - // Pop the subject: - pc->on_top--; - ADDOP(c, POP_TOP); return 1; error: @@ -8362,6 +8372,11 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) fold_rotations(inst - oparg + 1, oparg); } break; + case COPY: + if (oparg == 1) { + inst->i_opcode = DUP_TOP; + } + break; default: /* All HAS_CONST opcodes should be handled with LOAD_CONST */ assert (!HAS_CONST(inst->i_opcode)); |