Skip to content

Commit 323f39a

Browse files
committed
Merge pull request adafruit#278 from pfalcon/unix-gc
Enable GC for Unix port
2 parents 0d14d13 + 723a6ed commit 323f39a

8 files changed

Lines changed: 131 additions & 17 deletions

File tree

py/gc.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ void gc_info(gc_info_t *info) {
240240

241241
void *gc_alloc(machine_uint_t n_bytes) {
242242
machine_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1) & (~(BYTES_PER_BLOCK - 1))) / BYTES_PER_BLOCK;
243-
//printf("gc_alloc(%u bytes -> %u blocks)\n", n_bytes, n_blocks);
243+
DEBUG_printf("gc_alloc(%u bytes -> %u blocks)\n", n_bytes, n_blocks);
244244

245245
// check for 0 allocation
246246
if (n_blocks == 0) {
@@ -267,6 +267,7 @@ void *gc_alloc(machine_uint_t n_bytes) {
267267
if (collected) {
268268
return NULL;
269269
}
270+
DEBUG_printf("gc_alloc(" UINT_FMT "): no free mem, triggering GC\n", n_bytes);
270271
gc_collect();
271272
collected = 1;
272273
}
@@ -341,6 +342,14 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
341342
}
342343
}
343344

345+
void gc_dump_info() {
346+
gc_info_t info;
347+
gc_info(&info);
348+
printf("GC: total: " UINT_FMT ", used: " UINT_FMT ", free: " UINT_FMT "\n", info.total, info.used, info.free);
349+
printf(" No. of 1-blocks: " UINT_FMT ", 2-blocks: " UINT_FMT ", max blk sz: " UINT_FMT "\n",
350+
info.num_1block, info.num_2block, info.max_block);
351+
}
352+
344353
#if DEBUG_PRINT
345354
static void gc_dump_at(void) {
346355
for (machine_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) {

py/malloc.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,22 @@ static int peak_bytes_allocated = 0;
1919
#define UPDATE_PEAK() { if (current_bytes_allocated > peak_bytes_allocated) peak_bytes_allocated = current_bytes_allocated; }
2020
#endif
2121

22+
#if MICROPY_ENABLE_GC
23+
#include "gc.h"
24+
25+
// We redirect standard alloc functions to GC heap - just for the rest of
26+
// this module. In the rest of micropython source, system malloc can be
27+
// freely accessed - for interfacing with system and 3rd-party libs for
28+
// example. On the other hand, some (e.g. bare-metal) ports may use GC
29+
// heap as system heap, so, to avoid warnings, we do undef's first.
30+
#undef malloc
31+
#undef free
32+
#undef realloc
33+
#define malloc gc_alloc
34+
#define free gc_free
35+
#define realloc gc_realloc
36+
#endif // MICROPY_ENABLE_GC
37+
2238
void *m_malloc(int num_bytes) {
2339
if (num_bytes == 0) {
2440
return NULL;

stm/malloc0.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,6 @@ void *realloc(void *ptr, size_t n) {
2929

3030
#endif
3131

32-
void *malloc(size_t n) {
33-
return gc_alloc(n);
34-
}
35-
36-
void free(void *ptr) {
37-
gc_free(ptr);
38-
}
39-
40-
void *realloc(void *ptr, size_t n) {
41-
return gc_realloc(ptr, n);
42-
}
43-
4432
void __assert_func(void) {
4533
printf("\nASSERT FAIL!");
4634
for (;;) {

stm/mpconfigport.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ typedef float machine_float_t;
2121

2222
machine_float_t machine_sqrt(machine_float_t x);
2323

24+
// There is no classical C heap in bare-metal ports, only Python
25+
// garbage-collected heap. For completeness, emulate C heap via
26+
// GC heap. Note that MicroPython core never uses malloc() and friends,
27+
// so these defines are mostly to help extension module writers.
28+
#define malloc gc_alloc
29+
#define free gc_free
30+
#define realloc gc_realloc
31+
2432
// board specific definitions
2533

2634
// choose 1 of these boards

stm/std.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ typedef unsigned int size_t;
22

33
void __assert_func(void);
44

5-
void *malloc(size_t n);
6-
void free(void *ptr);
7-
void *realloc(void *ptr, size_t n);
8-
95
void *memcpy(void *dest, const void *src, size_t n);
106
void *memmove(void *dest, const void *src, size_t n);
117
void *memset(void *s, int c, size_t n);

unix/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ endif
3535
# source files
3636
SRC_C = \
3737
main.c \
38+
gccollect.c \
3839
file.c \
3940
socket.c \
4041
$(SRC_MOD)

unix/gccollect.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <stdint.h>
2+
#include <stdio.h>
3+
4+
#include "misc.h"
5+
#include "mpconfig.h"
6+
#include "gc.h"
7+
8+
#if MICROPY_ENABLE_GC
9+
10+
extern void *stack_top;
11+
12+
// We capture here callee-save registers, i.e. ones which may contain
13+
// interesting values held there by our callers. It doesn't make sense
14+
// to capture caller-saved registers, because they, well, put on the
15+
// stack already by the caller.
16+
#ifdef __x86_64__
17+
typedef machine_uint_t regs_t[6];
18+
19+
void gc_helper_get_regs(regs_t arr) {
20+
register long rbx asm ("rbx");
21+
register long rbp asm ("rbp");
22+
register long r12 asm ("r12");
23+
register long r13 asm ("r13");
24+
register long r14 asm ("r14");
25+
register long r15 asm ("r15");
26+
arr[0] = rbx;
27+
arr[1] = rbp;
28+
arr[2] = r12;
29+
arr[3] = r13;
30+
arr[4] = r14;
31+
arr[5] = r15;
32+
}
33+
#endif
34+
35+
#ifdef __i386__
36+
typedef machine_uint_t regs_t[4];
37+
38+
void gc_helper_get_regs(regs_t arr) {
39+
register long ebx asm ("ebx");
40+
register long esi asm ("esi");
41+
register long edi asm ("edi");
42+
register long ebp asm ("ebp");
43+
arr[0] = ebx;
44+
arr[1] = esi;
45+
arr[2] = edi;
46+
arr[3] = ebp;
47+
}
48+
#endif
49+
50+
void gc_collect(void) {
51+
//gc_dump_info();
52+
53+
gc_collect_start();
54+
// this traces .data and .bss sections
55+
extern char __bss_start, _end;
56+
//printf(".bss: %p-%p\n", &__bss_start, &_end);
57+
gc_collect_root((void**)&__bss_start, ((uint32_t)&_end - (uint32_t)&__bss_start) / sizeof(uint32_t));
58+
regs_t regs;
59+
gc_helper_get_regs(regs);
60+
// GC stack (and regs because we captured them)
61+
gc_collect_root((void**)&regs, ((uint32_t)stack_top - (uint32_t)&regs) / sizeof(uint32_t));
62+
gc_collect_end();
63+
64+
//printf("-----\n");
65+
//gc_dump_info();
66+
}
67+
68+
#endif //MICROPY_ENABLE_GC

unix/main.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,20 @@
1515
#include "runtime0.h"
1616
#include "runtime.h"
1717
#include "repl.h"
18+
#include "gc.h"
1819

1920
#if MICROPY_USE_READLINE
2021
#include <readline/readline.h>
2122
#include <readline/history.h>
2223
#endif
2324

25+
// Heap size of GC heap (if enabled)
26+
// TODO: allow to specify on command line
27+
#define HEAP_SIZE 128*1024
28+
29+
// Stack top at the start of program
30+
void *stack_top;
31+
2432
extern const mp_obj_fun_native_t mp_builtin_open_obj;
2533
void file_init();
2634
void microsocket_init();
@@ -217,7 +225,24 @@ mp_obj_t qstr_info(void) {
217225
return mp_const_none;
218226
}
219227

228+
#if MICROPY_ENABLE_GC
229+
// TODO: this doesn't belong here
230+
static mp_obj_t pyb_gc(void) {
231+
gc_collect();
232+
return mp_const_none;
233+
}
234+
MP_DEFINE_CONST_FUN_OBJ_0(pyb_gc_obj, pyb_gc);
235+
#endif
236+
220237
int main(int argc, char **argv) {
238+
volatile int stack_dummy;
239+
stack_top = (void*)&stack_dummy;
240+
241+
#if MICROPY_ENABLE_GC
242+
char *heap = malloc(HEAP_SIZE);
243+
gc_init(heap, heap + HEAP_SIZE);
244+
#endif
245+
221246
qstr_init();
222247
rt_init();
223248

@@ -263,6 +288,9 @@ int main(int argc, char **argv) {
263288
rt_store_name(qstr_from_str("test"), test_obj_new(42));
264289
rt_store_name(qstr_from_str("mem_info"), rt_make_function_n(0, mem_info));
265290
rt_store_name(qstr_from_str("qstr_info"), rt_make_function_n(0, qstr_info));
291+
#if MICROPY_ENABLE_GC
292+
rt_store_name(qstr_from_str("gc"), (mp_obj_t)&pyb_gc_obj);
293+
#endif
266294

267295
file_init();
268296
microsocket_init();

0 commit comments

Comments
 (0)