From cb9e6c78acc7f514930a377167d304a9776bc6f5 Mon Sep 17 00:00:00 2001 From: Alex Shinn Date: Mon, 29 Jun 2015 23:48:26 +0900 Subject: [PATCH] adding initial experimental compacting gc --- gc.c | 191 +++++++++++++++++++++++++++++++++++++++ include/chibi/features.h | 7 ++ main.c | 7 ++ 3 files changed, 205 insertions(+) diff --git a/gc.c b/gc.c index 5884a77e..f1814a44 100644 --- a/gc.c +++ b/gc.c @@ -775,6 +775,197 @@ sexp sexp_copy_context (sexp ctx, sexp dst, sexp flags) { #endif +#if SEXP_USE_COMPACTING_GC +#define sexp_forward_pointer(x) (((sexp*)&((x)->value))[0]) + +struct sexp_type_gc_info { + short field_base, field_len_base, field_len_off; + unsigned short field_len_scale; + short size_base, size_off; + unsigned short size_scale; +}; + +struct sexp_type_gc_info* sexp_get_type_gc_info(sexp ctx) { + int i; + sexp t; + struct sexp_type_gc_info* res = + malloc(sizeof(struct sexp_type_gc_info) * sexp_context_num_types(ctx)); + for (i=0; i < sexp_context_num_types(ctx); ++i) { + t = sexp_type_by_index(ctx, i); + res[i].field_base = sexp_type_field_base(t); + res[i].field_len_base = sexp_type_field_len_base(t); + res[i].field_len_off = sexp_type_field_len_off(t); + res[i].field_len_scale = sexp_type_field_len_scale(t); + res[i].size_base = sexp_type_size_base(t); + res[i].size_off = sexp_type_size_off(t); + res[i].size_scale = sexp_type_size_scale(t); + } + return res; +} + +static size_t sexp_heap_allocated_bytes(struct sexp_type_gc_info* t, sexp x) { + if (!x || !sexp_pointerp(x)) + return sexp_heap_align(1); + return sexp_heap_align((((sexp_uint_t*)((char*)x + t->size_off))[0] + * t->size_scale + t->size_base)); +} + +static void sexp_cheney_mark (struct sexp_type_gc_info* type_gc_info, sexp y, char** end) { + sexp_sint_t ysize; + if (!sexp_markedp(y)) { + ysize = sexp_heap_allocated_bytes(&type_gc_info[sexp_pointer_tag(y)], y); + memcpy(*end, (char*)y, ysize); + sexp_markedp(y) = 1; + sexp_forward_pointer(y) = (sexp)*end; + *end += ysize; + } +} + +#if SEXP_USE_ALIGNED_BYTECODE +#define sexp_align_index(i) i = sexp_word_align((sexp_uint_t)i) +#else +#define sexp_align_index(i) 0 +#endif + +/* cheney's algorithm: iterative BFS copy */ +char* sexp_cheney (struct sexp_type_gc_info* type_gc_info, sexp x, char* end) { + struct sexp_type_gc_info* t; + sexp_sint_t i, len; + sexp y, *p, *q; + while ((char*)x < end) { + /* walk fields */ + t = &(type_gc_info[sexp_pointer_tag(x)]); + len = (((sexp_uint_t*)((char*)x + t->field_len_off))[0] + * t->field_len_scale + t->field_len_base); + if (len > 0) { + p = (sexp*) (((char*)x) + t->field_base); + q = p + len; + for ( ; p < q; ++p) { + y = *p; + if (y && sexp_pointerp(y)) { + sexp_cheney_mark(type_gc_info, y, &end); + *p = sexp_forward_pointer(y); + } + } + } + /* walk pointer values in bytecode */ + if (sexp_bytecodep(x)) { + for (i=0; ifree_list = (sexp_free_list)to->data; + next = (sexp_free_list) + (((char*)free_ls)+sexp_heap_align(sexp_free_chunk_size)); + } else if (!sexp_contextp(dst)) { + return sexp_type_exception(ctx, NULL, SEXP_CONTEXT, dst); + } else if (sexp_context_heap(dst)->size < from_size) { + return sexp_user_exception(ctx, NULL, "destination context too small", dst); + } else { + to = sexp_context_heap(dst); + free_ls = to->free_list = (sexp_free_list)to->data; + next = (sexp_free_list) + (((char*)free_ls)+sexp_heap_align(sexp_free_chunk_size)); + free_ls->size = 0; /* actually sexp_heap_align(sexp_free_chunk_size) */ + free_ls->next = next; + next->size = from->size - sexp_heap_align(sexp_free_chunk_size); + next->next = NULL; + } + + /* extract the necessary type info outside the heap */ + /* this simplifies processing (since the types get moved), */ + /* and helps to keep the info in cache */ + type_gc_info = sexp_get_type_gc_info(ctx); + + /* recursively copy into the new heap starting with the root context */ + end = (char*)next; + memcpy(end, ctx, sexp_sizeof(context)); + end += sexp_heap_align(sexp_sizeof(context)); + /* update forward pointers */ + sexp_markedp(ctx) = 1; + sexp_forward_pointer(ctx) = (sexp)next; + ctx = (sexp)next; + /* run cheney (this does all the work) */ + free_ls = to->free_list = (sexp_free_list)sexp_cheney(type_gc_info, ctx, end); + /* fixup the new free list */ + next = (sexp_free_list) + (((char*)free_ls)+sexp_heap_align(sexp_free_chunk_size)); + free_ls->size = 0; + free_ls->next = next; + next->size = (char*)sexp_heap_end(to) - (char*)next; + next->next = NULL; + + /* cleanup and return the new ctx location */ + free(type_gc_info); + return ctx; +} +#endif + void sexp_gc_init (void) { #if SEXP_USE_GLOBAL_HEAP || SEXP_USE_CONSERVATIVE_GC sexp_uint_t size = sexp_heap_align(SEXP_INITIAL_HEAP_SIZE); diff --git a/include/chibi/features.h b/include/chibi/features.h index 4d6994d9..385f8dc1 100644 --- a/include/chibi/features.h +++ b/include/chibi/features.h @@ -84,6 +84,9 @@ /* go away and you're not working on your own C extension. */ /* #define SEXP_USE_CONSERVATIVE_GC 1 */ +/* uncomment this to enable experimental gc compaction */ +/* #define SEXP_USE_COMPACTING_GC 1 */ + /* uncomment this to disable automatic running of finalizers */ /* You will need to close ports and file descriptors manually */ /* (as you should anyway) and some C extensions may break. */ @@ -399,6 +402,10 @@ #define SEXP_USE_CONSERVATIVE_GC 0 #endif +#ifndef SEXP_USE_COMPACTING_GC +#define SEXP_USE_COMPACTING_GC 0 +#endif + #ifndef SEXP_USE_FINALIZERS #define SEXP_USE_FINALIZERS 1 #endif diff --git a/main.c b/main.c index 162c3e98..84d736c9 100644 --- a/main.c +++ b/main.c @@ -402,6 +402,8 @@ static sexp sexp_resume_ctx = SEXP_FALSE; static sexp sexp_resume_proc = SEXP_FALSE; #endif +sexp sexp_compact_heap (sexp ctx, sexp dst); + void run_main (int argc, char **argv) { #if SEXP_USE_MODULES char *impmod; @@ -617,6 +619,11 @@ void run_main (int argc, char **argv) { sexp_set_parameter(ctx, sexp_meta_env(ctx), sym=sexp_intern(ctx, sexp_argv_symbol, -1), args); if (i >= argc && main_symbol == NULL) { /* no script or main, run interactively */ +#if SEXP_USE_COMPACTING_GC + ctx = sexp_compact_heap(ctx, NULL); + sexp_context_saves(ctx) = NULL; + env = sexp_context_env(ctx); +#endif repl(ctx, env); } else { #if SEXP_USE_MODULES