1
0
forked from Mirror/wren

Tweak a few things in the new GC.

- Make sure it handles an empty gray set.
- Make sure growing the gray stack doesn't itself trigger a GC.
- Make sure it works when stress testing is enabled.
- Ensure the tests kick off a GC.
This commit is contained in:
Bob Nystrom
2015-10-29 07:38:09 -07:00
parent 25bd182c58
commit 2ff8acbe1a
5 changed files with 22 additions and 24 deletions

View File

@ -867,15 +867,14 @@ void wrenGrayObj(WrenVM* vm, Obj* obj)
// Add it to the gray list so it can be recursively explored for // Add it to the gray list so it can be recursively explored for
// more marks later. // more marks later.
if (vm->grayDepth >= vm->maxGray) if (vm->grayCount >= vm->grayCapacity)
{ {
size_t oldSize = vm->maxGray * sizeof(Obj*); vm->grayCapacity = vm->grayCount * 2;
size_t newSize = vm->grayDepth * 2 * sizeof(Obj*); vm->gray = vm->config.reallocateFn(vm->gray,
vm->gray = (Obj**)wrenReallocate(vm, vm->gray, oldSize, newSize); vm->grayCapacity * sizeof(Obj*));
vm->maxGray = vm->grayDepth * 2;
} }
vm->gray[vm->grayDepth++] = obj; vm->gray[vm->grayCount++] = obj;
} }
void wrenGrayValue(WrenVM* vm, Value value) void wrenGrayValue(WrenVM* vm, Value value)
@ -1095,12 +1094,12 @@ static void blackenObject(WrenVM* vm, Obj* obj)
void wrenBlackenObjects(WrenVM* vm) void wrenBlackenObjects(WrenVM* vm)
{ {
do while (vm->grayCount > 0)
{ {
// Pop an item from the gray stack. // Pop an item from the gray stack.
Obj* obj = vm->gray[--vm->grayDepth]; Obj* obj = vm->gray[--vm->grayCount];
blackenObject(vm, obj); blackenObject(vm, obj);
} while (vm->grayDepth > 0); }
} }
void wrenFreeObj(WrenVM* vm, Obj* obj) void wrenFreeObj(WrenVM* vm, Obj* obj)

View File

@ -46,29 +46,25 @@ void wrenInitConfiguration(WrenConfiguration* config)
config->heapGrowthPercent = 50; config->heapGrowthPercent = 50;
} }
static void initializeGC(WrenVM* vm)
{
vm->gray = (Obj**)wrenReallocate(vm, NULL, 0, 5 * sizeof(Obj*));
vm->grayDepth = 0;
vm->maxGray = 5;
}
WrenVM* wrenNewVM(WrenConfiguration* config) WrenVM* wrenNewVM(WrenConfiguration* config)
{ {
WrenVM* vm = (WrenVM*)config->reallocateFn(NULL, sizeof(*vm)); WrenVM* vm = (WrenVM*)config->reallocateFn(NULL, sizeof(*vm));
memset(vm, 0, sizeof(WrenVM)); memset(vm, 0, sizeof(WrenVM));
memcpy(&vm->config, config, sizeof(WrenConfiguration)); memcpy(&vm->config, config, sizeof(WrenConfiguration));
// TODO: Should we allocate and free this during a GC?
vm->grayCount = 0;
// TODO: Tune this.
vm->grayCapacity = 4;
vm->gray = vm->config.reallocateFn(NULL, vm->grayCapacity * sizeof(Obj*));
vm->nextGC = config->initialHeapSize; vm->nextGC = config->initialHeapSize;
wrenSymbolTableInit(&vm->methodNames); wrenSymbolTableInit(&vm->methodNames);
vm->modules = wrenNewMap(vm); vm->modules = wrenNewMap(vm);
wrenInitializeCore(vm); wrenInitializeCore(vm);
initializeGC(vm);
// TODO: Lazy load these. // TODO: Lazy load these.
#if WREN_OPT_META #if WREN_OPT_META
wrenLoadMetaModule(vm); wrenLoadMetaModule(vm);
@ -94,7 +90,7 @@ void wrenFreeVM(WrenVM* vm)
} }
// Free up the GC gray set. // Free up the GC gray set.
wrenReallocate(vm, vm->gray, vm->maxGray * sizeof(Obj*), 0); vm->gray = vm->config.reallocateFn(vm->gray, 0);
// Tell the user if they didn't free any handles. We don't want to just free // Tell the user if they didn't free any handles. We don't want to just free
// them here because the host app may still have pointers to them that they // them here because the host app may still have pointers to them that they

View File

@ -72,8 +72,8 @@ struct WrenVM
// The "gray" set for the garbage collector. This is the stack of unprocessed // The "gray" set for the garbage collector. This is the stack of unprocessed
// objects while a garbage collection pass is in process. // objects while a garbage collection pass is in process.
Obj** gray; Obj** gray;
int grayDepth; int grayCount;
int maxGray; int grayCapacity;
// The list of temporary roots. This is for temporary or new objects that are // The list of temporary roots. This is for temporary or new objects that are
// not otherwise reachable but should not be collected. // not otherwise reachable but should not be collected.

View File

@ -4,4 +4,5 @@ for (i in 1..400000) {
head = { "next" : head } head = { "next" : head }
} }
System.print("done") // expect: done System.gc()
System.print("done") // expect: done

View File

@ -10,5 +10,7 @@ for (i in 1..1000) {
} }
found.add(bar) found.add(bar)
} }
System.gc()
System.print(found.all {|i| i == 1337}) // expect: true System.print(found.all {|i| i == 1337}) // expect: true
System.print("DONE!") // expect: DONE! System.print("done") // expect: done