Skip to content

Commit

Permalink
replace refcount with gc root for c extensions
Browse files Browse the repository at this point in the history
Fixes #44
  • Loading branch information
p7g committed Jul 28, 2024
1 parent a3e5dbe commit 2ad754f
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 70 deletions.
52 changes: 35 additions & 17 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ inline void cb_gc_register(struct cb_gc_header *obj, size_t size,
{
obj->deinit = deinit_fn;
obj->mark = 0;
obj->refcount = 0;
obj->size = size;
obj->next = allocated;
allocated = obj;
Expand All @@ -42,18 +41,6 @@ inline int cb_gc_should_collect(void)
|| amount_allocated > next_allocation_threshold;
}

inline void cb_gc_adjust_refcount(cb_gc_header *obj, int amount)
{
obj->refcount += amount;
if (obj->refcount == 0) {
hint += 1;
if (cb_gc_should_collect()) {
DEBUG_LOG("collecting due to refcount hint");
cb_gc_collect();
}
}
}

inline void cb_gc_mark(struct cb_gc_header *obj)
{
obj->mark = 1;
Expand Down Expand Up @@ -95,6 +82,34 @@ static void evaluate_mark_queue(void)
}
}

struct cext_root {
struct cext_root *prev, *next;
struct cb_value value;
};

static struct cext_root *cext_root = NULL;

struct cext_root *cb_gc_hold(struct cb_value value)
{
struct cext_root *node = malloc(sizeof(struct cext_root));
node->prev = NULL;
node->next = cext_root;
node->value = value;
cext_root = node;
return node;
}

void cb_gc_release(struct cext_root *node)
{
if (node->prev)
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
if (node == cext_root)
cext_root = node->next;
free(node);
}

static void mark(void)
{
struct cb_module *mod;
Expand Down Expand Up @@ -133,6 +148,10 @@ static void mark(void)
cb_value_mark(&f->func);
}

DEBUG_LOG("marking c ext roots");
for (struct cext_root *node = cext_root; node; node = node->next)
cb_value_mark(&node->value);

evaluate_mark_queue();
}

Expand All @@ -145,16 +164,15 @@ static void sweep(void)
while (current) {
tmp = current;
current = current->next;
if (!tmp->mark && tmp->refcount == 0) {
if (!tmp->mark) {
*prev_ptr = tmp->next;
if (tmp->deinit)
tmp->deinit(tmp);
DEBUG_LOG("freeing object at %p", tmp);
amount_allocated -= tmp->size;
free(tmp);
} else {
DEBUG_LOG("not freeing object at %p (%s)", tmp,
tmp->mark ? "mark" : "refcount");
DEBUG_LOG("not freeing object at %p", tmp);
tmp->mark = 0;
prev_ptr = &tmp->next;
}
Expand All @@ -172,4 +190,4 @@ void cb_gc_collect(void)
DEBUG_LOG("end; allocated=%zu, collected=%zu, next collection at %zu",
amount_allocated, before - amount_allocated,
next_allocation_threshold);
}
}
8 changes: 6 additions & 2 deletions gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ typedef void (cb_deinit_fn)(void *);

typedef struct cb_gc_header {
struct cb_gc_header *next;
int refcount;
int mark;
size_t size;
cb_deinit_fn *deinit;
} cb_gc_header;

typedef struct cext_root cb_value_hold;

void cb_gc_mark(cb_gc_header *obj);
int cb_gc_is_marked(cb_gc_header *obj);
void cb_gc_adjust_refcount(cb_gc_header *obj, int amount);
Expand All @@ -25,4 +26,7 @@ void cb_gc_register(cb_gc_header *obj, size_t size, cb_deinit_fn *deinit_fn);
struct cb_value;
void cb_gc_queue_mark(struct cb_value *obj);

#endif
cb_value_hold *cb_gc_hold(struct cb_value value);
void cb_gc_release(cb_value_hold *hold);

#endif
7 changes: 5 additions & 2 deletions modules/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,10 @@ struct cb_struct_spec *get_stat_struct_spec(void)
F("mtime");
F("ctime");

cb_gc_adjust_refcount(&spec->gc_header, 1); /* Never collect it */
struct cb_value spec_value;
spec_value.type = CB_VALUE_STRUCT_SPEC;
spec_value.val.as_struct_spec = spec;
cb_gc_hold(spec_value); /* Never collect it */
return spec;
#undef F
}
Expand Down Expand Up @@ -487,4 +490,4 @@ void cb_fs_instantiate(struct cb_module *mod)
#define SET_CONST(C) CB_SET_EXPORT(mod, ident_ ## C, cb_int(C));
CONSTS(SET_CONST);
#undef SET_CONST
}
}
50 changes: 1 addition & 49 deletions value.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,54 +16,6 @@
#include "struct.h"
#include "value.h"

static void adjust_refcount(struct cb_value *value, int amount)
{
cb_gc_header *header;

switch (value->type) {
case CB_VALUE_ARRAY:
header = &value->val.as_array->gc_header;
break;
case CB_VALUE_STRING:
header = &value->val.as_string->gc_header;
break;
case CB_VALUE_BYTES:
header = &value->val.as_bytes->gc_header;
break;
case CB_VALUE_FUNCTION:
header = &value->val.as_function->gc_header;
break;
case CB_VALUE_STRUCT:
header = &value->val.as_struct->gc_header;
break;
case CB_VALUE_USERDATA:
header = &value->val.as_userdata->gc_header;
break;

default:
return;
}

if (cb_options.debug_gc) {
cb_str as_str = cb_value_to_string(value);
printf("GC: adjusted refcount by %d for object at %p: %s\n",
amount, header, cb_strptr(&as_str));
cb_str_free(as_str);
}

cb_gc_adjust_refcount(header, amount);
}

inline void cb_value_incref(struct cb_value *value)
{
adjust_refcount(value, 1);
}

inline void cb_value_decref(struct cb_value *value)
{
adjust_refcount(value, -1);
}

static void cb_function_deinit(void *ptr)
{
struct cb_user_function ufn;
Expand Down Expand Up @@ -868,4 +820,4 @@ struct cb_value cb_bytes_new_value(size_t size)
val.val.as_bytes = cb_bytes_new(size);

return val;
}
}

0 comments on commit 2ad754f

Please sign in to comment.