Skip to content

Commit b25f921

Browse files
committed
py/nlr: Factor out common NLR code to macro and generic funcs in nlr.c.
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, along with a helper macro in nlr.h. This eliminates duplicated code.
1 parent 5bf8e85 commit b25f921

8 files changed

Lines changed: 76 additions & 103 deletions

File tree

py/nlr.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2013-2017 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+
27+
#include "py/mpstate.h"
28+
29+
#if !MICROPY_NLR_SETJMP
30+
// When not using setjmp, nlr_push_tail is called from inline asm so needs special c
31+
#if MICROPY_NLR_X86 && (defined(_WIN32) || defined(__CYGWIN__))
32+
// On these 32-bit platforms make sure nlr_push_tail doesn't have a leading undersco
33+
unsigned int nlr_push_tail(nlr_buf_t *nlr) asm("nlr_push_tail");
34+
#else
35+
// LTO can't see inside inline asm functions so explicitly mark nlr_push_tail as use
36+
__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr);
37+
#endif
38+
#endif
39+
40+
unsigned int nlr_push_tail(nlr_buf_t *nlr) {
41+
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
42+
nlr->prev = *top;
43+
MP_NLR_SAVE_PYSTACK(nlr);
44+
*top = nlr;
45+
return 0; // normal return
46+
}
47+
48+
void nlr_pop(void) {
49+
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
50+
*top = (*top)->prev;
51+
}

py/nlr.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,24 +88,29 @@ struct _nlr_buf_t {
8888
#define MP_NLR_RESTORE_PYSTACK(nlr_buf) (void)nlr_buf
8989
#endif
9090

91-
#if MICROPY_NLR_SETJMP
92-
#include "py/mpstate.h"
91+
// Helper macro to use at the start of a specific nlr_jump implementation
92+
#define MP_NLR_JUMP_HEAD(val, top) \
93+
nlr_buf_t **_top_ptr = &MP_STATE_THREAD(nlr_top); \
94+
nlr_buf_t *top = *_top_ptr; \
95+
if (top == NULL) { \
96+
nlr_jump_fail(val); \
97+
} \
98+
top->ret_val = val; \
99+
MP_NLR_RESTORE_PYSTACK(top); \
100+
*_top_ptr = top->prev; \
93101

94-
NORETURN void nlr_setjmp_jump(void *val);
102+
#if MICROPY_NLR_SETJMP
95103
// nlr_push() must be defined as a macro, because "The stack context will be
96104
// invalidated if the function which called setjmp() returns."
97-
#define nlr_push(buf) ( \
98-
(buf)->prev = MP_STATE_THREAD(nlr_top), \
99-
MP_NLR_SAVE_PYSTACK(buf), \
100-
MP_STATE_THREAD(nlr_top) = (buf), \
101-
setjmp((buf)->jmpbuf))
102-
#define nlr_pop() { MP_STATE_THREAD(nlr_top) = MP_STATE_THREAD(nlr_top)->prev; }
103-
#define nlr_jump(val) nlr_setjmp_jump(val)
105+
// For this case it is safe to call nlr_push_tail() first.
106+
#define nlr_push(buf) (nlr_push_tail(buf), setjmp((buf)->jmpbuf))
104107
#else
105108
unsigned int nlr_push(nlr_buf_t *);
109+
#endif
110+
111+
unsigned int nlr_push_tail(nlr_buf_t *top);
106112
void nlr_pop(void);
107113
NORETURN void nlr_jump(void *val);
108-
#endif
109114

110115
// This must be implemented by a port. It's called by nlr_jump
111116
// if no nlr buf has been pushed. It must not return, but rather

py/nlrsetjmp.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* The MIT License (MIT)
55
*
6-
* Copyright (c) 2013, 2014 Damien P. George
6+
* Copyright (c) 2013-2017 Damien P. George
77
*
88
* Permission is hereby granted, free of charge, to any person obtaining a copy
99
* of this software and associated documentation files (the "Software"), to deal
@@ -24,11 +24,11 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
#include "py/nlr.h"
27+
#include "py/mpstate.h"
2828

2929
#if MICROPY_NLR_SETJMP
3030

31-
void nlr_setjmp_jump(void *val) {
31+
void nlr_jump(void *val) {
3232
nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
3333
nlr_buf_t *top = *top_ptr;
3434
if (top == NULL) {

py/nlrthumb.c

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* The MIT License (MIT)
55
*
6-
* Copyright (c) 2013-2016 Damien P. George
6+
* Copyright (c) 2013-2017 Damien P. George
77
*
88
* Permission is hereby granted, free of charge, to any person obtaining a copy
99
* of this software and associated documentation files (the "Software"), to deal
@@ -82,29 +82,8 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
8282
#endif
8383
}
8484

85-
__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
86-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
87-
nlr->prev = *top;
88-
MP_NLR_SAVE_PYSTACK(nlr);
89-
*top = nlr;
90-
return 0; // normal return
91-
}
92-
93-
void nlr_pop(void) {
94-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
95-
*top = (*top)->prev;
96-
}
97-
9885
NORETURN void nlr_jump(void *val) {
99-
nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
100-
nlr_buf_t *top = *top_ptr;
101-
if (top == NULL) {
102-
nlr_jump_fail(val);
103-
}
104-
105-
top->ret_val = val;
106-
MP_NLR_RESTORE_PYSTACK(top);
107-
*top_ptr = top->prev;
86+
MP_NLR_JUMP_HEAD(val, top)
10887

10988
__asm volatile (
11089
"mov r0, %0 \n" // r0 points to nlr_buf

py/nlrx64.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,29 +88,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
8888
return 0; // needed to silence compiler warning
8989
}
9090

91-
__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
92-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
93-
nlr->prev = *top;
94-
MP_NLR_SAVE_PYSTACK(nlr);
95-
*top = nlr;
96-
return 0; // normal return
97-
}
98-
99-
void nlr_pop(void) {
100-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
101-
*top = (*top)->prev;
102-
}
103-
10491
NORETURN void nlr_jump(void *val) {
105-
nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
106-
nlr_buf_t *top = *top_ptr;
107-
if (top == NULL) {
108-
nlr_jump_fail(val);
109-
}
110-
111-
top->ret_val = val;
112-
MP_NLR_RESTORE_PYSTACK(top);
113-
*top_ptr = top->prev;
92+
MP_NLR_JUMP_HEAD(val, top)
11493

11594
__asm volatile (
11695
"movq %0, %%rcx \n" // %rcx points to nlr_buf

py/nlrx86.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,29 +70,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
7070
return 0; // needed to silence compiler warning
7171
}
7272

73-
__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
74-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
75-
nlr->prev = *top;
76-
MP_NLR_SAVE_PYSTACK(nlr);
77-
*top = nlr;
78-
return 0; // normal return
79-
}
80-
81-
void nlr_pop(void) {
82-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
83-
*top = (*top)->prev;
84-
}
85-
8673
NORETURN void nlr_jump(void *val) {
87-
nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
88-
nlr_buf_t *top = *top_ptr;
89-
if (top == NULL) {
90-
nlr_jump_fail(val);
91-
}
92-
93-
top->ret_val = val;
94-
MP_NLR_RESTORE_PYSTACK(top);
95-
*top_ptr = top->prev;
74+
MP_NLR_JUMP_HEAD(val, top)
9675

9776
__asm volatile (
9877
"mov %0, %%edx \n" // %edx points to nlr_buf

py/nlrxtensa.c

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,29 +55,8 @@ unsigned int nlr_push(nlr_buf_t *nlr) {
5555
return 0; // needed to silence compiler warning
5656
}
5757

58-
__attribute__((used)) unsigned int nlr_push_tail(nlr_buf_t *nlr) {
59-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
60-
nlr->prev = *top;
61-
MP_NLR_SAVE_PYSTACK(nlr);
62-
*top = nlr;
63-
return 0; // normal return
64-
}
65-
66-
void nlr_pop(void) {
67-
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
68-
*top = (*top)->prev;
69-
}
70-
7158
NORETURN void nlr_jump(void *val) {
72-
nlr_buf_t **top_ptr = &MP_STATE_THREAD(nlr_top);
73-
nlr_buf_t *top = *top_ptr;
74-
if (top == NULL) {
75-
nlr_jump_fail(val);
76-
}
77-
78-
top->ret_val = val;
79-
MP_NLR_RESTORE_PYSTACK(top);
80-
*top_ptr = top->prev;
59+
MP_NLR_JUMP_HEAD(val, top)
8160

8261
__asm volatile (
8362
"mov.n a2, %0 \n" // a2 points to nlr_buf

py/py.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ endif
103103
# py object files
104104
PY_O_BASENAME = \
105105
mpstate.o \
106+
nlr.o \
106107
nlrx86.o \
107108
nlrx64.o \
108109
nlrthumb.o \

0 commit comments

Comments
 (0)