diff --git a/unix/Makefile b/unix/Makefile index a1a6a7102c..e834e7e847 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -35,6 +35,7 @@ endif # source files SRC_C = \ main.c \ + gccollect.c \ file.c \ socket.c \ $(SRC_MOD) diff --git a/unix/gccollect.c b/unix/gccollect.c new file mode 100644 index 0000000000..cb2cc7a034 --- /dev/null +++ b/unix/gccollect.c @@ -0,0 +1,72 @@ +#include +#include + +#include "misc.h" +#include "mpconfig.h" +#include "gc.h" + +#if MICROPY_ENABLE_GC + +extern void *stack_top; + +// 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. +#ifdef __x86_64__ +typedef machine_uint_t regs_t[6]; + +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"); + arr[0] = rbx; + arr[1] = rbp; + arr[2] = r12; + arr[3] = r13; + arr[4] = r14; + arr[5] = r15; +} +#endif + +#ifdef __i386__ +typedef machine_uint_t regs_t[4]; + +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; +} +#endif + +void gc_collect(void) { + gc_collect_start(); + // this traces .data and .bss sections + extern char __bss_start, _end; + //printf(".bss: %p-%p\n", &__bss_start, &_end); + gc_collect_root((void**)&__bss_start, ((uint32_t)&_end - (uint32_t)&__bss_start) / sizeof(uint32_t)); + regs_t regs; + gc_helper_get_regs(regs); + // GC stack (and regs because we captured them) + gc_collect_root((void**)®s, ((uint32_t)stack_top - (uint32_t)®s) / sizeof(uint32_t)); + gc_collect_end(); + + if (0) { + // print GC info + gc_info_t info; + gc_info(&info); + printf("GC: total: " UINT_FMT ", used: " UINT_FMT ", free: " UINT_FMT "\n", info.total, info.used, info.free); + printf(" No. of 1-blocks: " UINT_FMT ", 2-blocks: " UINT_FMT ", max blk sz: " UINT_FMT "\n", + info.num_1block, info.num_2block, info.max_block); + } +} + +#endif //MICROPY_ENABLE_GC diff --git a/unix/main.c b/unix/main.c index 9bdcc53a7c..192a0e6e8b 100644 --- a/unix/main.c +++ b/unix/main.c @@ -15,12 +15,20 @@ #include "runtime0.h" #include "runtime.h" #include "repl.h" +#include "gc.h" #if MICROPY_USE_READLINE #include #include #endif +// Heap size of GC heap (if enabled) +// TODO: allow to specify on command line +#define HEAP_SIZE 128*1024 + +// Stack top at the start of program +void *stack_top; + extern const mp_obj_fun_native_t mp_builtin_open_obj; void file_init(); void microsocket_init(); @@ -217,7 +225,24 @@ mp_obj_t qstr_info(void) { return mp_const_none; } +#if MICROPY_ENABLE_GC +// TODO: this doesn't belong here +static mp_obj_t pyb_gc(void) { + gc_collect(); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(pyb_gc_obj, pyb_gc); +#endif + int main(int argc, char **argv) { + volatile int stack_dummy; + stack_top = (void*)&stack_dummy; + +#if MICROPY_ENABLE_GC + char *heap = malloc(HEAP_SIZE); + gc_init(heap, heap + HEAP_SIZE); +#endif + qstr_init(); rt_init(); @@ -263,6 +288,9 @@ int main(int argc, char **argv) { rt_store_name(qstr_from_str("test"), test_obj_new(42)); rt_store_name(qstr_from_str("mem_info"), rt_make_function_n(0, mem_info)); rt_store_name(qstr_from_str("qstr_info"), rt_make_function_n(0, qstr_info)); +#if MICROPY_ENABLE_GC + rt_store_name(qstr_from_str("gc"), (mp_obj_t)&pyb_gc_obj); +#endif file_init(); microsocket_init();