py/compile: Add optimisation to compile OrderedDict inplace.

This optimisation eliminates the need to create a temporary normal dict.
The optimisation is enabled via MICROPY_COMP_CONST_LITERAL which is enabled
by default (although only has an effect if OrderdDict is enabled).

Thanks to @pfalcon for the initial idea and implementation.
This commit is contained in:
Damien George 2019-02-27 00:10:04 +11:00
parent 8ce22662fe
commit 0779693c23
2 changed files with 34 additions and 4 deletions

View File

@ -164,6 +164,7 @@ STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const cha
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map);
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
STATIC uint comp_next_label(compiler_t *comp) {
@ -2247,6 +2248,20 @@ STATIC void compile_atom_expr_normal(compiler_t *comp, mp_parse_node_struct_t *p
EMIT_ARG(call_function, 2, 0, 0);
i = 1;
}
#if MICROPY_COMP_CONST_LITERAL && MICROPY_PY_COLLECTIONS_ORDEREDDICT
// handle special OrderedDict constructor
} else if (MP_PARSE_NODE_IS_ID(pns->nodes[0])
&& MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]) == MP_QSTR_OrderedDict
&& MP_PARSE_NODE_STRUCT_KIND(pns_trail[0]) == PN_trailer_paren
&& MP_PARSE_NODE_IS_STRUCT_KIND(pns_trail[0]->nodes[0], PN_atom_brace)) {
// at this point we have matched "OrderedDict({...})"
EMIT_ARG(call_function, 0, 0, 0);
mp_parse_node_struct_t *pns_dict = (mp_parse_node_struct_t*)pns_trail[0]->nodes[0];
compile_atom_brace_helper(comp, pns_dict, false);
i = 1;
#endif
}
// compile the remaining trailers
@ -2455,16 +2470,20 @@ STATIC void compile_atom_bracket(compiler_t *comp, mp_parse_node_struct_t *pns)
}
}
STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
STATIC void compile_atom_brace_helper(compiler_t *comp, mp_parse_node_struct_t *pns, bool create_map) {
mp_parse_node_t pn = pns->nodes[0];
if (MP_PARSE_NODE_IS_NULL(pn)) {
// empty dict
EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);
if (create_map) {
EMIT_ARG(build, 0, MP_EMIT_BUILD_MAP);
}
} else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
pns = (mp_parse_node_struct_t*)pn;
if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker_item) {
// dict with one element
EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP);
if (create_map) {
EMIT_ARG(build, 1, MP_EMIT_BUILD_MAP);
}
compile_node(comp, pn);
EMIT(store_map);
} else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) {
@ -2481,7 +2500,9 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
bool is_dict;
if (!MICROPY_PY_BUILTINS_SET || MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_dictorsetmaker_item)) {
// a dictionary
EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP);
if (create_map) {
EMIT_ARG(build, 1 + n, MP_EMIT_BUILD_MAP);
}
compile_node(comp, pns->nodes[0]);
EMIT(store_map);
is_dict = true;
@ -2551,6 +2572,10 @@ STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
}
}
STATIC void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_atom_brace_helper(comp, pns, true);
}
STATIC void compile_trailer_paren(compiler_t *comp, mp_parse_node_struct_t *pns) {
compile_trailer_paren_helper(comp, pns->nodes[0], false, 0);
}

View File

@ -356,6 +356,11 @@
#define MICROPY_COMP_CONST_FOLDING (1)
#endif
// Whether to enable optimisations for constant literals, eg OrderedDict
#ifndef MICROPY_COMP_CONST_LITERAL
#define MICROPY_COMP_CONST_LITERAL (1)
#endif
// Whether to enable lookup of constants in modules; eg module.CONST
#ifndef MICROPY_COMP_MODULE_CONST
#define MICROPY_COMP_MODULE_CONST (0)