1 /* 2 * This file is part of the MicroPython project, http://micropython.org/ 3 * 4 * The MIT License (MIT) 5 * 6 * Copyright (c) 2013, 2014 Damien P. George 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in 16 * all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 * THE SOFTWARE. 25 */ 26 #ifndef MICROPY_INCLUDED_PY_NLR_H 27 #define MICROPY_INCLUDED_PY_NLR_H 28 29 // non-local return 30 // exception handling, basically a stack of setjmp/longjmp buffers 31 32 #include <limits.h> 33 #include <assert.h> 34 35 #include "py/mpconfig.h" 36 37 #define MICROPY_NLR_NUM_REGS_X86 (6) 38 #define MICROPY_NLR_NUM_REGS_X64 (8) 39 #define MICROPY_NLR_NUM_REGS_X64_WIN (10) 40 #define MICROPY_NLR_NUM_REGS_ARM_THUMB (10) 41 #define MICROPY_NLR_NUM_REGS_ARM_THUMB_FP (10 + 6) 42 #define MICROPY_NLR_NUM_REGS_AARCH64 (13) 43 #define MICROPY_NLR_NUM_REGS_XTENSA (10) 44 #define MICROPY_NLR_NUM_REGS_XTENSAWIN (17) 45 46 // *FORMAT-OFF* 47 48 // If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch 49 #if !MICROPY_NLR_SETJMP 50 // A lot of nlr-related things need different treatment on Windows 51 #if defined(_WIN32) || defined(__CYGWIN__) 52 #define MICROPY_NLR_OS_WINDOWS 1 53 #else 54 #define MICROPY_NLR_OS_WINDOWS 0 55 #endif 56 #if defined(__i386__) 57 #define MICROPY_NLR_X86 (1) 58 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X86) 59 #elif defined(__x86_64__) 60 #define MICROPY_NLR_X64 (1) 61 #if MICROPY_NLR_OS_WINDOWS 62 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64_WIN) 63 #else 64 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64) 65 #endif 66 #elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__) 67 #define MICROPY_NLR_THUMB (1) 68 #if defined(__SOFTFP__) 69 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB) 70 #else 71 // With hardware FP registers s16-s31 are callee save so in principle 72 // should be saved and restored by the NLR code. gcc only uses s16-s21 73 // so only save/restore those as an optimisation. 74 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB_FP) 75 #endif 76 #elif defined(__aarch64__) 77 #define MICROPY_NLR_AARCH64 (1) 78 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_AARCH64) 79 #elif defined(__xtensa__) 80 #define MICROPY_NLR_XTENSA (1) 81 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_XTENSA) 82 #elif defined(__powerpc__) 83 #define MICROPY_NLR_POWERPC (1) 84 // this could be less but using 128 for safety 85 #define MICROPY_NLR_NUM_REGS (128) 86 #else 87 #define MICROPY_NLR_SETJMP (1) 88 //#warning "No native NLR support for this arch, using setjmp implementation" 89 #endif 90 #endif 91 92 // *FORMAT-ON* 93 94 #if MICROPY_NLR_SETJMP 95 #include <setjmp.h> 96 #endif 97 98 typedef struct _nlr_buf_t nlr_buf_t; 99 struct _nlr_buf_t { 100 // the entries here must all be machine word size 101 nlr_buf_t *prev; 102 void *ret_val; // always a concrete object (an exception instance) 103 104 #if MICROPY_NLR_SETJMP 105 jmp_buf jmpbuf; 106 #else 107 void *regs[MICROPY_NLR_NUM_REGS]; 108 #endif 109 110 #if MICROPY_ENABLE_PYSTACK 111 void *pystack; 112 #endif 113 }; 114 115 // Helper macros to save/restore the pystack state 116 #if MICROPY_ENABLE_PYSTACK 117 #define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur) 118 #define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack 119 #else 120 #define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf 121 #define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf 122 #endif 123 124 // Helper macro to use at the start of a specific nlr_jump implementation 125 #define MP_NLR_JUMP_HEAD(val, top) \ 126 nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \ 127 nlr_buf_t *top = *_top_ptr; \ 128 if (top == NULL) { \ 129 nlr_jump_fail(val); \ 130 } \ 131 top->ret_val = val; \ 132 MP_NLR_RESTORE_PYSTACK(top); \ 133 *_top_ptr = top->prev; \ 134 135 #if MICROPY_NLR_SETJMP 136 // nlr_push() must be defined as a macro, because "The stack context will be 137 // invalidated if the function which called setjmp() returns." 138 // For this case it is safe to call nlr_push_tail() first. 139 #define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf)) 140 #else 141 unsigned int nlr_push(nlr_buf_t *); 142 #endif 143 144 unsigned int nlr_push_tail(nlr_buf_t *top); 145 void nlr_pop(void); 146 NORETURN void nlr_jump(void *val); 147 148 // This must be implemented by a port. It's called by nlr_jump 149 // if no nlr buf has been pushed. It must not return, but rather 150 // should bail out with a fatal error. 151 NORETURN void nlr_jump_fail(void *val); 152 153 // use nlr_raise instead of nlr_jump so that debugging is easier 154 #ifndef MICROPY_DEBUG_NLR 155 #define nlr_raise(val) nlr_jump(MP_OBJ_TO_PTR(val)) 156 #else 157 #include "mpstate.h" 158 #define nlr_raise(val) \ 159 do { \ 160 /*printf("nlr_raise: nlr_top=%p\n", MP_STATE_THREAD(nlr_top)); \ 161 fflush(stdout);*/ \ 162 void *_val = MP_OBJ_TO_PTR(val); \ 163 assert(_val != NULL); \ 164 assert(mp_obj_is_exception_instance(val)); \ 165 nlr_jump(_val); \ 166 } while (0) 167 168 #if !MICROPY_NLR_SETJMP 169 #define nlr_push(val) \ 170 assert(MP_STATE_THREAD(nlr_top) != val),nlr_push(val) 171 172 /* 173 #define nlr_push(val) \ 174 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) 175 */ 176 #endif 177 178 #endif 179 180 #endif // MICROPY_INCLUDED_PY_NLR_H 181