From d3b1f0b627ccc6705d9fe958549badb87a74ded1 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Fri, 29 Jan 2016 01:05:53 +0200 Subject: [PATCH] py/runtime: mp_stack_ctrl_init() should be called immediately on startup. Calling it from mp_init() is too late for some ports (like Unix), and leads to incomplete stack frame being captured, with following GC issues. So, now each port should call mp_stack_ctrl_init() on its own, ASAP after startup, and taking special precautions so it really was called before stack variables get allocated (because if such variable with a pointer is missed, it may lead to over-collecting (typical symptom is segfaulting)). --- py/runtime.c | 1 - qemu-arm/main.c | 1 + qemu-arm/test_main.c | 1 + stmhal/main.c | 1 + teensy/main.c | 1 + unix/main.c | 12 ++++++++++++ unix/mpconfigport.h | 4 ++++ windows/mpconfigport.h | 5 +++++ 8 files changed, 25 insertions(+), 1 deletion(-) diff --git a/py/runtime.c b/py/runtime.c index b0f407a150..e4a4d5b3f5 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -61,7 +61,6 @@ const mp_obj_module_t mp_module___main__ = { void mp_init(void) { qstr_init(); - mp_stack_ctrl_init(); // no pending exceptions to start with MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL; diff --git a/qemu-arm/main.c b/qemu-arm/main.c index f295475234..b6ff73980c 100644 --- a/qemu-arm/main.c +++ b/qemu-arm/main.c @@ -32,6 +32,7 @@ void do_str(const char *src, mp_parse_input_kind_t input_kind) { } int main(int argc, char **argv) { + mp_stack_ctrl_init(); mp_stack_set_limit(10240); void *heap = malloc(16 * 1024); gc_init(heap, (char*)heap + 16 * 1024); diff --git a/qemu-arm/test_main.c b/qemu-arm/test_main.c index a98e275cee..44f9cc6663 100644 --- a/qemu-arm/test_main.c +++ b/qemu-arm/test_main.c @@ -49,6 +49,7 @@ end: int main() { const char a[] = {"sim"}; + mp_stack_ctrl_init(); mp_stack_set_limit(10240); void *heap = malloc(256 * 1024); gc_init(heap, (char*)heap + 256 * 1024); diff --git a/stmhal/main.c b/stmhal/main.c index cce114605a..0e5fc44af3 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -335,6 +335,7 @@ int main(void) { // Stack limit should be less than real stack size, so we have a chance // to recover from limit hit. (Limit is measured in bytes.) + mp_stack_ctrl_init(); mp_stack_set_limit((char*)&_ram_end - (char*)&_heap_end - 1024); /* STM32F4xx HAL library initialization: diff --git a/teensy/main.c b/teensy/main.c index b630e88867..41e445cb59 100644 --- a/teensy/main.c +++ b/teensy/main.c @@ -253,6 +253,7 @@ int main(void) { #define SCB_CCR_STKALIGN (1 << 9) SCB_CCR |= SCB_CCR_STKALIGN; + mp_stack_ctrl_init(); mp_stack_set_limit(10240); pinMode(LED_BUILTIN, OUTPUT); diff --git a/unix/main.c b/unix/main.c index 03902a3e9a..4ba68dcb9b 100644 --- a/unix/main.c +++ b/unix/main.c @@ -376,7 +376,19 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) { #define PATHLIST_SEP_CHAR ':' #endif +MP_NOINLINE int main_(int argc, char **argv); + int main(int argc, char **argv) { + // We should capture stack top ASAP after start, and it should be + // captured guaranteedly before any other stack variables are allocated. + // For this, actual main (renamed main_) should not be inlined into + // this function. main_() itself may have other functions inlined (with + // their own stack variables), that's why we need this main/main_ split. + mp_stack_ctrl_init(); + return main_(argc, argv); +} + +MP_NOINLINE int main_(int argc, char **argv) { mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); pre_process_options(argc, argv); diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 2f992fdf03..f7fdeec07c 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -214,6 +214,10 @@ void mp_unix_mark_exec(void); #define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size) #define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size) +#ifndef MP_NOINLINE +#define MP_NOINLINE __attribute__((noinline)) +#endif + #if MICROPY_PY_OS_DUPTERM #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) #else diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index 80166f1495..ad79ef3813 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -178,6 +178,10 @@ extern const struct _mp_obj_module_t mp_module_time; #include "init.h" #include "sleep.h" +#ifdef __GNUC__ +#define MP_NOINLINE __attribute__((noinline)) +#endif + // MSVC specifics #ifdef _MSC_VER @@ -191,6 +195,7 @@ extern const struct _mp_obj_module_t mp_module_time; // CL specific overrides from mpconfig #define NORETURN __declspec(noreturn) +#define MP_NOINLINE __declspec(noinline) #define MP_LIKELY(x) (x) #define MP_UNLIKELY(x) (x) #define MICROPY_PORT_CONSTANTS { "dummy", 0 } //can't have zero-sized array