From 7f1c98177bb27a45886fd7e42aa72bef9b1e4a0f Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 28 Mar 2015 01:14:45 +0200 Subject: [PATCH] vm: Support strict stackless mode, with proper exception reporting. I.e. in this mode, C stack will never be used to call a Python function, but if there's no free heap for a call, it will be reported as RuntimeError (as expected), not MemoryError. --- py/mpconfig.h | 10 +++++++++- py/runtime.h | 1 + py/stackctrl.c | 9 +++++++-- py/vm.c | 21 +++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/py/mpconfig.h b/py/mpconfig.h index 94e2737de0..d561f80790 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -125,11 +125,19 @@ #define MICROPY_QSTR_BYTES_IN_LEN (1) #endif -// Avoid using C stack when making Python function calls. +// Avoid using C stack when making Python function calls. C stack still +// may be used if there's no free heap. #ifndef MICROPY_STACKLESS #define MICROPY_STACKLESS (0) #endif +// Never use C stack when making Python function calls. This may break +// testsuite as will subtly change which exception is thrown in case +// of too deep recursion and other similar cases. +#ifndef MICROPY_STACKLESS_STRICT +#define MICROPY_STACKLESS_STRICT (0) +#endif + /*****************************************************************************/ /* Micro Python emitters */ diff --git a/py/runtime.h b/py/runtime.h index 8666ce1075..a36f1b1bd7 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -130,6 +130,7 @@ void mp_import_all(mp_obj_t module); // Raise NotImplementedError with given message NORETURN void mp_not_implemented(const char *msg); +NORETURN void mp_exc_recursion_depth(void); // helper functions for native/viper code mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type); diff --git a/py/stackctrl.c b/py/stackctrl.c index 7d7bbc1be1..4c51653727 100644 --- a/py/stackctrl.c +++ b/py/stackctrl.c @@ -27,6 +27,7 @@ #include "py/mpstate.h" #include "py/nlr.h" #include "py/obj.h" +#include "py/runtime.h" #include "py/stackctrl.h" void mp_stack_ctrl_init(void) { @@ -46,10 +47,14 @@ void mp_stack_set_limit(mp_uint_t limit) { MP_STATE_VM(stack_limit) = limit; } +void mp_exc_recursion_depth(void) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, + MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); +} + void mp_stack_check(void) { if (mp_stack_usage() >= MP_STATE_VM(stack_limit)) { - nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError, - MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded))); + mp_exc_recursion_depth(); } } diff --git a/py/vm.c b/py/vm.c index 291e707c1f..dc4f9c2739 100644 --- a/py/vm.c +++ b/py/vm.c @@ -880,6 +880,12 @@ unwind_jump:; nlr_pop(); goto run_code_state; } + #if MICROPY_STACKLESS_STRICT + else { + deep_recursion_error: + mp_exc_recursion_depth(); + } + #endif } #endif SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1)); @@ -912,6 +918,11 @@ unwind_jump:; nlr_pop(); goto run_code_state; } + #if MICROPY_STACKLESS_STRICT + else { + goto deep_recursion_error; + } + #endif } #endif SET_TOP(mp_call_method_n_kw_var(false, unum, sp)); @@ -941,6 +952,11 @@ unwind_jump:; nlr_pop(); goto run_code_state; } + #if MICROPY_STACKLESS_STRICT + else { + goto deep_recursion_error; + } + #endif } #endif SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp)); @@ -973,6 +989,11 @@ unwind_jump:; nlr_pop(); goto run_code_state; } + #if MICROPY_STACKLESS_STRICT + else { + goto deep_recursion_error; + } + #endif } #endif SET_TOP(mp_call_method_n_kw_var(true, unum, sp));