mirror of
https://github.com/janet-lang/janet
synced 2025-01-25 22:56:52 +00:00
Garbage collection no longer blows stack.
This commit is contained in:
parent
486ce6bc81
commit
d9752a9028
@ -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 uint32_t janet_vm_next_collection;
|
||||||
JANET_THREAD_LOCAL int janet_vm_gc_suspend = 0;
|
JANET_THREAD_LOCAL int janet_vm_gc_suspend = 0;
|
||||||
|
|
||||||
/* Roots */
|
/* GC mark state */
|
||||||
JANET_THREAD_LOCAL Janet *janet_vm_roots;
|
JANET_THREAD_LOCAL Janet *janet_vm_gc_marklist = NULL;
|
||||||
JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
|
JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_count = 0;
|
||||||
JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
|
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 */
|
/* Helpers for marking the various gc types */
|
||||||
static void janet_mark_funcenv(JanetFuncEnv *env);
|
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_fiber(JanetFiber *fiber);
|
||||||
static void janet_mark_abstract(void *adata);
|
static void janet_mark_abstract(void *adata);
|
||||||
|
|
||||||
/* Mark a value */
|
/* Mark a value (Pushes it to the black list).*/
|
||||||
void janet_mark(Janet x) {
|
void janet_mark(Janet x) {
|
||||||
switch (janet_type(x)) {
|
if (janet_vm_gc_marklist_count >= janet_vm_gc_marklist_capacity) {
|
||||||
default: break;
|
janet_vm_gc_marklist_capacity = (3 * janet_vm_gc_marklist_count) / 2 + 1;
|
||||||
case JANET_STRING:
|
janet_vm_gc_marklist = realloc(janet_vm_gc_marklist,
|
||||||
case JANET_SYMBOL: janet_mark_string(janet_unwrap_string(x)); break;
|
janet_vm_gc_marklist_capacity * sizeof(Janet));
|
||||||
case JANET_FUNCTION: janet_mark_function(janet_unwrap_function(x)); break;
|
if (NULL == janet_vm_gc_marklist) {
|
||||||
case JANET_ARRAY: janet_mark_array(janet_unwrap_array(x)); break;
|
JANET_OUT_OF_MEMORY;
|
||||||
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_vm_gc_marklist[janet_vm_gc_marklist_count++] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void janet_mark_string(const uint8_t *str) {
|
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 */
|
/* Mark a bunch of items in memory */
|
||||||
static void janet_mark_many(const Janet *values, int32_t n) {
|
static void janet_mark_many(const Janet *values, int32_t n) {
|
||||||
const Janet *end = values + n;
|
const Janet *end = values + n;
|
||||||
while (values < end) {
|
while (values < end)
|
||||||
janet_mark(*values);
|
janet_mark(*values++);
|
||||||
values += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark a bunch of key values items in memory */
|
/* 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 */
|
/* Run garbage collection */
|
||||||
void janet_collect(void) {
|
void janet_collect(void) {
|
||||||
uint32_t i;
|
size_t i;
|
||||||
if (janet_vm_gc_suspend) return;
|
if (janet_vm_gc_suspend) return;
|
||||||
for (i = 0; i < janet_vm_root_count; i++)
|
/* Mark the roots */
|
||||||
janet_mark(janet_vm_roots[i]);
|
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_sweep();
|
||||||
janet_vm_next_collection = 0;
|
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
|
* 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. */
|
* must also be called n times to remove it as a gc root. */
|
||||||
void janet_gcroot(Janet root) {
|
void janet_gcroot(Janet root) {
|
||||||
uint32_t newcount = janet_vm_root_count + 1;
|
janet_mark(root);
|
||||||
if (newcount > janet_vm_root_capacity) {
|
janet_vm_gc_marklist_rootcount++;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Identity equality for GC purposes */
|
/* 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
|
/* Remove a root value from the GC. This allows the gc to potentially reclaim
|
||||||
* a value and all its children. */
|
* a value and all its children. */
|
||||||
int janet_gcunroot(Janet root) {
|
int janet_gcunroot(Janet root) {
|
||||||
Janet *vtop = janet_vm_roots + janet_vm_root_count;
|
Janet *vtop = janet_vm_gc_marklist + janet_vm_gc_marklist_rootcount;
|
||||||
Janet *v = janet_vm_roots;
|
Janet *v = janet_vm_gc_marklist;
|
||||||
/* Search from top to bottom as access is most likely LIFO */
|
/* 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)) {
|
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;
|
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. */
|
/* Remove a root value from the GC. This sets the effective reference count to 0. */
|
||||||
int janet_gcunrootall(Janet root) {
|
int janet_gcunrootall(Janet root) {
|
||||||
Janet *vtop = janet_vm_roots + janet_vm_root_count;
|
Janet *vtop = janet_vm_gc_marklist + janet_vm_gc_marklist_rootcount;
|
||||||
Janet *v = janet_vm_roots;
|
Janet *v = janet_vm_gc_marklist;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
/* Search from top to bottom as access is most likely LIFO */
|
/* 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)) {
|
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--;
|
vtop--;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
|
@ -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 uint32_t janet_vm_next_collection;
|
||||||
extern JANET_THREAD_LOCAL int janet_vm_gc_suspend;
|
extern JANET_THREAD_LOCAL int janet_vm_gc_suspend;
|
||||||
|
|
||||||
/* GC roots */
|
extern JANET_THREAD_LOCAL Janet *janet_vm_gc_marklist;
|
||||||
extern JANET_THREAD_LOCAL Janet *janet_vm_roots;
|
extern JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_count;
|
||||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
|
extern JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_capacity;
|
||||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
|
extern JANET_THREAD_LOCAL size_t janet_vm_gc_marklist_rootcount;
|
||||||
|
|
||||||
#endif /* JANET_STATE_H_defined */
|
#endif /* JANET_STATE_H_defined */
|
||||||
|
@ -1335,10 +1335,11 @@ int janet_init(void) {
|
|||||||
* there are no memory bugs during development */
|
* there are no memory bugs during development */
|
||||||
janet_vm_gc_interval = 0x1000000;
|
janet_vm_gc_interval = 0x1000000;
|
||||||
janet_symcache_init();
|
janet_symcache_init();
|
||||||
/* Initialize gc roots */
|
/* Initialize gc list */
|
||||||
janet_vm_roots = NULL;
|
janet_vm_gc_marklist = NULL;
|
||||||
janet_vm_root_count = 0;
|
janet_vm_gc_marklist_count = 0;
|
||||||
janet_vm_root_capacity = 0;
|
janet_vm_gc_marklist_capacity = 0;
|
||||||
|
janet_vm_gc_marklist_rootcount = 0;
|
||||||
/* Initialize registry */
|
/* Initialize registry */
|
||||||
janet_vm_registry = janet_table(0);
|
janet_vm_registry = janet_table(0);
|
||||||
janet_gcroot(janet_wrap_table(janet_vm_registry));
|
janet_gcroot(janet_wrap_table(janet_vm_registry));
|
||||||
@ -1349,9 +1350,7 @@ int janet_init(void) {
|
|||||||
void janet_deinit(void) {
|
void janet_deinit(void) {
|
||||||
janet_clear_memory();
|
janet_clear_memory();
|
||||||
janet_symcache_deinit();
|
janet_symcache_deinit();
|
||||||
free(janet_vm_roots);
|
free(janet_vm_gc_marklist);
|
||||||
janet_vm_roots = NULL;
|
janet_vm_gc_marklist = NULL;
|
||||||
janet_vm_root_count = 0;
|
|
||||||
janet_vm_root_capacity = 0;
|
|
||||||
janet_vm_registry = NULL;
|
janet_vm_registry = NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user