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:
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user