diff options
author | Mark Shannon <mark@hotpy.org> | 2020-01-27 09:57:45 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-27 09:57:45 +0000 |
commit | 8a4cd700a7426341c2074a2b580306d2d60ec839 (patch) | |
tree | 64ff9fdc0361fe05e0ef5a2508e832a5de03b830 /Python/compile.c | |
parent | 72b1004657e60c900e4cd031b2635b587f4b280e (diff) | |
download | cpython-git-8a4cd700a7426341c2074a2b580306d2d60ec839.tar.gz |
bpo-39320: Handle unpacking of **values in compiler (GH-18141)
* Add DICT_UPDATE and DICT_MERGE bytecodes. Use them for ** unpacking.
* Remove BUILD_MAP_UNPACK and BUILD_MAP_UNPACK_WITH_CALL, as they are now unused.
* Update magic number for ** unpacking opcodes.
* Update dis.rst to incorporate new bytecodes.
* Add blurb entry.
Diffstat (limited to 'Python/compile.c')
-rw-r--r-- | Python/compile.c | 90 |
1 files changed, 58 insertions, 32 deletions
diff --git a/Python/compile.c b/Python/compile.c index 9ed29f4a1f..6776df54d4 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1007,9 +1007,6 @@ stack_effect(int opcode, int oparg, int jump) case BUILD_SET: case BUILD_STRING: return 1-oparg; - case BUILD_MAP_UNPACK: - case BUILD_MAP_UNPACK_WITH_CALL: - return 1 - oparg; case BUILD_MAP: return 1 - 2*oparg; case BUILD_CONST_KEY_MAP: @@ -1125,6 +1122,8 @@ stack_effect(int opcode, int oparg, int jump) return 0; case LIST_EXTEND: case SET_UPDATE: + case DICT_MERGE: + case DICT_UPDATE: return -1; default: return PY_INVALID_STACK_EFFECT; @@ -3868,37 +3867,58 @@ static int compiler_dict(struct compiler *c, expr_ty e) { Py_ssize_t i, n, elements; - int containers; + int have_dict; int is_unpacking = 0; n = asdl_seq_LEN(e->v.Dict.values); - containers = 0; + have_dict = 0; elements = 0; for (i = 0; i < n; i++) { is_unpacking = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i) == NULL; - if (elements == 0xFFFF || (elements && is_unpacking)) { - if (!compiler_subdict(c, e, i - elements, i)) - return 0; - containers++; - elements = 0; - } if (is_unpacking) { + if (elements) { + if (!compiler_subdict(c, e, i - elements, i)) { + return 0; + } + if (have_dict) { + ADDOP_I(c, DICT_UPDATE, 1); + } + have_dict = 1; + elements = 0; + } + if (have_dict == 0) { + ADDOP_I(c, BUILD_MAP, 0); + have_dict = 1; + } VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); - containers++; + ADDOP_I(c, DICT_UPDATE, 1); } else { - elements++; + if (elements == 0xFFFF) { + if (!compiler_subdict(c, e, i - elements, i)) { + return 0; + } + if (have_dict) { + ADDOP_I(c, DICT_UPDATE, 1); + } + have_dict = 1; + elements = 0; + } + else { + elements++; + } } } - if (elements || containers == 0) { - if (!compiler_subdict(c, e, n - elements, n)) + if (elements) { + if (!compiler_subdict(c, e, n - elements, n)) { return 0; - containers++; + } + if (have_dict) { + ADDOP_I(c, DICT_UPDATE, 1); + } + have_dict = 1; } - /* If there is more than one dict, they need to be merged into a new - * dict. If there is one dict and it's an unpacking, then it needs - * to be copied into a new dict." */ - if (containers > 1 || is_unpacking) { - ADDOP_I(c, BUILD_MAP_UNPACK, containers); + if (!have_dict) { + ADDOP_I(c, BUILD_MAP, 0); } return 1; } @@ -4263,8 +4283,8 @@ ex_call: } /* Then keyword arguments */ if (nkwelts) { - /* the number of dictionaries on the stack */ - Py_ssize_t nsubkwargs = 0; + /* Has a new dict been pushed */ + int have_dict = 0; nseen = 0; /* the number of keyword arguments on the stack following */ for (i = 0; i < nkwelts; i++) { @@ -4272,13 +4292,18 @@ ex_call: if (kw->arg == NULL) { /* A keyword argument unpacking. */ if (nseen) { - if (!compiler_subkwargs(c, keywords, i - nseen, i)) + if (!compiler_subkwargs(c, keywords, i - nseen, i)) { return 0; - nsubkwargs++; + } + have_dict = 1; nseen = 0; } + if (!have_dict) { + ADDOP_I(c, BUILD_MAP, 0); + have_dict = 1; + } VISIT(c, expr, kw->value); - nsubkwargs++; + ADDOP_I(c, DICT_MERGE, 1); } else { nseen++; @@ -4286,14 +4311,15 @@ ex_call: } if (nseen) { /* Pack up any trailing keyword arguments. */ - if (!compiler_subkwargs(c, keywords, nkwelts - nseen, nkwelts)) + if (!compiler_subkwargs(c, keywords, nkwelts - nseen, nkwelts)) { return 0; - nsubkwargs++; - } - if (nsubkwargs > 1) { - /* Pack it all up */ - ADDOP_I(c, BUILD_MAP_UNPACK_WITH_CALL, nsubkwargs); + } + if (have_dict) { + ADDOP_I(c, DICT_MERGE, 1); + } + have_dict = 1; } + assert(have_dict); } ADDOP_I(c, CALL_FUNCTION_EX, nkwelts > 0); return 1; |