blob: 62972dba62713424ba96439ccba0ae5b1c250fae [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
Alexander Steffen55f33242017-06-30 09:22:17 +02002 * This file is part of the MicroPython project, http://micropython.org/
Damien George04b91472014-05-03 23:27:38 +01003 *
4 * The MIT License (MIT)
5 *
Damien George2757acf2023-05-09 11:03:04 +10006 * Copyright (c) 2013-2023 Damien P. George
Damien George04b91472014-05-03 23:27:38 +01007 *
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 */
Alexander Steffen299bc622017-06-29 23:14:58 +020026#ifndef MICROPY_INCLUDED_PY_NLR_H
27#define MICROPY_INCLUDED_PY_NLR_H
Damien George04b91472014-05-03 23:27:38 +010028
Damience89a212013-10-15 22:25:17 +010029// non-local return
30// exception handling, basically a stack of setjmp/longjmp buffers
31
32#include <limits.h>
Emmanuel Blotbf3366a2014-06-19 18:47:38 +020033#include <assert.h>
Damien George2757acf2023-05-09 11:03:04 +100034#include <stdbool.h>
Damience89a212013-10-15 22:25:17 +010035
Damien George51dfcb42015-01-01 20:27:54 +000036#include "py/mpconfig.h"
37
Damien Georgea48cdb52019-09-18 13:39:01 +100038#define MICROPY_NLR_NUM_REGS_X86 (6)
39#define MICROPY_NLR_NUM_REGS_X64 (8)
40#define MICROPY_NLR_NUM_REGS_X64_WIN (10)
41#define MICROPY_NLR_NUM_REGS_ARM_THUMB (10)
42#define MICROPY_NLR_NUM_REGS_ARM_THUMB_FP (10 + 6)
Yonatan Goldschmidt2d5cece2021-02-18 01:28:42 +020043#define MICROPY_NLR_NUM_REGS_AARCH64 (13)
Jan Willeke40a3aa72022-01-07 21:57:20 +010044#define MICROPY_NLR_NUM_REGS_MIPS (13)
Damien Georgea48cdb52019-09-18 13:39:01 +100045#define MICROPY_NLR_NUM_REGS_XTENSA (10)
Damien George9adedce2019-09-13 13:15:12 +100046#define MICROPY_NLR_NUM_REGS_XTENSAWIN (17)
Damien Georgea48cdb52019-09-18 13:39:01 +100047
Damien George3f39d182020-02-26 11:58:42 +110048// *FORMAT-OFF*
49
Damien George5bf8e852017-12-28 16:18:39 +110050// If MICROPY_NLR_SETJMP is not enabled then auto-detect the machine arch
51#if !MICROPY_NLR_SETJMP
stijnb184b6a2017-12-26 10:52:09 +010052// A lot of nlr-related things need different treatment on Windows
53#if defined(_WIN32) || defined(__CYGWIN__)
54#define MICROPY_NLR_OS_WINDOWS 1
55#else
56#define MICROPY_NLR_OS_WINDOWS 0
57#endif
Paul Sokolovsky82a165d2014-02-27 18:01:43 +020058#if defined(__i386__)
Damien George5bf8e852017-12-28 16:18:39 +110059 #define MICROPY_NLR_X86 (1)
Damien Georgea48cdb52019-09-18 13:39:01 +100060 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X86)
Paul Sokolovsky82a165d2014-02-27 18:01:43 +020061#elif defined(__x86_64__)
Damien George5bf8e852017-12-28 16:18:39 +110062 #define MICROPY_NLR_X64 (1)
stijnb184b6a2017-12-26 10:52:09 +010063 #if MICROPY_NLR_OS_WINDOWS
Damien Georgea48cdb52019-09-18 13:39:01 +100064 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64_WIN)
Damien George5bf8e852017-12-28 16:18:39 +110065 #else
Damien Georgea48cdb52019-09-18 13:39:01 +100066 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_X64)
Damien George5bf8e852017-12-28 16:18:39 +110067 #endif
Paul Sokolovskya96cc822014-06-22 01:14:28 +030068#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
Damien George5bf8e852017-12-28 16:18:39 +110069 #define MICROPY_NLR_THUMB (1)
Damien George34c04d22019-06-17 23:19:34 +100070 #if defined(__SOFTFP__)
Damien Georgea48cdb52019-09-18 13:39:01 +100071 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB)
Damien George34c04d22019-06-17 23:19:34 +100072 #else
73 // With hardware FP registers s16-s31 are callee save so in principle
74 // should be saved and restored by the NLR code. gcc only uses s16-s21
75 // so only save/restore those as an optimisation.
Damien Georgea48cdb52019-09-18 13:39:01 +100076 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_ARM_THUMB_FP)
Damien George34c04d22019-06-17 23:19:34 +100077 #endif
Yonatan Goldschmidt2d5cece2021-02-18 01:28:42 +020078#elif defined(__aarch64__)
79 #define MICROPY_NLR_AARCH64 (1)
80 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_AARCH64)
Damien George2399aa02014-11-27 20:29:33 +000081#elif defined(__xtensa__)
Damien George5bf8e852017-12-28 16:18:39 +110082 #define MICROPY_NLR_XTENSA (1)
Damien Georgea48cdb52019-09-18 13:39:01 +100083 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_XTENSA)
Michael Neuling079cc942019-08-22 10:21:48 +100084#elif defined(__powerpc__)
85 #define MICROPY_NLR_POWERPC (1)
86 // this could be less but using 128 for safety
87 #define MICROPY_NLR_NUM_REGS (128)
Jan Willeke40a3aa72022-01-07 21:57:20 +010088#elif defined(__mips__)
89 #define MICROPY_NLR_MIPS (1)
90 #define MICROPY_NLR_NUM_REGS (MICROPY_NLR_NUM_REGS_MIPS)
Paul Sokolovsky82a165d2014-02-27 18:01:43 +020091#else
Paul Sokolovsky3a83b802014-04-17 00:16:45 +030092 #define MICROPY_NLR_SETJMP (1)
Paul Sokolovsky851c8562014-04-30 04:14:31 +030093 //#warning "No native NLR support for this arch, using setjmp implementation"
Paul Sokolovsky3a83b802014-04-17 00:16:45 +030094#endif
95#endif
96
Damien George3f39d182020-02-26 11:58:42 +110097// *FORMAT-ON*
98
Paul Sokolovsky3a83b802014-04-17 00:16:45 +030099#if MICROPY_NLR_SETJMP
Damien George5bf8e852017-12-28 16:18:39 +1100100#include <setjmp.h>
Paul Sokolovsky096e9672017-12-26 18:39:51 +0200101#endif
Damien George6a3a7422017-12-18 18:57:15 +1100102
Damien George5bf8e852017-12-28 16:18:39 +1100103typedef struct _nlr_buf_t nlr_buf_t;
104struct _nlr_buf_t {
Damien Georged54208a2022-12-16 17:31:21 +1100105 // The entries in this struct must all be machine word size.
106
107 // Pointer to the previous nlr_buf_t in the chain.
108 // Or NULL if it's the top-level one.
Damien George5bf8e852017-12-28 16:18:39 +1100109 nlr_buf_t *prev;
Damien Georged54208a2022-12-16 17:31:21 +1100110
111 // The exception that is being raised:
112 // - NULL means the jump is because of a VM abort (only if MICROPY_ENABLE_VM_ABORT enabled)
113 // - otherwise it's always a concrete object (an exception instance)
114 void *ret_val;
Damien George5bf8e852017-12-28 16:18:39 +1100115
116 #if MICROPY_NLR_SETJMP
117 jmp_buf jmpbuf;
118 #else
119 void *regs[MICROPY_NLR_NUM_REGS];
120 #endif
121
Damien George02d830c2017-11-26 23:28:40 +1100122 #if MICROPY_ENABLE_PYSTACK
123 void *pystack;
124 #endif
Damience89a212013-10-15 22:25:17 +0100125};
126
Damien George2757acf2023-05-09 11:03:04 +1000127typedef void (*nlr_jump_callback_fun_t)(void *ctx);
128
129typedef struct _nlr_jump_callback_node_t nlr_jump_callback_node_t;
130
131struct _nlr_jump_callback_node_t {
132 nlr_jump_callback_node_t *prev;
133 nlr_jump_callback_fun_t fun;
134};
135
Paul Sokolovsky096e9672017-12-26 18:39:51 +0200136// Helper macros to save/restore the pystack state
137#if MICROPY_ENABLE_PYSTACK
138#define MP_NLR_SAVE_PYSTACK(nlr_buf) (nlr_buf)->pystack = MP_STATE_THREAD(pystack_cur)
139#define MP_NLR_RESTORE_PYSTACK(nlr_buf) MP_STATE_THREAD(pystack_cur) = (nlr_buf)->pystack
Paul Sokolovsky3a83b802014-04-17 00:16:45 +0300140#else
Paul Sokolovsky096e9672017-12-26 18:39:51 +0200141#define MP_NLR_SAVE_PYSTACK(nlr_buf) (void)nlr_buf
142#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf
Damien George6a3a7422017-12-18 18:57:15 +1100143#endif
144
Damien Georgeb25f9212017-12-28 16:46:30 +1100145// Helper macro to use at the start of a specific nlr_jump implementation
146#define MP_NLR_JUMP_HEAD(val, top) \
147 nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \
148 nlr_buf_t *top = *_top_ptr; \
149 if (top == NULL) { \
150 nlr_jump_fail(val); \
151 } \
152 top->ret_val = val; \
Damien George2757acf2023-05-09 11:03:04 +1000153 nlr_call_jump_callbacks(top); \
Damien Georgeb25f9212017-12-28 16:46:30 +1100154 MP_NLR_RESTORE_PYSTACK(top); \
155 *_top_ptr = top->prev; \
Paul Sokolovsky096e9672017-12-26 18:39:51 +0200156
Damien Georgeb25f9212017-12-28 16:46:30 +1100157#if MICROPY_NLR_SETJMP
Paul Sokolovsky096e9672017-12-26 18:39:51 +0200158// nlr_push() must be defined as a macro, because "The stack context will be
159// invalidated if the function which called setjmp() returns."
Damien Georgeb25f9212017-12-28 16:46:30 +1100160// For this case it is safe to call nlr_push_tail() first.
161#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf))
Paul Sokolovsky096e9672017-12-26 18:39:51 +0200162#else
163unsigned int nlr_push(nlr_buf_t *);
Damien Georgeb25f9212017-12-28 16:46:30 +1100164#endif
165
166unsigned int nlr_push_tail(nlr_buf_t *top);
Damien8b3a7c22013-10-23 20:20:17 +0100167void nlr_pop(void);
Paul Sokolovskye9085912014-04-30 05:35:18 +0300168NORETURN void nlr_jump(void *val);
Damien Georgeea13f402014-04-05 18:32:08 +0100169
Damien Georged54208a2022-12-16 17:31:21 +1100170#if MICROPY_ENABLE_VM_ABORT
171#define nlr_set_abort(buf) MP_STATE_VM(nlr_abort) = buf
172#define nlr_get_abort() MP_STATE_VM(nlr_abort)
173NORETURN void nlr_jump_abort(void);
174#endif
175
Damien George26cf55a2014-04-08 14:08:14 +0000176// This must be implemented by a port. It's called by nlr_jump
177// if no nlr buf has been pushed. It must not return, but rather
178// should bail out with a fatal error.
Damien Georgebe3d7f92017-02-16 17:23:06 +1100179NORETURN void nlr_jump_fail(void *val);
Damien George26cf55a2014-04-08 14:08:14 +0000180
Damien Georgeea13f402014-04-05 18:32:08 +0100181// use nlr_raise instead of nlr_jump so that debugging is easier
stijn2f0ce2a2017-04-26 13:17:55 +0200182#ifndef MICROPY_DEBUG_NLR
Damien George999cedb2015-11-27 17:01:44 +0000183#define nlr_raise(val) nlr_jump(MP_OBJ_TO_PTR(val))
Damien Georgeea13f402014-04-05 18:32:08 +0100184#else
Damien Georgef36ae5e2023-06-02 17:52:40 +1000185
Damien Georgeea13f402014-04-05 18:32:08 +0100186#define nlr_raise(val) \
187 do { \
Damien George999cedb2015-11-27 17:01:44 +0000188 void *_val = MP_OBJ_TO_PTR(val); \
Damien Georgeea13f402014-04-05 18:32:08 +0100189 assert(_val != NULL); \
Damien George999cedb2015-11-27 17:01:44 +0000190 assert(mp_obj_is_exception_instance(val)); \
Damien Georgeea13f402014-04-05 18:32:08 +0100191 nlr_jump(_val); \
192 } while (0)
Paul Sokolovskye89cc132015-02-15 20:23:52 +0300193
stijn803264b2015-03-03 11:15:06 +0100194#if !MICROPY_NLR_SETJMP
Paul Sokolovskye89cc132015-02-15 20:23:52 +0300195#define nlr_push(val) \
Damien George5b700b02022-05-05 13:28:32 +1000196 assert(MP_STATE_THREAD(nlr_top) != val), nlr_push(val)
stijn803264b2015-03-03 11:15:06 +0100197#endif
Paul Sokolovsky3077fbf2015-02-15 20:28:18 +0300198
Damien Georgeea13f402014-04-05 18:32:08 +0100199#endif
Damien George51dfcb42015-01-01 20:27:54 +0000200
Damien George2757acf2023-05-09 11:03:04 +1000201// Push a callback on to the linked-list of NLR jump callbacks. The `node` pointer must
202// be on the C stack. The `fun` callback will be executed if an NLR jump is taken which
203// unwinds the C stack through this `node`.
204void nlr_push_jump_callback(nlr_jump_callback_node_t *node, nlr_jump_callback_fun_t fun);
205
206// Pop a callback from the linked-list of NLR jump callbacks. The corresponding function
207// will be called if `run_callback` is true.
208void nlr_pop_jump_callback(bool run_callback);
209
210// Pop and call all NLR jump callbacks that were registered after `nlr` buffer was pushed.
211void nlr_call_jump_callbacks(nlr_buf_t *nlr);
212
Alexander Steffen299bc622017-06-29 23:14:58 +0200213#endif // MICROPY_INCLUDED_PY_NLR_H