summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/embedding/mpconfigport_minimal.h11
-rw-r--r--lib/utils/gchelper.h18
-rw-r--r--lib/utils/gchelper_generic.c156
-rw-r--r--lib/utils/gchelper_m3.s12
-rw-r--r--lib/utils/gchelper_native.c47
-rw-r--r--mpy-cross/Makefile1
-rw-r--r--mpy-cross/gccollect.c113
-rw-r--r--mpy-cross/mpconfigport.h11
-rw-r--r--mpy-cross/mpy-cross.vcxproj3
-rw-r--r--ports/cc3200/application.mk2
-rw-r--r--ports/cc3200/mptask.c4
-rw-r--r--ports/cc3200/util/cortex_m3_get_sp.s43
-rw-r--r--ports/cc3200/util/gccollect.c8
-rw-r--r--ports/mimxrt/Makefile1
-rw-r--r--ports/mimxrt/main.c4
-rw-r--r--ports/qemu-arm/Makefile1
-rw-r--r--ports/qemu-arm/test_main.c9
-rw-r--r--ports/samd/Makefile1
-rw-r--r--ports/samd/main.c4
-rw-r--r--ports/stm32/Makefile1
-rw-r--r--ports/stm32/gccollect.c8
-rw-r--r--ports/teensy/Makefile1
-rw-r--r--ports/unix/Makefile1
-rw-r--r--ports/unix/gccollect.c137
-rw-r--r--ports/unix/mpconfigport.h11
-rw-r--r--ports/unix/mpthreadport.c5
-rw-r--r--ports/unix/variants/minimal/mpconfigvariant.h11
-rw-r--r--ports/windows/Makefile1
-rw-r--r--ports/windows/micropython.vcxproj1
29 files changed, 307 insertions, 319 deletions
diff --git a/examples/embedding/mpconfigport_minimal.h b/examples/embedding/mpconfigport_minimal.h
index fa52be4ad..1050d947d 100644
--- a/examples/embedding/mpconfigport_minimal.h
+++ b/examples/embedding/mpconfigport_minimal.h
@@ -97,14 +97,9 @@ extern const struct _mp_obj_module_t mp_module_os;
// Do not change anything beyond this line
//////////////////////////////////////////
-// Define to 1 to use undertested inefficient GC helper implementation
-// (if more efficient arch-specific one is not available).
-#ifndef MICROPY_GCREGS_SETJMP
- #ifdef __mips__
- #define MICROPY_GCREGS_SETJMP (1)
- #else
- #define MICROPY_GCREGS_SETJMP (0)
- #endif
+#if !defined(__x86_64__) || !defined(__i386__) || !defined(__thumb2__) || !defined(__thumb__) || !defined(__arm__)
+// Fall back to setjmp() implementation for discovery of GC pointers in registers.
+#define MICROPY_GCREGS_SETJMP (1)
#endif
// type definitions for the specific machine
diff --git a/lib/utils/gchelper.h b/lib/utils/gchelper.h
index 7149b6a72..4b6ead6ba 100644
--- a/lib/utils/gchelper.h
+++ b/lib/utils/gchelper.h
@@ -28,7 +28,21 @@
#include <stdint.h>
-uintptr_t gc_helper_get_sp(void);
-uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs);
+#if MICROPY_GCREGS_SETJMP
+#include <setjmp.h>
+typedef jmp_buf gc_helper_regs_t;
+#else
+
+#if defined(__x86_64__)
+typedef uintptr_t gc_helper_regs_t[6];
+#elif defined(__i386__)
+typedef uintptr_t gc_helper_regs_t[4];
+#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
+typedef uintptr_t gc_helper_regs_t[10];
+#endif
+
+#endif
+
+void gc_helper_collect_regs_and_stack(void);
#endif // MICROPY_INCLUDED_LIB_UTILS_GCHELPER_H
diff --git a/lib/utils/gchelper_generic.c b/lib/utils/gchelper_generic.c
new file mode 100644
index 000000000..9750e8b0c
--- /dev/null
+++ b/lib/utils/gchelper_generic.c
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 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 <stdio.h>
+
+#include "py/mpstate.h"
+#include "py/gc.h"
+#include "lib/utils/gchelper.h"
+
+#if MICROPY_ENABLE_GC
+
+// Even if we have specific support for an architecture, it is
+// possible to force use of setjmp-based implementation.
+#if !MICROPY_GCREGS_SETJMP
+
+// We capture here callee-save registers, i.e. ones which may contain
+// interesting values held there by our callers. It doesn't make sense
+// to capture caller-saved registers, because they, well, put on the
+// stack already by the caller.
+#if defined(__x86_64__)
+
+STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
+ register long rbx asm ("rbx");
+ register long rbp asm ("rbp");
+ register long r12 asm ("r12");
+ register long r13 asm ("r13");
+ register long r14 asm ("r14");
+ register long r15 asm ("r15");
+ #ifdef __clang__
+ // TODO:
+ // This is dirty workaround for Clang. It tries to get around
+ // uncompliant (wrt to GCC) behavior of handling register variables.
+ // Application of this patch here is random, and done only to unbreak
+ // MacOS build. Better, cross-arch ways to deal with Clang issues should
+ // be found.
+ asm ("" : "=r" (rbx));
+ asm ("" : "=r" (rbp));
+ asm ("" : "=r" (r12));
+ asm ("" : "=r" (r13));
+ asm ("" : "=r" (r14));
+ asm ("" : "=r" (r15));
+ #endif
+ arr[0] = rbx;
+ arr[1] = rbp;
+ arr[2] = r12;
+ arr[3] = r13;
+ arr[4] = r14;
+ arr[5] = r15;
+}
+
+#elif defined(__i386__)
+
+STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
+ register long ebx asm ("ebx");
+ register long esi asm ("esi");
+ register long edi asm ("edi");
+ register long ebp asm ("ebp");
+ #ifdef __clang__
+ // TODO:
+ // This is dirty workaround for Clang. It tries to get around
+ // uncompliant (wrt to GCC) behavior of handling register variables.
+ // Application of this patch here is random, and done only to unbreak
+ // MacOS build. Better, cross-arch ways to deal with Clang issues should
+ // be found.
+ asm ("" : "=r" (ebx));
+ asm ("" : "=r" (esi));
+ asm ("" : "=r" (edi));
+ asm ("" : "=r" (ebp));
+ #endif
+ arr[0] = ebx;
+ arr[1] = esi;
+ arr[2] = edi;
+ arr[3] = ebp;
+}
+
+#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
+
+// Fallback implementation, prefer gchelper_m0.s or gchelper_m3.s
+
+STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
+ register long r4 asm ("r4");
+ register long r5 asm ("r5");
+ register long r6 asm ("r6");
+ register long r7 asm ("r7");
+ register long r8 asm ("r8");
+ register long r9 asm ("r9");
+ register long r10 asm ("r10");
+ register long r11 asm ("r11");
+ register long r12 asm ("r12");
+ register long r13 asm ("r13");
+ arr[0] = r4;
+ arr[1] = r5;
+ arr[2] = r6;
+ arr[3] = r7;
+ arr[4] = r8;
+ arr[5] = r9;
+ arr[6] = r10;
+ arr[7] = r11;
+ arr[8] = r12;
+ arr[9] = r13;
+}
+
+#else
+
+#error "Architecture not supported for gc_helper_get_regs. Set MICROPY_GCREGS_SETJMP to use the fallback implementation."
+
+#endif
+
+#else // !MICROPY_GCREGS_SETJMP
+
+// Even if we have specific support for an architecture, it is
+// possible to force use of setjmp-based implementation.
+
+STATIC void gc_helper_get_regs(gc_helper_regs_t arr) {
+ setjmp(arr);
+}
+
+#endif // MICROPY_GCREGS_SETJMP
+
+// Explicitly mark this as noinline to make sure the regs variable
+// is effectively at the top of the stack: otherwise, in builds where
+// LTO is enabled and a lot of inlining takes place we risk a stack
+// layout where regs is lower on the stack than pointers which have
+// just been allocated but not yet marked, and get incorrectly sweeped.
+MP_NOINLINE void gc_helper_collect_regs_and_stack(void) {
+ gc_helper_regs_t regs;
+ gc_helper_get_regs(regs);
+ // GC stack (and regs because we captured them)
+ void **regs_ptr = (void **)(void *)&regs;
+ gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_THREAD(stack_top) - (uintptr_t)&regs) / sizeof(uintptr_t));
+}
+
+#endif // MICROPY_ENABLE_GC
diff --git a/lib/utils/gchelper_m3.s b/lib/utils/gchelper_m3.s
index 3aac0dedf..5220fa088 100644
--- a/lib/utils/gchelper_m3.s
+++ b/lib/utils/gchelper_m3.s
@@ -31,18 +31,6 @@
.section .text
.align 2
- .global gc_helper_get_sp
- .type gc_helper_get_sp, %function
-
-@ uint gc_helper_get_sp(void)
-gc_helper_get_sp:
- @ return the sp
- mov r0, sp
- bx lr
-
- .size gc_helper_get_sp, .-gc_helper_get_sp
-
-
.global gc_helper_get_regs_and_sp
.type gc_helper_get_regs_and_sp, %function
diff --git a/lib/utils/gchelper_native.c b/lib/utils/gchelper_native.c
new file mode 100644
index 000000000..6bf386b51
--- /dev/null
+++ b/lib/utils/gchelper_native.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013, 2014 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 <stdio.h>
+
+#include "py/mpstate.h"
+#include "py/gc.h"
+#include "lib/utils/gchelper.h"
+
+#if MICROPY_ENABLE_GC
+
+// provided by gchelper_*.s
+uintptr_t gc_helper_get_regs_and_sp(uintptr_t *regs);
+
+MP_NOINLINE void gc_helper_collect_regs_and_stack(void) {
+ // get the registers and the sp
+ gc_helper_regs_t regs;
+ uintptr_t sp = gc_helper_get_regs_and_sp(regs);
+
+ // trace the stack, including the registers (since they live on the stack in this function)
+ gc_collect_root((void **)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+}
+
+#endif
diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile
index 2116cc670..f80ee761b 100644
--- a/mpy-cross/Makefile
+++ b/mpy-cross/Makefile
@@ -48,6 +48,7 @@ LDFLAGS = $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA)
SRC_C = \
main.c \
gccollect.c \
+ lib/utils/gchelper_generic.c \
# Add fmode when compiling with mingw gcc
COMPILER_TARGET := $(shell $(CC) -dumpmachine)
diff --git a/mpy-cross/gccollect.c b/mpy-cross/gccollect.c
index f655a07da..120f1a225 100644
--- a/mpy-cross/gccollect.c
+++ b/mpy-cross/gccollect.c
@@ -29,120 +29,13 @@
#include "py/mpstate.h"
#include "py/gc.h"
-#if MICROPY_ENABLE_GC
-
-// Even if we have specific support for an architecture, it is
-// possible to force use of setjmp-based implementation.
-#if !MICROPY_GCREGS_SETJMP
-
-// We capture here callee-save registers, i.e. ones which may contain
-// interesting values held there by our callers. It doesn't make sense
-// to capture caller-saved registers, because they, well, put on the
-// stack already by the caller.
-#if defined(__x86_64__)
-typedef mp_uint_t regs_t[6];
-
-STATIC void gc_helper_get_regs(regs_t arr) {
- register long rbx asm ("rbx");
- register long rbp asm ("rbp");
- register long r12 asm ("r12");
- register long r13 asm ("r13");
- register long r14 asm ("r14");
- register long r15 asm ("r15");
- #ifdef __clang__
- // TODO:
- // This is dirty workaround for Clang. It tries to get around
- // uncompliant (wrt to GCC) behavior of handling register variables.
- // Application of this patch here is random, and done only to unbreak
- // MacOS build. Better, cross-arch ways to deal with Clang issues should
- // be found.
- asm ("" : "=r" (rbx));
- asm ("" : "=r" (rbp));
- asm ("" : "=r" (r12));
- asm ("" : "=r" (r13));
- asm ("" : "=r" (r14));
- asm ("" : "=r" (r15));
- #endif
- arr[0] = rbx;
- arr[1] = rbp;
- arr[2] = r12;
- arr[3] = r13;
- arr[4] = r14;
- arr[5] = r15;
-}
-
-#elif defined(__i386__)
-
-typedef mp_uint_t regs_t[4];
-
-STATIC void gc_helper_get_regs(regs_t arr) {
- register long ebx asm ("ebx");
- register long esi asm ("esi");
- register long edi asm ("edi");
- register long ebp asm ("ebp");
- arr[0] = ebx;
- arr[1] = esi;
- arr[2] = edi;
- arr[3] = ebp;
-}
-
-#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
-
-typedef mp_uint_t regs_t[10];
+#include "lib/utils/gchelper.h"
-STATIC void gc_helper_get_regs(regs_t arr) {
- register long r4 asm ("r4");
- register long r5 asm ("r5");
- register long r6 asm ("r6");
- register long r7 asm ("r7");
- register long r8 asm ("r8");
- register long r9 asm ("r9");
- register long r10 asm ("r10");
- register long r11 asm ("r11");
- register long r12 asm ("r12");
- register long r13 asm ("r13");
- arr[0] = r4;
- arr[1] = r5;
- arr[2] = r6;
- arr[3] = r7;
- arr[4] = r8;
- arr[5] = r9;
- arr[6] = r10;
- arr[7] = r11;
- arr[8] = r12;
- arr[9] = r13;
-}
-
-#else
-
-// If we don't have architecture-specific optimized support,
-// just fall back to setjmp-based implementation.
-#undef MICROPY_GCREGS_SETJMP
-#define MICROPY_GCREGS_SETJMP (1)
-
-#endif // Arch-specific selection
-#endif // !MICROPY_GCREGS_SETJMP
-
-// If MICROPY_GCREGS_SETJMP was requested explicitly, or if
-// we enabled it as a fallback above.
-#if MICROPY_GCREGS_SETJMP
-#include <setjmp.h>
-
-typedef jmp_buf regs_t;
-
-STATIC void gc_helper_get_regs(regs_t arr) {
- setjmp(arr);
-}
-
-#endif // MICROPY_GCREGS_SETJMP
+#if MICROPY_ENABLE_GC
void gc_collect(void) {
gc_collect_start();
- regs_t regs;
- gc_helper_get_regs(regs);
- // GC stack (and regs because we captured them)
- void **regs_ptr = (void **)(void *)&regs;
- gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_THREAD(stack_top) - (mp_uint_t)&regs) / sizeof(mp_uint_t));
+ gc_helper_collect_regs_and_stack();
gc_collect_end();
}
diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h
index f2b4ae99b..2282e5e08 100644
--- a/mpy-cross/mpconfigport.h
+++ b/mpy-cross/mpconfigport.h
@@ -68,14 +68,9 @@
#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
-// Define to 1 to use undertested inefficient GC helper implementation
-// (if more efficient arch-specific one is not available).
-#ifndef MICROPY_GCREGS_SETJMP
- #ifdef __mips__
- #define MICROPY_GCREGS_SETJMP (1)
- #else
- #define MICROPY_GCREGS_SETJMP (0)
- #endif
+#if !defined(__x86_64__) || !defined(__i386__) || !defined(__thumb2__) || !defined(__thumb__) || !defined(__arm__)
+// Fall back to setjmp() implementation for discovery of GC pointers in registers.
+#define MICROPY_GCREGS_SETJMP (1)
#endif
#define MICROPY_PY___FILE__ (0)
diff --git a/mpy-cross/mpy-cross.vcxproj b/mpy-cross/mpy-cross.vcxproj
index 805580c78..74a366712 100644
--- a/mpy-cross/mpy-cross.vcxproj
+++ b/mpy-cross/mpy-cross.vcxproj
@@ -89,6 +89,9 @@
<Import Project="$(PyMsvcDir)sources.props" />
<ItemGroup>
<ClCompile Include="@(PyCoreSource)" />
+ <ClCompile Include="$(PyBaseDir)lib/utils/gchelper_generic.c" >
+ <PreprocessorDefinitions>MICROPY_GCREGS_SETJMP</PreprocessorDefinitions>
+ </ClCompile>
<ClCompile Include="$(PyBaseDir)mpy-cross\gccollect.c"/>
<ClCompile Include="$(PyBaseDir)mpy-cross\main.c"/>
<ClCompile Include="$(PyBaseDir)ports\windows\fmode.c" />
diff --git a/ports/cc3200/application.mk b/ports/cc3200/application.mk
index 86ea3c730..b216ca16d 100644
--- a/ports/cc3200/application.mk
+++ b/ports/cc3200/application.mk
@@ -126,6 +126,7 @@ APP_UTIL_SRC_C = $(addprefix util/,\
)
APP_UTIL_SRC_S = $(addprefix util/,\
+ cortex_m3_get_sp.s \
sleeprestore.s \
)
@@ -143,6 +144,7 @@ APP_LIB_SRC_C = $(addprefix lib/,\
mp-readline/readline.c \
netutils/netutils.c \
timeutils/timeutils.c \
+ utils/gchelper_native.c \
utils/pyexec.c \
utils/interrupt_char.c \
utils/sys_stdio_mphal.c \
diff --git a/ports/cc3200/mptask.c b/ports/cc3200/mptask.c
index 79c7fc349..f06a50277 100644
--- a/ports/cc3200/mptask.c
+++ b/ports/cc3200/mptask.c
@@ -111,9 +111,11 @@ static const char fresh_boot_py[] = "# boot.py -- run on boot-up\r\n"
DECLARE PUBLIC FUNCTIONS
******************************************************************************/
+uintptr_t cortex_m3_get_sp(void);
+
void TASK_MicroPython (void *pvParameters) {
// get the top of the stack to initialize the garbage collector
- uint32_t sp = gc_helper_get_sp();
+ uint32_t sp = cortex_m3_get_sp();
bool safeboot = false;
mptask_pre_init();
diff --git a/ports/cc3200/util/cortex_m3_get_sp.s b/ports/cc3200/util/cortex_m3_get_sp.s
new file mode 100644
index 000000000..b7e78f1d3
--- /dev/null
+++ b/ports/cc3200/util/cortex_m3_get_sp.s
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013-2014 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.
+ */
+
+ .syntax unified
+ .cpu cortex-m3
+ .thumb
+
+ .section .text
+ .align 2
+
+ .global cortex_m3_get_sp
+ .type cortex_m3_get_sp, %function
+
+@ uint cortex_m3_get_sp(void)
+cortex_m3_get_sp:
+ @ return the sp
+ mov r0, sp
+ bx lr
+
+ .size cortex_m3_get_sp, .-cortex_m3_get_sp
diff --git a/ports/cc3200/util/gccollect.c b/ports/cc3200/util/gccollect.c
index 65b2f1605..eac0c86b0 100644
--- a/ports/cc3200/util/gccollect.c
+++ b/ports/cc3200/util/gccollect.c
@@ -41,12 +41,8 @@ void gc_collect(void) {
// start the GC
gc_collect_start();
- // get the registers and the sp
- mp_uint_t regs[10];
- mp_uint_t sp = gc_helper_get_regs_and_sp(regs);
-
- // trace the stack, including the registers (since they live on the stack in this function)
- gc_collect_root((void**)sp, ((mp_uint_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+ // trace the stack and the registers
+ gc_helper_collect_regs_and_stack();
// trace root pointers from any threads
#if MICROPY_PY_THREAD
diff --git a/ports/mimxrt/Makefile b/ports/mimxrt/Makefile
index 3bf9916e7..cbd2b8595 100644
--- a/ports/mimxrt/Makefile
+++ b/ports/mimxrt/Makefile
@@ -96,6 +96,7 @@ SRC_C = \
mphalport.c \
lib/mp-readline/readline.c \
lib/libc/string0.c \
+ lib/utils/gchelper_native.c \
lib/utils/printf.c \
lib/utils/pyexec.c \
lib/utils/stdout_helpers.c \
diff --git a/ports/mimxrt/main.c b/ports/mimxrt/main.c
index a718cb46c..d94bf2441 100644
--- a/ports/mimxrt/main.c
+++ b/ports/mimxrt/main.c
@@ -75,9 +75,7 @@ int main(void) {
void gc_collect(void) {
gc_collect_start();
- uintptr_t regs[10];
- uintptr_t sp = gc_helper_get_regs_and_sp(regs);
- gc_collect_root((void **)sp, ((uintptr_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+ gc_helper_collect_regs_and_stack();
gc_collect_end();
}
diff --git a/ports/qemu-arm/Makefile b/ports/qemu-arm/Makefile
index 47a45af61..430740ccf 100644
--- a/ports/qemu-arm/Makefile
+++ b/ports/qemu-arm/Makefile
@@ -94,6 +94,7 @@ LIB_SRC_C += $(addprefix lib/,\
libm/atanf.c \
libm/atan2f.c \
libm/roundf.c \
+ utils/gchelper_native.c \
utils/sys_stdio_mphal.c \
)
diff --git a/ports/qemu-arm/test_main.c b/ports/qemu-arm/test_main.c
index 5fc5d4ece..a59a8de0a 100644
--- a/ports/qemu-arm/test_main.c
+++ b/ports/qemu-arm/test_main.c
@@ -31,14 +31,7 @@ int main() {
void gc_collect(void) {
gc_collect_start();
-
- // get the registers and the sp
- uintptr_t regs[10];
- uintptr_t sp = gc_helper_get_regs_and_sp(regs);
-
- // trace the stack, including the registers (since they live on the stack in this function)
- gc_collect_root((void **)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - (uint32_t)sp) / sizeof(uint32_t));
-
+ gc_helper_collect_regs_and_stack();
gc_collect_end();
}
diff --git a/ports/samd/Makefile b/ports/samd/Makefile
index 2a5c2905c..ffd0f06a3 100644
--- a/ports/samd/Makefile
+++ b/ports/samd/Makefile
@@ -65,6 +65,7 @@ SRC_C = \
lib/tinyusb/src/device/usbd_control.c \
lib/tinyusb/src/portable/microchip/samd/dcd_samd.c \
lib/tinyusb/src/tusb.c \
+ lib/utils/gchelper_native.c \
lib/utils/printf.c \
lib/utils/pyexec.c \
lib/utils/stdout_helpers.c \
diff --git a/ports/samd/main.c b/ports/samd/main.c
index 6c6b6f354..038373ceb 100644
--- a/ports/samd/main.c
+++ b/ports/samd/main.c
@@ -65,9 +65,7 @@ void samd_main(void) {
void gc_collect(void) {
gc_collect_start();
- uintptr_t regs[10];
- uintptr_t sp = gc_helper_get_regs_and_sp(regs);
- gc_collect_root((void **)sp, ((uintptr_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+ gc_helper_collect_regs_and_stack();
gc_collect_end();
}
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index 4e35a4454..fdea95e92 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -148,6 +148,7 @@ LIB_SRC_C = $(addprefix lib/,\
netutils/trace.c \
netutils/dhcpserver.c \
timeutils/timeutils.c \
+ utils/gchelper_native.c \
utils/pyexec.c \
utils/interrupt_char.c \
utils/sys_stdio_mphal.c \
diff --git a/ports/stm32/gccollect.c b/ports/stm32/gccollect.c
index cd7b22c5f..ad5645738 100644
--- a/ports/stm32/gccollect.c
+++ b/ports/stm32/gccollect.c
@@ -43,12 +43,8 @@ void gc_collect(void) {
// start the GC
gc_collect_start();
- // get the registers and the sp
- uintptr_t regs[10];
- uintptr_t sp = gc_helper_get_regs_and_sp(regs);
-
- // trace the stack, including the registers (since they live on the stack in this function)
- gc_collect_root((void **)sp, ((uint32_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+ // trace the stack and registers
+ gc_helper_collect_regs_and_stack();
// trace root pointers from any threads
#if MICROPY_PY_THREAD
diff --git a/ports/teensy/Makefile b/ports/teensy/Makefile
index adfc8d74f..f2623eabd 100644
--- a/ports/teensy/Makefile
+++ b/ports/teensy/Makefile
@@ -104,6 +104,7 @@ STM_SRC_C = $(addprefix ports/stm32/,\
LIB_SRC_C = $(addprefix lib/,\
libc/string0.c \
mp-readline/readline.c \
+ utils/gchelper_native.c \
utils/pyexec.c \
utils/sys_stdio_mphal.c \
)
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
index d9e77c26c..ec1416614 100644
--- a/ports/unix/Makefile
+++ b/ports/unix/Makefile
@@ -205,6 +205,7 @@ SRC_C = \
LIB_SRC_C += $(addprefix lib/,\
$(LIB_SRC_C_EXTRA) \
timeutils/timeutils.c \
+ utils/gchelper_generic.c \
)
OBJ = $(PY_O)
diff --git a/ports/unix/gccollect.c b/ports/unix/gccollect.c
index 231f016c2..f0441e4ea 100644
--- a/ports/unix/gccollect.c
+++ b/ports/unix/gccollect.c
@@ -29,146 +29,15 @@
#include "py/mpstate.h"
#include "py/gc.h"
-#if MICROPY_ENABLE_GC
-
-// Even if we have specific support for an architecture, it is
-// possible to force use of setjmp-based implementation.
-#if !MICROPY_GCREGS_SETJMP
-
-// We capture here callee-save registers, i.e. ones which may contain
-// interesting values held there by our callers. It doesn't make sense
-// to capture caller-saved registers, because they, well, put on the
-// stack already by the caller.
-#if defined(__x86_64__)
-typedef mp_uint_t regs_t[6];
-
-STATIC void gc_helper_get_regs(regs_t arr) {
- register long rbx asm ("rbx");
- register long rbp asm ("rbp");
- register long r12 asm ("r12");
- register long r13 asm ("r13");
- register long r14 asm ("r14");
- register long r15 asm ("r15");
- #ifdef __clang__
- // TODO:
- // This is dirty workaround for Clang. It tries to get around
- // uncompliant (wrt to GCC) behavior of handling register variables.
- // Application of this patch here is random, and done only to unbreak
- // MacOS build. Better, cross-arch ways to deal with Clang issues should
- // be found.
- asm ("" : "=r" (rbx));
- asm ("" : "=r" (rbp));
- asm ("" : "=r" (r12));
- asm ("" : "=r" (r13));
- asm ("" : "=r" (r14));
- asm ("" : "=r" (r15));
- #endif
- arr[0] = rbx;
- arr[1] = rbp;
- arr[2] = r12;
- arr[3] = r13;
- arr[4] = r14;
- arr[5] = r15;
-}
-
-#elif defined(__i386__)
-
-typedef mp_uint_t regs_t[4];
-
-STATIC void gc_helper_get_regs(regs_t arr) {
- register long ebx asm ("ebx");
- register long esi asm ("esi");
- register long edi asm ("edi");
- register long ebp asm ("ebp");
- #ifdef __clang__
- // TODO:
- // This is dirty workaround for Clang. It tries to get around
- // uncompliant (wrt to GCC) behavior of handling register variables.
- // Application of this patch here is random, and done only to unbreak
- // MacOS build. Better, cross-arch ways to deal with Clang issues should
- // be found.
- asm ("" : "=r" (ebx));
- asm ("" : "=r" (esi));
- asm ("" : "=r" (edi));
- asm ("" : "=r" (ebp));
- #endif
- arr[0] = ebx;
- arr[1] = esi;
- arr[2] = edi;
- arr[3] = ebp;
-}
-
-#elif defined(__thumb2__) || defined(__thumb__) || defined(__arm__)
-
-typedef mp_uint_t regs_t[10];
+#include "lib/utils/gchelper.h"
-STATIC void gc_helper_get_regs(regs_t arr) {
- register long r4 asm ("r4");
- register long r5 asm ("r5");
- register long r6 asm ("r6");
- register long r7 asm ("r7");
- register long r8 asm ("r8");
- register long r9 asm ("r9");
- register long r10 asm ("r10");
- register long r11 asm ("r11");
- register long r12 asm ("r12");
- register long r13 asm ("r13");
- arr[0] = r4;
- arr[1] = r5;
- arr[2] = r6;
- arr[3] = r7;
- arr[4] = r8;
- arr[5] = r9;
- arr[6] = r10;
- arr[7] = r11;
- arr[8] = r12;
- arr[9] = r13;
-}
-
-#else
-
-// If we don't have architecture-specific optimized support,
-// just fall back to setjmp-based implementation.
-#undef MICROPY_GCREGS_SETJMP
-#define MICROPY_GCREGS_SETJMP (1)
-
-#endif // Arch-specific selection
-#endif // !MICROPY_GCREGS_SETJMP
-
-// If MICROPY_GCREGS_SETJMP was requested explicitly, or if
-// we enabled it as a fallback above.
-#if MICROPY_GCREGS_SETJMP
-#include <setjmp.h>
-
-typedef jmp_buf regs_t;
-
-STATIC void gc_helper_get_regs(regs_t arr) {
- setjmp(arr);
-}
-
-#endif // MICROPY_GCREGS_SETJMP
-
-// this function is used by mpthreadport.c
-MP_NOINLINE void gc_collect_regs_and_stack(void);
-
-// Explicitly mark this as noinline to make sure the regs variable
-// is effectively at the top of the stack: otherwise, in builds where
-// LTO is enabled and a lot of inlining takes place we risk a stack
-// layout where regs is lower on the stack than pointers which have
-// just been allocated but not yet marked, and get incorrectly sweeped.
-MP_NOINLINE void gc_collect_regs_and_stack(void) {
- regs_t regs;
- gc_helper_get_regs(regs);
- // GC stack (and regs because we captured them)
- void **regs_ptr = (void **)(void *)&regs;
- gc_collect_root(regs_ptr, ((uintptr_t)MP_STATE_THREAD(stack_top) - (uintptr_t)&regs) / sizeof(uintptr_t));
-}
+#if MICROPY_ENABLE_GC
void gc_collect(void) {
// gc_dump_info();
gc_collect_start();
- gc_collect_regs_and_stack();
+ gc_helper_collect_regs_and_stack();
#if MICROPY_PY_THREAD
mp_thread_gc_others();
#endif
diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h
index 5708ceab6..0565c0d76 100644
--- a/ports/unix/mpconfigport.h
+++ b/ports/unix/mpconfigport.h
@@ -178,14 +178,9 @@
extern const struct _mp_print_t mp_stderr_print;
-// Define to 1 to use undertested inefficient GC helper implementation
-// (if more efficient arch-specific one is not available).
-#ifndef MICROPY_GCREGS_SETJMP
- #ifdef __mips__
- #define MICROPY_GCREGS_SETJMP (1)
- #else
- #define MICROPY_GCREGS_SETJMP (0)
- #endif
+#if !defined(__x86_64__) || !defined(__i386__) || !defined(__thumb2__) || !defined(__thumb__) || !defined(__arm__)
+// Fall back to setjmp() implementation for discovery of GC pointers in registers.
+#define MICROPY_GCREGS_SETJMP (1)
#endif
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c
index 66c428940..711cf2a6b 100644
--- a/ports/unix/mpthreadport.c
+++ b/ports/unix/mpthreadport.c
@@ -39,6 +39,8 @@
#include <sched.h>
#include <semaphore.h>
+#include "lib/utils/gchelper.h"
+
// Some platforms don't have SIGRTMIN but if we do have it, use it to avoid
// potential conflict with other uses of the more commonly used SIGUSR1.
#ifdef SIGRTMIN
@@ -88,8 +90,7 @@ STATIC void mp_thread_gc(int signo, siginfo_t *info, void *context) {
(void)info; // unused
(void)context; // unused
if (signo == MP_THREAD_GC_SIGNAL) {
- void gc_collect_regs_and_stack(void);
- gc_collect_regs_and_stack();
+ gc_helper_collect_regs_and_stack();
// We have access to the context (regs, stack) of the thread but it seems
// that we don't need the extra information, enough is captured by the
// gc_collect_regs_and_stack function above
diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h
index e961ff4b2..25e1d20d5 100644
--- a/ports/unix/variants/minimal/mpconfigvariant.h
+++ b/ports/unix/variants/minimal/mpconfigvariant.h
@@ -110,14 +110,9 @@ extern const struct _mp_obj_module_t mp_module_os;
// Do not change anything beyond this line
//////////////////////////////////////////
-// Define to 1 to use undertested inefficient GC helper implementation
-// (if more efficient arch-specific one is not available).
-#ifndef MICROPY_GCREGS_SETJMP
- #ifdef __mips__
- #define MICROPY_GCREGS_SETJMP (1)
- #else
- #define MICROPY_GCREGS_SETJMP (0)
- #endif
+#if !defined(__x86_64__) || !defined(__i386__) || !defined(__thumb2__) || !defined(__thumb__) || !defined(__arm__)
+// Fall back to setjmp() implementation for discovery of GC pointers in registers.
+#define MICROPY_GCREGS_SETJMP (1)
#endif
// type definitions for the specific machine
diff --git a/ports/windows/Makefile b/ports/windows/Makefile
index 6c8963513..b2d11872e 100644
--- a/ports/windows/Makefile
+++ b/ports/windows/Makefile
@@ -28,6 +28,7 @@ endif
# source files
SRC_C = \
+ lib/utils/gchelper_generic.c \
lib/utils/printf.c \
ports/unix/main.c \
ports/unix/input.c \
diff --git a/ports/windows/micropython.vcxproj b/ports/windows/micropython.vcxproj
index dea06de35..f70fe9615 100644
--- a/ports/windows/micropython.vcxproj
+++ b/ports/windows/micropython.vcxproj
@@ -86,6 +86,7 @@
<ClCompile Include="@(PyCoreSource)" />
<ClCompile Include="@(PyExtModSource)" />
<ClCompile Include="$(PyBaseDir)lib\mp-readline\*.c" />
+ <ClCompile Include="$(PyBaseDir)lib\utils\gchelper_generic.c" />
<ClCompile Include="$(PyBaseDir)ports\windows\*.c" />
<ClCompile Include="$(PyBaseDir)ports\windows\msvc\*.c" />
<ClCompile Include="$(PyBaseDir)ports\unix\gccollect.c"/>