From dd5353a4054024a411aa343a22ffcd16195a16ad Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 18 Dec 2015 12:35:44 +0000 Subject: [PATCH] py: Add MICROPY_ENABLE_COMPILER and MICROPY_PY_BUILTINS_EVAL_EXEC opts. MICROPY_ENABLE_COMPILER can be used to enable/disable the entire compiler, which is useful when only loading of pre-compiled bytecode is supported. It is enabled by default. MICROPY_PY_BUILTINS_EVAL_EXEC controls support of eval and exec builtin functions. By default they are only included if MICROPY_ENABLE_COMPILER is enabled. Disabling both options saves about 40k of code size on 32-bit x86. --- py/builtinevex.c | 4 ++++ py/builtinimport.c | 12 +++++++++++- py/compile.c | 4 ++++ py/emitbc.c | 4 ++++ py/emitcommon.c | 4 ++++ py/lexer.c | 4 ++++ py/lexerstr.c | 4 ++++ py/modbuiltins.c | 2 ++ py/mpconfig.h | 11 +++++++++++ py/parse.c | 4 ++++ py/runtime.c | 4 ++++ py/scope.c | 4 ++++ 12 files changed, 60 insertions(+), 1 deletion(-) diff --git a/py/builtinevex.c b/py/builtinevex.c index c14869e350..cac74e94fd 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -107,6 +107,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_compile_obj, 3, 6, mp_builtin_com #endif // MICROPY_PY_BUILTINS_COMPILE +#if MICROPY_PY_BUILTINS_EVAL_EXEC + STATIC mp_obj_t eval_exec_helper(mp_uint_t n_args, const mp_obj_t *args, mp_parse_input_kind_t parse_input_kind) { // work out the context mp_obj_dict_t *globals = mp_globals_get(); @@ -155,6 +157,8 @@ STATIC mp_obj_t mp_builtin_exec(mp_uint_t n_args, const mp_obj_t *args) { } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_exec_obj, 1, 3, mp_builtin_exec); +#endif // MICROPY_PY_BUILTINS_EVAL_EXEC + #if MICROPY_PY_BUILTINS_EXECFILE STATIC mp_obj_t mp_builtin_execfile(mp_uint_t n_args, const mp_obj_t *args) { // MP_PARSE_SINGLE_INPUT is used to indicate a file input diff --git a/py/builtinimport.c b/py/builtinimport.c index a8d5f06968..2560ec1563 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -120,6 +120,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d #endif } +#if MICROPY_ENABLE_COMPILER STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char *fname) { if (lex == NULL) { @@ -141,6 +142,7 @@ STATIC void do_load_from_lexer(mp_obj_t module_obj, mp_lexer_t *lex, const char mp_obj_dict_t *mod_globals = mp_obj_module_get_globals(module_obj); mp_parse_compile_execute(lex, MP_PARSE_FILE_INPUT, mod_globals, mod_globals); } +#endif #if MICROPY_PERSISTENT_CODE_LOAD STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { @@ -182,16 +184,24 @@ STATIC void do_execute_raw_code(mp_obj_t module_obj, mp_raw_code_t *raw_code) { STATIC void do_load(mp_obj_t module_obj, vstr_t *file) { // create the lexer char *file_str = vstr_null_terminated_str(file); + #if MICROPY_PERSISTENT_CODE_LOAD if (file_str[file->len - 3] == 'm') { mp_raw_code_t *raw_code = mp_raw_code_load_file(file_str); do_execute_raw_code(module_obj, raw_code); - } else + return; + } #endif + + #if MICROPY_ENABLE_COMPILER { mp_lexer_t *lex = mp_lexer_new_from_file(file_str); do_load_from_lexer(module_obj, lex, file_str); } + #else + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ImportError, + "script compilation not supported")); + #endif } STATIC void chop_component(const char *start, const char **end) { diff --git a/py/compile.c b/py/compile.c index 4b929d52ff..f349dca2b3 100644 --- a/py/compile.c +++ b/py/compile.c @@ -35,6 +35,8 @@ #include "py/compile.h" #include "py/runtime.h" +#if MICROPY_ENABLE_COMPILER + // TODO need to mangle __attr names typedef enum { @@ -3310,3 +3312,5 @@ mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, uint emit_opt // return function that executes the outer module return mp_make_function_from_raw_code(rc, MP_OBJ_NULL, MP_OBJ_NULL); } + +#endif // MICROPY_ENABLE_COMPILER diff --git a/py/emitbc.c b/py/emitbc.c index 7957a21314..2f5304deb1 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -34,6 +34,8 @@ #include "py/emit.h" #include "py/bc0.h" +#if MICROPY_ENABLE_COMPILER + #define BYTES_FOR_INT ((BYTES_PER_WORD * 8 + 6) / 7) #define DUMMY_DATA_SIZE (BYTES_FOR_INT) @@ -1070,3 +1072,5 @@ const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_delete_id_ops = { mp_emit_bc_delete_global, }; #endif + +#endif //MICROPY_ENABLE_COMPILER diff --git a/py/emitcommon.c b/py/emitcommon.c index 1fd2bd1dc1..435188f366 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -28,6 +28,8 @@ #include "py/emit.h" +#if MICROPY_ENABLE_COMPILER + void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) { // name adding/lookup bool added; @@ -77,3 +79,5 @@ void mp_emit_common_id_op(emit_t *emit, const mp_emit_method_table_id_ops_t *emi emit_method_table->deref(emit, qst, id->local_num); } } + +#endif // MICROPY_ENABLE_COMPILER diff --git a/py/lexer.c b/py/lexer.c index 6bacb9fc6f..89ecc386e9 100644 --- a/py/lexer.c +++ b/py/lexer.c @@ -31,6 +31,8 @@ #include "py/lexer.h" #include "py/runtime.h" +#if MICROPY_ENABLE_COMPILER + #define TAB_SIZE (8) // TODO seems that CPython allows NULL byte in the input stream @@ -785,3 +787,5 @@ void mp_lexer_show_token(const mp_lexer_t *lex) { printf("\n"); } #endif + +#endif // MICROPY_ENABLE_COMPILER diff --git a/py/lexerstr.c b/py/lexerstr.c index 5481b1032d..9fdf4c1eb5 100644 --- a/py/lexerstr.c +++ b/py/lexerstr.c @@ -26,6 +26,8 @@ #include "py/lexer.h" +#if MICROPY_ENABLE_COMPILER + typedef struct _mp_lexer_str_buf_t { mp_uint_t free_len; // if > 0, src_beg will be freed when done by: m_free(src_beg, free_len) const char *src_beg; // beginning of source @@ -59,3 +61,5 @@ mp_lexer_t *mp_lexer_new_from_str_len(qstr src_name, const char *str, mp_uint_t sb->src_end = str + len; return mp_lexer_new(src_name, sb, (mp_lexer_stream_next_byte_t)str_buf_next_byte, (mp_lexer_stream_close_t)str_buf_free); } + +#endif // MICROPY_ENABLE_COMPILER diff --git a/py/modbuiltins.c b/py/modbuiltins.c index 2d2dd054e6..9d1e90f578 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -630,8 +630,10 @@ STATIC const mp_rom_map_elem_t mp_module_builtins_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_chr), MP_ROM_PTR(&mp_builtin_chr_obj) }, { MP_ROM_QSTR(MP_QSTR_dir), MP_ROM_PTR(&mp_builtin_dir_obj) }, { MP_ROM_QSTR(MP_QSTR_divmod), MP_ROM_PTR(&mp_builtin_divmod_obj) }, + #if MICROPY_PY_BUILTINS_EVAL_EXEC { MP_ROM_QSTR(MP_QSTR_eval), MP_ROM_PTR(&mp_builtin_eval_obj) }, { MP_ROM_QSTR(MP_QSTR_exec), MP_ROM_PTR(&mp_builtin_exec_obj) }, + #endif #if MICROPY_PY_BUILTINS_EXECFILE { MP_ROM_QSTR(MP_QSTR_execfile), MP_ROM_PTR(&mp_builtin_execfile_obj) }, #endif diff --git a/py/mpconfig.h b/py/mpconfig.h index c05f33c453..58aa2ce0c0 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -278,6 +278,11 @@ /*****************************************************************************/ /* Compiler configuration */ +// Whether to include the compiler +#ifndef MICROPY_ENABLE_COMPILER +#define MICROPY_ENABLE_COMPILER (1) +#endif + // Whether to enable constant folding; eg 1+2 rewritten as 3 #ifndef MICROPY_COMP_CONST_FOLDING #define MICROPY_COMP_CONST_FOLDING (1) @@ -590,6 +595,12 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_ENUMERATE (1) #endif +// Whether to support eval and exec functions +// By default they are supported if the compiler is enabled +#ifndef MICROPY_PY_BUILTINS_EVAL_EXEC +#define MICROPY_PY_BUILTINS_EVAL_EXEC (MICROPY_ENABLE_COMPILER) +#endif + // Whether to support the Python 2 execfile function #ifndef MICROPY_PY_BUILTINS_EXECFILE #define MICROPY_PY_BUILTINS_EXECFILE (0) diff --git a/py/parse.c b/py/parse.c index ae15373227..1741757646 100644 --- a/py/parse.c +++ b/py/parse.c @@ -38,6 +38,8 @@ #include "py/runtime.h" #include "py/builtin.h" +#if MICROPY_ENABLE_COMPILER + #define RULE_ACT_ARG_MASK (0x0f) #define RULE_ACT_KIND_MASK (0x30) #define RULE_ACT_ALLOW_IDENT (0x40) @@ -1079,3 +1081,5 @@ void mp_parse_tree_clear(mp_parse_tree_t *tree) { chunk = next; } } + +#endif // MICROPY_ENABLE_COMPILER diff --git a/py/runtime.c b/py/runtime.c index c9a56f635b..3a1f588ab7 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1304,6 +1304,8 @@ void mp_import_all(mp_obj_t module) { } } +#if MICROPY_ENABLE_COMPILER + // this is implemented in this file so it can optimise access to locals/globals mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_input_kind, mp_obj_dict_t *globals, mp_obj_dict_t *locals) { // save context @@ -1342,6 +1344,8 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i } } +#endif // MICROPY_ENABLE_COMPILER + void *m_malloc_fail(size_t num_bytes) { DEBUG_printf("memory allocation failed, allocating " UINT_FMT " bytes\n", num_bytes); if (0) { diff --git a/py/scope.c b/py/scope.c index f9b1fb122b..632e527521 100644 --- a/py/scope.c +++ b/py/scope.c @@ -28,6 +28,8 @@ #include "py/scope.h" +#if MICROPY_ENABLE_COMPILER + scope_t *scope_new(scope_kind_t kind, mp_parse_node_t pn, qstr source_file, mp_uint_t emit_options) { scope_t *scope = m_new0(scope_t, 1); scope->kind = kind; @@ -149,3 +151,5 @@ void scope_close_over_in_parents(scope_t *scope, qstr qst) { } assert(0); // we should have found the variable in one of the parents } + +#endif // MICROPY_ENABLE_COMPILER