garbage collection

This commit is contained in:
2026-06-19 14:46:05 +02:00
parent 0e39f0e0b5
commit 8493f62a70
6 changed files with 109 additions and 3 deletions

View File

@@ -68,6 +68,7 @@ local files = {
'src/parser.c', 'src/parser.c',
'src/compiler.c', 'src/compiler.c',
'src/vm.c', 'src/vm.c',
'src/gc.c',
'src/main.c', 'src/main.c',
} }

View File

@@ -22,6 +22,7 @@ pub fn build(b: *std.Build) void {
"src/parser.c", "src/parser.c",
"src/compiler.c", "src/compiler.c",
"src/vm.c", "src/vm.c",
"src/gc.c",
"src/error.c", "src/error.c",
"src/main.c", "src/main.c",
} }

89
src/gc.c Normal file
View File

@@ -0,0 +1,89 @@
#include "noom.h"
#include "vm.h"
static void noomG_grayObj(noom_LuaVM *vm, noomV_Object *obj);
static void noomG_grayValue(noom_LuaVM *vm, noomV_Value value) {
if(value.tag != NOOMV_VOBJ) return;
noomG_grayObj(vm, value.obj);
}
static void noomG_grayObj(noom_LuaVM *vm, noomV_Object *obj) {
if(obj == 0) return;
if(obj->marked) return;
obj->marked = 1;
obj->nextGray = vm->graySet;
vm->graySet = obj;
}
void noomG_markObj(noom_LuaVM *vm, noomV_Object *obj) {
if(obj->tag == NOOMV_OPOINTER) {
noomV_Pointer *p = (noomV_Pointer *)obj;
noomG_grayValue(vm, p->value);
return;
}
if(obj->tag == NOOMV_OFUNC) {
noomV_Function *f = (noomV_Function *)obj;
noomG_grayObj(vm, &f->chunkname->obj);
noomG_grayObj(vm, &f->env->obj);
for(noom_uint_t i = 0; i < f->constsize; i++) {
noomG_grayValue(vm, f->consts[i]);
}
for(noom_uint_t i = 0; i < f->protosize; i++) {
noomG_grayObj(vm, (noomV_Object *)f->protos[i]);
}
return;
}
if(obj->tag == NOOMV_OTABLE) {
noomV_Table *t = (noomV_Table *)obj;
noomG_grayObj(vm, (noomV_Object *)t->meta);
for(noom_uint_t i = 0; i < t->entries*2; i++) {
noomG_grayValue(vm, t->entrydata[i]);
}
return;
}
if(obj->tag == NOOMV_OTHREAD) {
noomV_Thread *thrd = (noomV_Thread *)obj;
for(noom_uint_t i = 0; i < thrd->stacklen; i++) {
noomG_grayValue(vm, thrd->stack[i]);
}
for(noom_uint_t i = 0; i < thrd->calldepth; i++) {
noomV_CallFrame cf = thrd->calls[i];
noomG_grayValue(vm, cf.errhandler);
}
noomG_grayValue(vm, thrd->errObj);
noomG_grayObj(vm, (noomV_Object *)thrd->resuming);
noomG_grayObj(vm, (noomV_Object *)thrd->resumedBy);
return;
}
}
void noom_gc(noom_LuaVM* vm) {
vm->graySet = 0;
noomG_grayObj(vm, (noomV_Object *)vm->mainThread);
noomG_grayObj(vm, (noomV_Object *)vm->globals);
noomG_grayObj(vm, (noomV_Object *)vm->registry);
while(vm->graySet) {
noomG_markObj(vm, vm->graySet);
vm->graySet = vm->graySet->nextGray;
}
noomV_Object **sweep = &vm->heap;
while(*sweep) {
noomV_Object *current = *sweep;
if(current->marked) {
sweep = &current->next;
} else {
*sweep = current->next;
noomV_freeObj(vm, current);
}
}
vm->gcTarget = vm->objCount * vm->gcRatio;
}
void noom_trygc(noom_LuaVM* vm) {
if(vm->objCount >= vm->gcTarget) noom_gc(vm);
}

View File

@@ -299,6 +299,11 @@ noom_Exit noom_cast2str(noom_LuaVM* vm, noom_slot_t x);
// DO NOT RUN IN THE ALLOCATOR IF ANY IS SUPPLIED, OR YOU WILL GET THE WORST POSSIBLE ERRORS. // DO NOT RUN IN THE ALLOCATOR IF ANY IS SUPPLIED, OR YOU WILL GET THE WORST POSSIBLE ERRORS.
void noom_gc(noom_LuaVM* vm); void noom_gc(noom_LuaVM* vm);
// Like [noom_gc], except it will only do things if the GC feels like it.
// You can sneak this in your long-running C functions to reduce memory usage
// without destroying this CPU.
void noom_trygc(noom_LuaVM* vm);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -163,6 +163,7 @@ noomV_Object* noomV_allocObj(noom_LuaVM* vm, noomV_ObjTag tag, noom_uint_t size)
o->next = vm->heap; o->next = vm->heap;
o->nextGray = 0; o->nextGray = 0;
vm->heap = o; vm->heap = o;
vm->objCount++;
return o; return o;
} }
@@ -444,7 +445,7 @@ noom_Exit noomV_setErrorFromExit(noom_LuaVM *vm, noomV_Thread *coro, noom_Exit e
return exit; return exit;
} }
void noomV_freeObj(noomV_Object* obj) { void noomV_freeObj(noom_LuaVM *vm, noomV_Object* obj) {
if(obj->tag == NOOMV_OFUNC) { if(obj->tag == NOOMV_OFUNC) {
noomV_Function *f = (noomV_Function *)obj; noomV_Function *f = (noomV_Function *)obj;
noom_free(f->consts); noom_free(f->consts);
@@ -462,6 +463,7 @@ void noomV_freeObj(noomV_Object* obj) {
noom_free(thrd->calls); noom_free(thrd->calls);
} }
noom_free(obj); noom_free(obj);
vm->objCount--;
} }
noom_Exit noomV_pushCallFrame(noom_LuaVM *vm, noomV_Thread *coro, noomV_CallFrame cf); noom_Exit noomV_pushCallFrame(noom_LuaVM *vm, noomV_Thread *coro, noomV_CallFrame cf);
@@ -513,6 +515,9 @@ noom_LuaVM* noom_createVM(noom_LuaVersion version) {
vm->mainThread = 0; vm->mainThread = 0;
vm->currentThread = 0; vm->currentThread = 0;
vm->version = version; vm->version = version;
vm->objCount = 0;
vm->gcTarget = 100;
vm->gcRatio = 2;
const char *oomStr = "out of memory"; const char *oomStr = "out of memory";
vm->oomVal.obj = (noomV_Object *)noomV_allocStr(vm, oomStr, noom_strlen(oomStr)); vm->oomVal.obj = (noomV_Object *)noomV_allocStr(vm, oomStr, noom_strlen(oomStr));
@@ -539,6 +544,8 @@ noom_LuaVM* noom_createVM(noom_LuaVersion version) {
assert(noomV_rawequalValue(noomV_rawgetTable(vm->registry, _GKey), _GVal)); assert(noomV_rawequalValue(noomV_rawgetTable(vm->registry, _GKey), _GVal));
noom_gc(vm);
return vm; return vm;
rip: rip:
noom_destroyVM(vm); noom_destroyVM(vm);
@@ -550,7 +557,7 @@ void noom_destroyVM(noom_LuaVM* vm) {
while (iter) { while (iter) {
noomV_Object* cur = iter; noomV_Object* cur = iter;
iter = iter->next; iter = iter->next;
noomV_freeObj(cur); noomV_freeObj(vm, cur);
} }
noom_free(vm); noom_free(vm);
} }

View File

@@ -352,6 +352,9 @@ struct noom_LuaVM {
noomV_Thread* mainThread; noomV_Thread* mainThread;
noomV_Thread* currentThread; noomV_Thread* currentThread;
noom_LuaVersion version; noom_LuaVersion version;
noom_uint_t objCount;
noom_uint_t gcTarget;
double gcRatio;
}; };
// for conveniently passing around nil // for conveniently passing around nil
@@ -379,7 +382,7 @@ void noomV_setErrorStr(noom_LuaVM *vm, noomV_Thread *coro, const char *str);
// Returns the exit for convenience // Returns the exit for convenience
noom_Exit noomV_setErrorFromExit(noom_LuaVM *vm, noomV_Thread *coro, noom_Exit exit); noom_Exit noomV_setErrorFromExit(noom_LuaVM *vm, noomV_Thread *coro, noom_Exit exit);
void noomV_freeObj(noomV_Object* obj); void noomV_freeObj(noom_LuaVM *vm, noomV_Object* obj);
noom_Exit noomV_pushCallFrame(noom_LuaVM *vm, noomV_Thread *coro, noomV_CallFrame cf); noom_Exit noomV_pushCallFrame(noom_LuaVM *vm, noomV_Thread *coro, noomV_CallFrame cf);