summaryrefslogtreecommitdiff
path: root/Python/compile.c
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2020-01-27 09:57:45 +0000
committerGitHub <noreply@github.com>2020-01-27 09:57:45 +0000
commit8a4cd700a7426341c2074a2b580306d2d60ec839 (patch)
tree64ff9fdc0361fe05e0ef5a2508e832a5de03b830 /Python/compile.c
parent72b1004657e60c900e4cd031b2635b587f4b280e (diff)
downloadcpython-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.c90
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;