Skip to content

Commit 2127e9a

Browse files
committed
py, unix: Trace root pointers with native emitter under unix port.
Native code has GC-heap pointers in it so it must be scanned. But on unix port memory for native functions is mmap'd, and so it must have explicit code to scan it for root pointers.
1 parent c935d69 commit 2127e9a

5 files changed

Lines changed: 45 additions & 4 deletions

File tree

py/emitnative.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,7 @@ STATIC void emit_native_load_const_str(emit_t *emit, qstr qst, bool bytes) {
11741174

11751175
STATIC void emit_native_load_const_obj(emit_t *emit, void *obj) {
11761176
emit_native_pre(emit);
1177+
need_reg_single(emit, REG_RET, 0);
11771178
ASM_MOV_ALIGNED_IMM_TO_REG(emit->as, (mp_uint_t)obj, REG_RET);
11781179
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
11791180
}

py/mpconfig.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,9 @@ typedef double mp_float_t;
569569
#define MICROPY_MAKE_POINTER_CALLABLE(p) (p)
570570
#endif
571571

572+
// If these MP_PLAT_* macros are overridden then the memory allocated by them
573+
// must be somehow reachable for marking by the GC, since the native code
574+
// generators store pointers to GC managed memory in the code.
572575
#ifndef MP_PLAT_ALLOC_EXEC
573576
#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) do { *ptr = m_new(byte, min_size); *size = min_size; } while(0)
574577
#endif

unix/alloc.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,25 +24,61 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <stdio.h>
2728
#include <stdint.h>
2829
#include <stdlib.h>
30+
#include <string.h>
2931
#include <sys/mman.h>
3032

31-
#include "mpconfigport.h"
33+
#include "py/mpstate.h"
34+
#include "py/gc.h"
3235

3336
#if defined(__OpenBSD__) || defined(__MACH__)
3437
#define MAP_ANONYMOUS MAP_ANON
3538
#endif
3639

40+
// The memory allocated here is not on the GC heap (and it may contain pointers
41+
// that need to be GC'd) so we must somehow trace this memory. We do it by
42+
// keeping a linked list of all mmap'd regions, and tracing them explicitly.
43+
44+
typedef struct _mmap_region_t {
45+
void *ptr;
46+
size_t len;
47+
struct _mmap_region_t *next;
48+
} mmap_region_t;
49+
3750
void mp_unix_alloc_exec(mp_uint_t min_size, void **ptr, mp_uint_t *size) {
3851
// size needs to be a multiple of the page size
3952
*size = (min_size + 0xfff) & (~0xfff);
4053
*ptr = mmap(NULL, *size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
4154
if (*ptr == MAP_FAILED) {
4255
*ptr = NULL;
4356
}
57+
58+
// add new link to the list of mmap'd regions
59+
mmap_region_t *rg = m_new_obj(mmap_region_t);
60+
rg->ptr = *ptr;
61+
rg->len = min_size;
62+
rg->next = MP_STATE_VM(mmap_region_head);
63+
MP_STATE_VM(mmap_region_head) = rg;
4464
}
4565

4666
void mp_unix_free_exec(void *ptr, mp_uint_t size) {
4767
munmap(ptr, size);
68+
69+
// unlink the mmap'd region from the list
70+
for (mmap_region_t **rg = (mmap_region_t**)&MP_STATE_VM(mmap_region_head); *rg != NULL; *rg = (*rg)->next) {
71+
if ((*rg)->ptr == ptr) {
72+
mmap_region_t *next = (*rg)->next;
73+
m_del_obj(mmap_region_t, *rg);
74+
*rg = next;
75+
return;
76+
}
77+
}
78+
}
79+
80+
void mp_unix_mark_exec(void) {
81+
for (mmap_region_t *rg = MP_STATE_VM(mmap_region_head); rg != NULL; rg = rg->next) {
82+
gc_collect_root(rg->ptr, rg->len / sizeof(mp_uint_t));
83+
}
4884
}

unix/gccollect.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131

3232
#if MICROPY_ENABLE_GC
3333

34-
extern char *stack_top;
35-
3634
#if MICROPY_GCREGS_SETJMP
3735
#include <setjmp.h>
3836

@@ -133,6 +131,7 @@ void gc_collect(void) {
133131
// GC stack (and regs because we captured them)
134132
void **regs_ptr = (void**)(void*)&regs;
135133
gc_collect_root(regs_ptr, ((mp_uint_t)MP_STATE_VM(stack_top) - (mp_uint_t)&regs) / sizeof(mp_uint_t));
134+
mp_unix_mark_exec();
136135
gc_collect_end();
137136

138137
//printf("-----\n");

unix/mpconfigport.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ typedef const void *machine_const_ptr_t; // must be of pointer size
148148

149149
void mp_unix_alloc_exec(mp_uint_t min_size, void** ptr, mp_uint_t *size);
150150
void mp_unix_free_exec(void *ptr, mp_uint_t size);
151+
void mp_unix_mark_exec(void);
151152
#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size)
152153
#define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size)
153154

@@ -158,7 +159,8 @@ extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
158159
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
159160

160161
#define MICROPY_PORT_ROOT_POINTERS \
161-
mp_obj_t keyboard_interrupt_obj;
162+
mp_obj_t keyboard_interrupt_obj; \
163+
void *mmap_region_head; \
162164

163165
// We need to provide a declaration/definition of alloca()
164166
#ifdef __FreeBSD__

0 commit comments

Comments
 (0)