diff options
| author | Damien George <damien.p.george@gmail.com> | 2017-12-18 18:57:15 +1100 |
|---|---|---|
| committer | Damien George <damien.p.george@gmail.com> | 2017-12-20 15:42:06 +1100 |
| commit | 6a3a742a6c9caaa2be0fd0aac7a5df4ac816081c (patch) | |
| tree | cb91633e1592d474a5bc51db97f6442616d1cf63 /py/nlr.h | |
| parent | d8d633f15658911369d7b1b912777fa74efd3ea6 (diff) | |
py/nlr: Factor out common NLR code to generic functions.
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. This eliminates duplicated code.
The factoring also allows to make the machine-specific NLR code pure
assembler code, thus allowing nlrthumb.c to use naked function attributes
in the correct way (naked functions can only have basic inline assembler
code in them).
There is a small overhead introduced (typically 1 machine instruction)
because now the generic nlr_jump() must call nlr_jump_tail() rather than
them being one combined function.
Diffstat (limited to 'py/nlr.h')
| -rw-r--r-- | py/nlr.h | 71 |
1 files changed, 34 insertions, 37 deletions
@@ -30,29 +30,29 @@ // exception handling, basically a stack of setjmp/longjmp buffers #include <limits.h> -#include <setjmp.h> #include <assert.h> #include "py/mpconfig.h" -typedef struct _nlr_buf_t nlr_buf_t; -struct _nlr_buf_t { - // the entries here must all be machine word size - nlr_buf_t *prev; - void *ret_val; // always a concrete object (an exception instance) -#if !defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP +// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch +// Allow a port to set MICROPY_NLR_NUM_REGS to define their own implementation +#if !MICROPY_NLR_SETJMP && !defined(MICROPY_NLR_NUM_REGS) #if defined(__i386__) - void *regs[6]; + #define MICROPY_NLR_X86 (1) + #define MICROPY_NLR_NUM_REGS (6) #elif defined(__x86_64__) - #if defined(__CYGWIN__) - void *regs[12]; - #else - void *regs[8]; - #endif + #define MICROPY_NLR_X64 (1) + #if defined(__CYGWIN__) + #define MICROPY_NLR_NUM_REGS (12) + #else + #define MICROPY_NLR_NUM_REGS (8) + #endif #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) - void *regs[10]; + #define MICROPY_NLR_THUMB (1) + #define MICROPY_NLR_NUM_REGS (10) #elif defined(__xtensa__) - void *regs[10]; + #define MICROPY_NLR_XTENSA (1) + #define MICROPY_NLR_NUM_REGS (10) #else #define MICROPY_NLR_SETJMP (1) //#warning "No native NLR support for this arch, using setjmp implementation" @@ -60,41 +60,39 @@ struct _nlr_buf_t { #endif #if MICROPY_NLR_SETJMP - jmp_buf jmpbuf; +#include <setjmp.h> #endif +typedef struct _nlr_buf_t nlr_buf_t; +struct _nlr_buf_t { + // the entries here must all be machine word size + nlr_buf_t *prev; + void *ret_val; // always a concrete object (an exception instance) + + #if MICROPY_NLR_SETJMP + jmp_buf jmpbuf; + #else + void *regs[MICROPY_NLR_NUM_REGS]; + #endif + #if MICROPY_ENABLE_PYSTACK void *pystack; #endif }; -// Helper macros to save/restore the pystack state -#if MICROPY_ENABLE_PYSTACK -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack -#else -#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf -#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf -#endif - #if MICROPY_NLR_SETJMP -#include "py/mpstate.h" - -NORETURN void nlr_setjmp_jump(void *val); // 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 +NORETURN void nlr_jump_tail(nlr_buf_t *top); // 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 @@ -123,7 +121,6 @@ NORETURN void nlr_jump_fail(void *val); /* #define nlr_push(val) \ printf("nlr_push: before: nlr_top=%p, val=%p\n", MP_STATE_THREAD(nlr_top), val),assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) -#endif */ #endif |
