summaryrefslogtreecommitdiff
path: root/py/nlr.h
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-12-18 18:57:15 +1100
committerDamien George <damien.p.george@gmail.com>2017-12-20 15:42:06 +1100
commit6a3a742a6c9caaa2be0fd0aac7a5df4ac816081c (patch)
treecb91633e1592d474a5bc51db97f6442616d1cf63 /py/nlr.h
parentd8d633f15658911369d7b1b912777fa74efd3ea6 (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.h71
1 files changed, 34 insertions, 37 deletions
diff --git a/py/nlr.h b/py/nlr.h
index 1235f1460..012a73c31 100644
--- a/py/nlr.h
+++ b/py/nlr.h
@@ -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