From b25f92160b318a096c516c430afde5472a944c19 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 28 Dec 2017 16:46:30 +1100 Subject: [PATCH] py/nlr: Factor out common NLR code to macro and generic funcs in nlr.c. Each NLR implementation (Thumb, x86, x64, xtensa, setjmp) duplicates a lot of the NLR code, specifically that dealing with pushing and popping the NLR pointer to maintain the linked-list of NLR buffers. This patch factors all of that code out of the specific implementations into generic functions in nlr.c, along with a helper macro in nlr.h. This eliminates duplicated code. --- py/nlr.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ py/nlr.h | 27 +++++++++++++++----------- py/nlrsetjmp.c | 6 +++--- py/nlrthumb.c | 25 ++----------------------- py/nlrx64.c | 23 +---------------------- py/nlrx86.c | 23 +---------------------- py/nlrxtensa.c | 23 +---------------------- py/py.mk | 1 + 8 files changed, 76 insertions(+), 103 deletions(-) create mode 100644 py/nlr.c diff --git a/py/nlr.c b/py/nlr.c new file mode 100644 index 0000000000..52d56afb8a --- /dev/null +++ b/py/nlr.c @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2017 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mpstate.h" + +#if !MICROPY_NLR_SETJMP +// When not using setjmp, nlr_push_tail is called from inline asm so needs special c +#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__)) +// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading undersco +unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail"); +#else +// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as use +__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr); +#endif +#endif + +unsigned int nlr_push_tail(nlr_buf_t *nlr) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + nlr->prev = *top; + MP_NLR_SAVE_PYSTACK(nlr); + *top = nlr; + return 0; // normal return +} + +void nlr_pop(void) { + nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); + *top = (*top)->prev; +} diff --git a/py/nlr.h b/py/nlr.h index bd9fcc8847..e4dfa68963 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -88,24 +88,29 @@ struct _nlr_buf_t { #define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf #endif -#if MICROPY_NLR_SETJMP -#include "py/mpstate.h" +// Helper macro to use at the start of a specific nlr_jump implementation +#define MP_NLR_JUMP_HEAD(val, top) \ + nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \ + nlr_buf_t *top = *_top_ptr; \ + if (top == NULL) { \ + nlr_jump_fail(val); \ + } \ + top->ret_val = val; \ + MP_NLR_RESTORE_PYSTACK(top); \ + *_top_ptr = top->prev; \ -NORETURN void nlr_setjmp_jump(void *val); +#if MICROPY_NLR_SETJMP // nlr_push() must be defined as a macro, because "The stack context will be // invalidated if the function which called setjmp() returns." -#define nlr_push(buf) ( \ - (buf)->prev = MP_STATE_THREAD(nlr_top), \ - MP_NLR_SAVE_PYSTACK(buf), \ - MP_STATE_THREAD(nlr_top) = (buf), \ - setjmp((buf)->jmpbuf)) -#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; } -#define nlr_jump(val) nlr_setjmp_jump(val) +// For this case it is safe to call nlr_push_tail() first. +#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf)) #else unsigned int nlr_push(nlr_buf_t *); +#endif + +unsigned int nlr_push_tail(nlr_buf_t *top); void nlr_pop(void); NORETURN void nlr_jump(void *val); -#endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c index 63376a5537..960dd86f52 100644 --- a/py/nlrsetjmp.c +++ b/py/nlrsetjmp.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,11 +24,11 @@ * THE SOFTWARE. */ -#include "py/nlr.h" +#include "py/mpstate.h" #if MICROPY_NLR_SETJMP -void nlr_setjmp_jump(void *val) { +void nlr_jump(void *val) { nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); nlr_buf_t *top = *top_ptr; if (top == NULL) { diff --git a/py/nlrthumb.c b/py/nlrthumb.c index cc081e3ffb..fb0a92236f 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2013-2016 Damien P. George + * Copyright (c) 2013-2017 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -82,29 +82,8 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { #endif } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov r0, %0 \n" // r0 points to nlr_buf diff --git a/py/nlrx64.c b/py/nlrx64.c index 927b215912..663a457b70 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -88,29 +88,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "movq %0, %%rcx \n" // %rcx points to nlr_buf diff --git a/py/nlrx86.c b/py/nlrx86.c index 0e03eef6fe..9490c4f42c 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -70,29 +70,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov %0, %%edx \n" // %edx points to nlr_buf diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index 73f14385d0..cd3dee364c 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -55,29 +55,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - nlr->prev = *top; - MP_NLR_SAVE_PYSTACK(nlr); - *top = nlr; - return 0; // normal return -} - -void nlr_pop(void) { - nlr_buf_t **top = &MP_STATE_THREAD(nlr_top); - *top = (*top)->prev; -} - NORETURN void nlr_jump(void *val) { - nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top); - nlr_buf_t *top = *top_ptr; - if (top == NULL) { - nlr_jump_fail(val); - } - - top->ret_val = val; - MP_NLR_RESTORE_PYSTACK(top); - *top_ptr = top->prev; + MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "mov.n a2, %0 \n" // a2 points to nlr_buf diff --git a/py/py.mk b/py/py.mk index 0b5d5f8c40..de82a971bc 100644 --- a/py/py.mk +++ b/py/py.mk @@ -103,6 +103,7 @@ endif # py object files PY_O_BASENAME = \ mpstate.o \ + nlr.o \ nlrx86.o \ nlrx64.o \ nlrthumb.o \