py: Use nlr jump callbacks to optimise compile/execute functions.
The changed functions now use less stack, and don't have any issues with local variables needing to be declared volatile. Testing on a PYBv1.0, imports (of .py, .mpy and frozen code) now use 64 less bytes of C stack per import depth. Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
parent
2757acf6ed
commit
ce31e5a2dc
|
@ -45,12 +45,18 @@ STATIC MP_DEFINE_CONST_OBJ_TYPE(
|
||||||
);
|
);
|
||||||
|
|
||||||
STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj_dict_t *locals) {
|
STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj_dict_t *locals) {
|
||||||
// save context and set new context
|
// save context
|
||||||
mp_obj_dict_t *old_globals = mp_globals_get();
|
nlr_jump_callback_node_globals_locals_t ctx;
|
||||||
mp_obj_dict_t *old_locals = mp_locals_get();
|
ctx.globals = mp_globals_get();
|
||||||
|
ctx.locals = mp_locals_get();
|
||||||
|
|
||||||
|
// set new context
|
||||||
mp_globals_set(globals);
|
mp_globals_set(globals);
|
||||||
mp_locals_set(locals);
|
mp_locals_set(locals);
|
||||||
|
|
||||||
|
// set exception handler to restore context if an exception is raised
|
||||||
|
nlr_push_jump_callback(&ctx.callback, mp_globals_locals_set_from_nlr_jump_callback);
|
||||||
|
|
||||||
// a bit of a hack: fun_bc will re-set globals, so need to make sure it's
|
// a bit of a hack: fun_bc will re-set globals, so need to make sure it's
|
||||||
// the correct one
|
// the correct one
|
||||||
if (mp_obj_is_type(self->module_fun, &mp_type_fun_bc)) {
|
if (mp_obj_is_type(self->module_fun, &mp_type_fun_bc)) {
|
||||||
|
@ -59,19 +65,13 @@ STATIC mp_obj_t code_execute(mp_obj_code_t *self, mp_obj_dict_t *globals, mp_obj
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute code
|
// execute code
|
||||||
nlr_buf_t nlr;
|
mp_obj_t ret = mp_call_function_0(self->module_fun);
|
||||||
if (nlr_push(&nlr) == 0) {
|
|
||||||
mp_obj_t ret = mp_call_function_0(self->module_fun);
|
// deregister exception handler and restore context
|
||||||
nlr_pop();
|
nlr_pop_jump_callback(true);
|
||||||
mp_globals_set(old_globals);
|
|
||||||
mp_locals_set(old_locals);
|
// return value
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
|
||||||
// exception; restore context and re-raise same exception
|
|
||||||
mp_globals_set(old_globals);
|
|
||||||
mp_locals_set(old_locals);
|
|
||||||
nlr_jump(nlr.ret_val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) {
|
||||||
|
|
|
@ -184,28 +184,23 @@ STATIC void do_execute_raw_code(const mp_module_context_t *context, const mp_raw
|
||||||
mp_obj_dict_t *mod_globals = context->module.globals;
|
mp_obj_dict_t *mod_globals = context->module.globals;
|
||||||
|
|
||||||
// save context
|
// save context
|
||||||
mp_obj_dict_t *volatile old_globals = mp_globals_get();
|
nlr_jump_callback_node_globals_locals_t ctx;
|
||||||
mp_obj_dict_t *volatile old_locals = mp_locals_get();
|
ctx.globals = mp_globals_get();
|
||||||
|
ctx.locals = mp_locals_get();
|
||||||
|
|
||||||
// set new context
|
// set new context
|
||||||
mp_globals_set(mod_globals);
|
mp_globals_set(mod_globals);
|
||||||
mp_locals_set(mod_globals);
|
mp_locals_set(mod_globals);
|
||||||
|
|
||||||
nlr_buf_t nlr;
|
// set exception handler to restore context if an exception is raised
|
||||||
if (nlr_push(&nlr) == 0) {
|
nlr_push_jump_callback(&ctx.callback, mp_globals_locals_set_from_nlr_jump_callback);
|
||||||
mp_obj_t module_fun = mp_make_function_from_raw_code(rc, context, NULL);
|
|
||||||
mp_call_function_0(module_fun);
|
|
||||||
|
|
||||||
// finish nlr block, restore context
|
// make and execute the function
|
||||||
nlr_pop();
|
mp_obj_t module_fun = mp_make_function_from_raw_code(rc, context, NULL);
|
||||||
mp_globals_set(old_globals);
|
mp_call_function_0(module_fun);
|
||||||
mp_locals_set(old_locals);
|
|
||||||
} else {
|
// deregister exception handler and restore context
|
||||||
// exception; restore context and re-raise same exception
|
nlr_pop_jump_callback(true);
|
||||||
mp_globals_set(old_globals);
|
|
||||||
mp_locals_set(old_locals);
|
|
||||||
nlr_jump(nlr.ret_val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
50
py/runtime.c
50
py/runtime.c
|
@ -188,6 +188,12 @@ void mp_deinit(void) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mp_globals_locals_set_from_nlr_jump_callback(void *ctx_in) {
|
||||||
|
nlr_jump_callback_node_globals_locals_t *ctx = ctx_in;
|
||||||
|
mp_globals_set(ctx->globals);
|
||||||
|
mp_locals_set(ctx->locals);
|
||||||
|
}
|
||||||
|
|
||||||
mp_obj_t MICROPY_WRAP_MP_LOAD_NAME(mp_load_name)(qstr qst) {
|
mp_obj_t MICROPY_WRAP_MP_LOAD_NAME(mp_load_name)(qstr qst) {
|
||||||
// logic: search locals, globals, builtins
|
// logic: search locals, globals, builtins
|
||||||
DEBUG_OP_printf("load name %s\n", qstr_str(qst));
|
DEBUG_OP_printf("load name %s\n", qstr_str(qst));
|
||||||
|
@ -1582,39 +1588,35 @@ void mp_import_all(mp_obj_t module) {
|
||||||
|
|
||||||
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) {
|
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
|
// save context
|
||||||
mp_obj_dict_t *volatile old_globals = mp_globals_get();
|
nlr_jump_callback_node_globals_locals_t ctx;
|
||||||
mp_obj_dict_t *volatile old_locals = mp_locals_get();
|
ctx.globals = mp_globals_get();
|
||||||
|
ctx.locals = mp_locals_get();
|
||||||
|
|
||||||
// set new context
|
// set new context
|
||||||
mp_globals_set(globals);
|
mp_globals_set(globals);
|
||||||
mp_locals_set(locals);
|
mp_locals_set(locals);
|
||||||
|
|
||||||
nlr_buf_t nlr;
|
// set exception handler to restore context if an exception is raised
|
||||||
if (nlr_push(&nlr) == 0) {
|
nlr_push_jump_callback(&ctx.callback, mp_globals_locals_set_from_nlr_jump_callback);
|
||||||
qstr source_name = lex->source_name;
|
|
||||||
mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind);
|
|
||||||
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, parse_input_kind == MP_PARSE_SINGLE_INPUT);
|
|
||||||
|
|
||||||
mp_obj_t ret;
|
qstr source_name = lex->source_name;
|
||||||
if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) {
|
mp_parse_tree_t parse_tree = mp_parse(lex, parse_input_kind);
|
||||||
// for compile only, return value is the module function
|
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, parse_input_kind == MP_PARSE_SINGLE_INPUT);
|
||||||
ret = module_fun;
|
|
||||||
} else {
|
|
||||||
// execute module function and get return value
|
|
||||||
ret = mp_call_function_0(module_fun);
|
|
||||||
}
|
|
||||||
|
|
||||||
// finish nlr block, restore context and return value
|
mp_obj_t ret;
|
||||||
nlr_pop();
|
if (MICROPY_PY_BUILTINS_COMPILE && globals == NULL) {
|
||||||
mp_globals_set(old_globals);
|
// for compile only, return value is the module function
|
||||||
mp_locals_set(old_locals);
|
ret = module_fun;
|
||||||
return ret;
|
|
||||||
} else {
|
} else {
|
||||||
// exception; restore context and re-raise same exception
|
// execute module function and get return value
|
||||||
mp_globals_set(old_globals);
|
ret = mp_call_function_0(module_fun);
|
||||||
mp_locals_set(old_locals);
|
|
||||||
nlr_jump(nlr.ret_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deregister exception handler and restore context
|
||||||
|
nlr_pop_jump_callback(true);
|
||||||
|
|
||||||
|
// return value
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // MICROPY_ENABLE_COMPILER
|
#endif // MICROPY_ENABLE_COMPILER
|
||||||
|
|
|
@ -66,6 +66,13 @@ typedef struct _mp_sched_node_t {
|
||||||
struct _mp_sched_node_t *next;
|
struct _mp_sched_node_t *next;
|
||||||
} mp_sched_node_t;
|
} mp_sched_node_t;
|
||||||
|
|
||||||
|
// For use with mp_globals_locals_set_from_nlr_jump_callback.
|
||||||
|
typedef struct _nlr_jump_callback_node_globals_locals_t {
|
||||||
|
nlr_jump_callback_node_t callback;
|
||||||
|
mp_obj_dict_t *globals;
|
||||||
|
mp_obj_dict_t *locals;
|
||||||
|
} nlr_jump_callback_node_globals_locals_t;
|
||||||
|
|
||||||
// Tables mapping operator enums to qstrs, defined in objtype.c
|
// Tables mapping operator enums to qstrs, defined in objtype.c
|
||||||
extern const byte mp_unary_op_method_name[];
|
extern const byte mp_unary_op_method_name[];
|
||||||
extern const byte mp_binary_op_method_name[];
|
extern const byte mp_binary_op_method_name[];
|
||||||
|
@ -113,6 +120,8 @@ static inline void mp_globals_set(mp_obj_dict_t *d) {
|
||||||
MP_STATE_THREAD(dict_globals) = d;
|
MP_STATE_THREAD(dict_globals) = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mp_globals_locals_set_from_nlr_jump_callback(void *ctx_in);
|
||||||
|
|
||||||
mp_obj_t mp_load_name(qstr qst);
|
mp_obj_t mp_load_name(qstr qst);
|
||||||
mp_obj_t mp_load_global(qstr qst);
|
mp_obj_t mp_load_global(qstr qst);
|
||||||
mp_obj_t mp_load_build_class(void);
|
mp_obj_t mp_load_build_class(void);
|
||||||
|
|
Loading…
Reference in New Issue