summaryrefslogtreecommitdiff
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/nlr.c74
-rw-r--r--py/nlr.h71
-rw-r--r--py/nlrsetjmp.c10
-rw-r--r--py/nlrthumb.c38
-rw-r--r--py/nlrx64.c70
-rw-r--r--py/nlrx86.c63
-rw-r--r--py/nlrxtensa.c34
-rw-r--r--py/py.mk1
8 files changed, 157 insertions, 204 deletions
diff --git a/py/nlr.c b/py/nlr.c
new file mode 100644
index 000000000..e4d6d10c0
--- /dev/null
+++ b/py/nlr.c
@@ -0,0 +1,74 @@
+/*
+ * 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"
+
+// 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
+// When not using setjmp, nlr_push_tail is called from inline asm so needs special care
+#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__))
+// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading underscore
+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 used
+__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;
+}
+
+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;
+
+ nlr_jump_tail(top);
+}
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
diff --git a/py/nlrsetjmp.c b/py/nlrsetjmp.c
index 63376a553..6ddad3793 100644
--- a/py/nlrsetjmp.c
+++ b/py/nlrsetjmp.c
@@ -28,15 +28,7 @@
#if MICROPY_NLR_SETJMP
-void nlr_setjmp_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;
+NORETURN void nlr_jump_tail(nlr_buf_t *top) {
longjmp(top->jmpbuf, 1);
}
diff --git a/py/nlrthumb.c b/py/nlrthumb.c
index eab5759f2..4edd1456d 100644
--- a/py/nlrthumb.c
+++ b/py/nlrthumb.c
@@ -26,7 +26,7 @@
#include "py/mpstate.h"
-#if (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
+#if MICROPY_NLR_THUMB
#undef nlr_push
@@ -37,7 +37,6 @@
// r4-r11, r13=sp
__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
-
__asm volatile (
"str r4, [r0, #12] \n" // store r4 into nlr_buf
"str r5, [r0, #16] \n" // store r5 into nlr_buf
@@ -75,36 +74,10 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
"b nlr_push_tail \n" // do the rest in C
#endif
);
-
- 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 __attribute__((naked)) 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;
-
+NORETURN __attribute__((naked)) void nlr_jump_tail(nlr_buf_t *top) {
__asm volatile (
- "mov r0, %0 \n" // r0 points to nlr_buf
"ldr r4, [r0, #12] \n" // load r4 from nlr_buf
"ldr r5, [r0, #16] \n" // load r5 from nlr_buf
"ldr r6, [r0, #20] \n" // load r6 from nlr_buf
@@ -133,12 +106,7 @@ NORETURN __attribute__((naked)) void nlr_jump(void *val) {
#endif
"movs r0, #1 \n" // return 1, non-local return
"bx lr \n" // return
- : // output operands
- : "r"(top) // input operands
- : // clobbered registers
);
-
- for (;;); // needed to silence compiler warning
}
-#endif // (!defined(MICROPY_NLR_SETJMP) || !MICROPY_NLR_SETJMP) && (defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
+#endif // MICROPY_NLR_THUMB
diff --git a/py/nlrx64.c b/py/nlrx64.c
index ddcd76166..e7e2e1474 100644
--- a/py/nlrx64.c
+++ b/py/nlrx64.c
@@ -26,7 +26,7 @@
#include "py/mpstate.h"
-#if !MICROPY_NLR_SETJMP && defined(__x86_64__)
+#if MICROPY_NLR_X64
#undef nlr_push
@@ -39,8 +39,6 @@
#define NLR_OS_WINDOWS 0
#endif
-__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
-
unsigned int nlr_push(nlr_buf_t *nlr) {
(void)nlr;
@@ -88,54 +86,38 @@ 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;
+NORETURN void nlr_jump_tail(nlr_buf_t *top) {
+ (void)top;
__asm volatile (
- "movq %0, %%rcx \n" // %rcx points to nlr_buf
#if NLR_OS_WINDOWS
- "movq 88(%%rcx), %%rsi \n" // load saved %rsi
- "movq 80(%%rcx), %%rdi \n" // load saved %rdr
+ "movq 88(%rcx), %rsi \n" // load saved %rsi
+ "movq 80(%rcx), %rdi \n" // load saved %rdr
+ "movq 72(%rcx), %r15 \n" // load saved %r15
+ "movq 64(%rcx), %r14 \n" // load saved %r14
+ "movq 56(%rcx), %r13 \n" // load saved %r13
+ "movq 48(%rcx), %r12 \n" // load saved %r12
+ "movq 40(%rcx), %rbx \n" // load saved %rbx
+ "movq 32(%rcx), %rsp \n" // load saved %rsp
+ "movq 24(%rcx), %rbp \n" // load saved %rbp
+ "movq 16(%rcx), %rax \n" // load saved %rip
+ #else
+ "movq 72(%rdi), %r15 \n" // load saved %r15
+ "movq 64(%rdi), %r14 \n" // load saved %r14
+ "movq 56(%rdi), %r13 \n" // load saved %r13
+ "movq 48(%rdi), %r12 \n" // load saved %r12
+ "movq 40(%rdi), %rbx \n" // load saved %rbx
+ "movq 32(%rdi), %rsp \n" // load saved %rsp
+ "movq 24(%rdi), %rbp \n" // load saved %rbp
+ "movq 16(%rdi), %rax \n" // load saved %rip
#endif
- "movq 72(%%rcx), %%r15 \n" // load saved %r15
- "movq 64(%%rcx), %%r14 \n" // load saved %r14
- "movq 56(%%rcx), %%r13 \n" // load saved %r13
- "movq 48(%%rcx), %%r12 \n" // load saved %r12
- "movq 40(%%rcx), %%rbx \n" // load saved %rbx
- "movq 32(%%rcx), %%rsp \n" // load saved %rsp
- "movq 24(%%rcx), %%rbp \n" // load saved %rbp
- "movq 16(%%rcx), %%rax \n" // load saved %rip
- "movq %%rax, (%%rsp) \n" // store saved %rip to stack
- "xorq %%rax, %%rax \n" // clear return register
- "inc %%al \n" // increase to make 1, non-local return
+ "movq %rax, (%rsp) \n" // store saved %rip to stack
+ "xorq %rax, %rax \n" // clear return register
+ "inc %al \n" // increase to make 1, non-local return
"ret \n" // return
- : // output operands
- : "r"(top) // input operands
- : // clobbered registers
);
for (;;); // needed to silence compiler warning
}
-#endif // !MICROPY_NLR_SETJMP && defined(__x86_64__)
+#endif // MICROPY_NLR_X64
diff --git a/py/nlrx86.c b/py/nlrx86.c
index 3a27460eb..cc37f72af 100644
--- a/py/nlrx86.c
+++ b/py/nlrx86.c
@@ -26,25 +26,13 @@
#include "py/mpstate.h"
-#if !MICROPY_NLR_SETJMP && defined(__i386__)
+#if MICROPY_NLR_X86
#undef nlr_push
// For reference, x86 callee save regs are:
// ebx, esi, edi, ebp, esp, eip
-#if defined(_WIN32) || defined(__CYGWIN__)
-#define NLR_OS_WINDOWS 1
-#else
-#define NLR_OS_WINDOWS 0
-#endif
-
-#if NLR_OS_WINDOWS
-unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail");
-#else
-__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
-#endif
-
unsigned int nlr_push(nlr_buf_t *nlr) {
(void)nlr;
@@ -70,48 +58,23 @@ 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;
+NORETURN void nlr_jump_tail(nlr_buf_t *top) {
+ (void)top;
__asm volatile (
- "mov %0, %%edx \n" // %edx points to nlr_buf
- "mov 28(%%edx), %%esi \n" // load saved %esi
- "mov 24(%%edx), %%edi \n" // load saved %edi
- "mov 20(%%edx), %%ebx \n" // load saved %ebx
- "mov 16(%%edx), %%esp \n" // load saved %esp
- "mov 12(%%edx), %%ebp \n" // load saved %ebp
- "mov 8(%%edx), %%eax \n" // load saved %eip
- "mov %%eax, (%%esp) \n" // store saved %eip to stack
- "xor %%eax, %%eax \n" // clear return register
- "inc %%al \n" // increase to make 1, non-local return
+ "mov 28(%edx), %esi \n" // load saved %esi
+ "mov 24(%edx), %edi \n" // load saved %edi
+ "mov 20(%edx), %ebx \n" // load saved %ebx
+ "mov 16(%edx), %esp \n" // load saved %esp
+ "mov 12(%edx), %ebp \n" // load saved %ebp
+ "mov 8(%edx), %eax \n" // load saved %eip
+ "mov %eax, (%esp) \n" // store saved %eip to stack
+ "xor %eax, %eax \n" // clear return register
+ "inc %al \n" // increase to make 1, non-local return
"ret \n" // return
- : // output operands
- : "r"(top) // input operands
- : // clobbered registers
);
for (;;); // needed to silence compiler warning
}
-#endif // !MICROPY_NLR_SETJMP && defined(__i386__)
+#endif // MICROPY_NLR_X86
diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c
index 5a969fc87..6b9918227 100644
--- a/py/nlrxtensa.c
+++ b/py/nlrxtensa.c
@@ -26,7 +26,7 @@
#include "py/mpstate.h"
-#if !MICROPY_NLR_SETJMP && defined(__xtensa__)
+#if MICROPY_NLR_XTENSA
#undef nlr_push
@@ -37,6 +37,7 @@
// a3-a7 = rest of args
unsigned int nlr_push(nlr_buf_t *nlr) {
+ (void)nlr;
__asm volatile (
"s32i.n a0, a2, 8 \n" // save regs...
@@ -55,32 +56,10 @@ 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;
+NORETURN void nlr_jump_tail(nlr_buf_t *top) {
+ (void)top;
__asm volatile (
- "mov.n a2, %0 \n" // a2 points to nlr_buf
"l32i.n a0, a2, 8 \n" // restore regs...
"l32i.n a1, a2, 12 \n"
"l32i.n a8, a2, 16 \n"
@@ -93,12 +72,9 @@ NORETURN void nlr_jump(void *val) {
"l32i.n a15, a2, 44 \n"
"movi.n a2, 1 \n" // return 1, non-local return
"ret.n \n" // return
- : // output operands
- : "r"(top) // input operands
- : // clobbered registers
);
for (;;); // needed to silence compiler warning
}
-#endif // !MICROPY_NLR_SETJMP && defined(__xtensa__)
+#endif // MICROPY_NLR_XTENSA
diff --git a/py/py.mk b/py/py.mk
index 0b5d5f8c4..de82a971b 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 \