diff --git a/src/core/gc.c b/src/core/gc.c index 2b90d850..11be1522 100644 --- a/src/core/gc.c +++ b/src/core/gc.c @@ -31,10 +31,11 @@ JANET_THREAD_LOCAL uint32_t janet_vm_gc_interval; JANET_THREAD_LOCAL uint32_t janet_vm_next_collection; JANET_THREAD_LOCAL int janet_vm_gc_suspend = 0; -/* Roots */ -JANET_THREAD_LOCAL Janet *janet_vm_roots; -JANET_THREAD_LOCAL uint32_t janet_vm_root_count; -JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity; +/* GC mark state */ +JANET_THREAD_LOCAL Janet *janet_vm_gc_marklist = NULL; +JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_count = 0; +JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_capacity = 0; +JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_rootcount = 0; /* Helpers for marking the various gc types */ static void janet_mark_funcenv(JanetFuncEnv *env); @@ -49,21 +50,17 @@ static void janet_mark_string(const uint8_t *str); static void janet_mark_fiber(JanetFiber *fiber); static void janet_mark_abstract(void *adata); -/* Mark a value */ +/* Mark a value (Pushes it to the black list).*/ void janet_mark(Janet x) { - switch (janet_type(x)) { - default: break; - case JANET_STRING: - case JANET_SYMBOL: janet_mark_string(janet_unwrap_string(x)); break; - case JANET_FUNCTION: janet_mark_function(janet_unwrap_function(x)); break; - case JANET_ARRAY: janet_mark_array(janet_unwrap_array(x)); break; - case JANET_TABLE: janet_mark_table(janet_unwrap_table(x)); break; - case JANET_STRUCT: janet_mark_struct(janet_unwrap_struct(x)); break; - case JANET_TUPLE: janet_mark_tuple(janet_unwrap_tuple(x)); break; - case JANET_BUFFER: janet_mark_buffer(janet_unwrap_buffer(x)); break; - case JANET_FIBER: janet_mark_fiber(janet_unwrap_fiber(x)); break; - case JANET_ABSTRACT: janet_mark_abstract(janet_unwrap_abstract(x)); break; + if (janet_vm_gc_marklist_count >= janet_vm_gc_marklist_capacity) { + janet_vm_gc_marklist_capacity = (3 * janet_vm_gc_marklist_count) / 2 + 1; + janet_vm_gc_marklist = realloc(janet_vm_gc_marklist, + janet_vm_gc_marklist_capacity * sizeof(Janet)); + if (NULL == janet_vm_gc_marklist) { + JANET_OUT_OF_MEMORY; + } } + janet_vm_gc_marklist[janet_vm_gc_marklist_count++] = x; } static void janet_mark_string(const uint8_t *str) { @@ -86,10 +83,8 @@ static void janet_mark_abstract(void *adata) { /* Mark a bunch of items in memory */ static void janet_mark_many(const Janet *values, int32_t n) { const Janet *end = values + n; - while (values < end) { - janet_mark(*values); - values += 1; - } + while (values < end) + janet_mark(*values++); } /* Mark a bunch of key values items in memory */ @@ -315,10 +310,28 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) { /* Run garbage collection */ void janet_collect(void) { - uint32_t i; + size_t i; if (janet_vm_gc_suspend) return; - for (i = 0; i < janet_vm_root_count; i++) - janet_mark(janet_vm_roots[i]); + /* Mark the roots */ + for (i = 0; i < janet_vm_gc_marklist_rootcount; i++) + janet_mark(janet_vm_gc_marklist[i]); + /* While list not empty */ + while (janet_vm_gc_marklist_count > janet_vm_gc_marklist_rootcount) { + Janet x = janet_vm_gc_marklist[--janet_vm_gc_marklist_count]; + switch (janet_type(x)) { + default: break; + case JANET_STRING: + case JANET_SYMBOL: janet_mark_string(janet_unwrap_string(x)); break; + case JANET_FUNCTION: janet_mark_function(janet_unwrap_function(x)); break; + case JANET_ARRAY: janet_mark_array(janet_unwrap_array(x)); break; + case JANET_TABLE: janet_mark_table(janet_unwrap_table(x)); break; + case JANET_STRUCT: janet_mark_struct(janet_unwrap_struct(x)); break; + case JANET_TUPLE: janet_mark_tuple(janet_unwrap_tuple(x)); break; + case JANET_BUFFER: janet_mark_buffer(janet_unwrap_buffer(x)); break; + case JANET_FIBER: janet_mark_fiber(janet_unwrap_fiber(x)); break; + case JANET_ABSTRACT: janet_mark_abstract(janet_unwrap_abstract(x)); break; + } + } janet_sweep(); janet_vm_next_collection = 0; } @@ -327,17 +340,8 @@ void janet_collect(void) { * and all of its children. If gcroot is called on a value n times, unroot * must also be called n times to remove it as a gc root. */ void janet_gcroot(Janet root) { - uint32_t newcount = janet_vm_root_count + 1; - if (newcount > janet_vm_root_capacity) { - uint32_t newcap = 2 * newcount; - janet_vm_roots = realloc(janet_vm_roots, sizeof(Janet) * newcap); - if (NULL == janet_vm_roots) { - JANET_OUT_OF_MEMORY; - } - janet_vm_root_capacity = newcap; - } - janet_vm_roots[janet_vm_root_count] = root; - janet_vm_root_count = newcount; + janet_mark(root); + janet_vm_gc_marklist_rootcount++; } /* Identity equality for GC purposes */ @@ -361,12 +365,12 @@ static int janet_gc_idequals(Janet lhs, Janet rhs) { /* Remove a root value from the GC. This allows the gc to potentially reclaim * a value and all its children. */ int janet_gcunroot(Janet root) { - Janet *vtop = janet_vm_roots + janet_vm_root_count; - Janet *v = janet_vm_roots; + Janet *vtop = janet_vm_gc_marklist + janet_vm_gc_marklist_rootcount; + Janet *v = janet_vm_gc_marklist; /* Search from top to bottom as access is most likely LIFO */ - for (v = janet_vm_roots; v < vtop; v++) { + for (v = janet_vm_gc_marklist; v < vtop; v++) { if (janet_gc_idequals(root, *v)) { - *v = janet_vm_roots[--janet_vm_root_count]; + *v = janet_vm_gc_marklist[--janet_vm_gc_marklist_rootcount]; return 1; } } @@ -375,13 +379,13 @@ int janet_gcunroot(Janet root) { /* Remove a root value from the GC. This sets the effective reference count to 0. */ int janet_gcunrootall(Janet root) { - Janet *vtop = janet_vm_roots + janet_vm_root_count; - Janet *v = janet_vm_roots; + Janet *vtop = janet_vm_gc_marklist + janet_vm_gc_marklist_rootcount; + Janet *v = janet_vm_gc_marklist; int ret = 0; /* Search from top to bottom as access is most likely LIFO */ - for (v = janet_vm_roots; v < vtop; v++) { + for (v = janet_vm_gc_marklist; v < vtop; v++) { if (janet_gc_idequals(root, *v)) { - *v = janet_vm_roots[--janet_vm_root_count]; + *v = janet_vm_gc_marklist[--janet_vm_gc_marklist_rootcount]; vtop--; ret = 1; } diff --git a/src/core/state.h b/src/core/state.h index 32f2c738..5b669ac7 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -55,9 +55,9 @@ extern JANET_THREAD_LOCAL uint32_t janet_vm_gc_interval; extern JANET_THREAD_LOCAL uint32_t janet_vm_next_collection; extern JANET_THREAD_LOCAL int janet_vm_gc_suspend; -/* GC roots */ -extern JANET_THREAD_LOCAL Janet *janet_vm_roots; -extern JANET_THREAD_LOCAL uint32_t janet_vm_root_count; -extern JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity; +extern JANET_THREAD_LOCAL Janet *janet_vm_gc_marklist; +extern JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_count; +extern JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_capacity; +extern JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_rootcount; #endif /* JANET_STATE_H_defined */ diff --git a/src/core/vm.c b/src/core/vm.c index 4aa2e2fa..6ea0dcb2 100644 --- a/src/core/vm.c +++ b/src/core/vm.c @@ -1335,10 +1335,11 @@ int janet_init(void) { * there are no memory bugs during development */ janet_vm_gc_interval = 0x1000000; janet_symcache_init(); - /* Initialize gc roots */ - janet_vm_roots = NULL; - janet_vm_root_count = 0; - janet_vm_root_capacity = 0; + /* Initialize gc list */ + janet_vm_gc_marklist = NULL; + janet_vm_gc_marklist_count = 0; + janet_vm_gc_marklist_capacity = 0; + janet_vm_gc_marklist_rootcount = 0; /* Initialize registry */ janet_vm_registry = janet_table(0); janet_gcroot(janet_wrap_table(janet_vm_registry)); @@ -1349,9 +1350,7 @@ int janet_init(void) { void janet_deinit(void) { janet_clear_memory(); janet_symcache_deinit(); - free(janet_vm_roots); - janet_vm_roots = NULL; - janet_vm_root_count = 0; - janet_vm_root_capacity = 0; + free(janet_vm_gc_marklist); + janet_vm_gc_marklist = NULL; janet_vm_registry = NULL; }