feat: add configurable heap growth, initial, and minimum heap size to WrenVM
Replace the single `WrenReallocateFn` parameter in `wrenNewVM` with a `WrenConfiguration` struct containing `reallocateFn`, `initialHeapSize`, `minHeapSize`, and `heapGrowthPercent` fields. Update the VM to use these values for GC thresholds instead of hardcoded constants, and modify the CLI entry point to pass a configuration with a 100MB initial heap.
This commit is contained in:
+19
-14
@@ -49,15 +49,9 @@ static char* readFile(const char* path)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void* reallocate(void* memory, size_t oldSize, size_t newSize)
|
||||
{
|
||||
return realloc(memory, newSize);
|
||||
}
|
||||
|
||||
static int runFile(const char* path)
|
||||
static int runFile(WrenVM* vm, const char* path)
|
||||
{
|
||||
char* source = readFile(path);
|
||||
WrenVM* vm = wrenNewVM(reallocate);
|
||||
|
||||
int result = wrenInterpret(vm, source);
|
||||
|
||||
@@ -67,10 +61,8 @@ static int runFile(const char* path)
|
||||
return result;
|
||||
}
|
||||
|
||||
static int runRepl()
|
||||
static int runRepl(WrenVM* vm)
|
||||
{
|
||||
WrenVM* vm = wrenNewVM(reallocate);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
printf("> ");
|
||||
@@ -99,9 +91,22 @@ static int runRepl()
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc == 1) return runRepl();
|
||||
if (argc == 2) return runFile(argv[1]);
|
||||
if (argc < 1 || argc > 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: wren [file]");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Usage: wren [file]");
|
||||
return 1;
|
||||
WrenConfiguration config = {
|
||||
.reallocateFn = NULL,
|
||||
.heapGrowthPercent = 0,
|
||||
.minHeapSize = 0,
|
||||
// Since we're running in a separate process, be generous with memory.
|
||||
.initialHeapSize = 1024 * 1024 * 100
|
||||
};
|
||||
|
||||
WrenVM* vm = wrenNewVM(&config);
|
||||
|
||||
if (argc == 1) return runRepl(vm);
|
||||
if (argc == 2) return runFile(vm, argv[1]);
|
||||
}
|
||||
|
||||
+40
-8
@@ -9,23 +9,54 @@
|
||||
#include "wren_vm.h"
|
||||
#include "wren_debug.h"
|
||||
|
||||
WrenVM* wrenNewVM(WrenReallocateFn reallocateFn)
|
||||
// The built-in reallocation function used when one is not provided by the
|
||||
// configuration.
|
||||
static void* defaultReallocate(void* memory, size_t oldSize, size_t newSize)
|
||||
{
|
||||
WrenVM* vm = reallocateFn(NULL, 0, sizeof(WrenVM));
|
||||
return realloc(memory, newSize);
|
||||
}
|
||||
|
||||
WrenVM* wrenNewVM(WrenConfiguration* configuration)
|
||||
{
|
||||
WrenReallocateFn reallocate = defaultReallocate;
|
||||
if (configuration->reallocateFn != NULL)
|
||||
{
|
||||
reallocate = configuration->reallocateFn;
|
||||
}
|
||||
|
||||
WrenVM* vm = reallocate(NULL, 0, sizeof(WrenVM));
|
||||
initSymbolTable(&vm->methods);
|
||||
initSymbolTable(&vm->globalSymbols);
|
||||
|
||||
vm->fiber = reallocateFn(NULL, 0, sizeof(Fiber));
|
||||
vm->fiber = reallocate(NULL, 0, sizeof(Fiber));
|
||||
vm->fiber->stackSize = 0;
|
||||
vm->fiber->numFrames = 0;
|
||||
vm->fiber->openUpvalues = NULL;
|
||||
|
||||
vm->bytesAllocated = 0;
|
||||
|
||||
// TODO: Make this configurable.
|
||||
vm->nextGC = 1024 * 1024 * 100;
|
||||
vm->first = NULL;
|
||||
vm->nextGC = 1024 * 1024 * 10;
|
||||
if (configuration->initialHeapSize != 0)
|
||||
{
|
||||
vm->nextGC = configuration->initialHeapSize;
|
||||
}
|
||||
|
||||
vm->minNextGC = 1024 * 1024;
|
||||
if (configuration->minHeapSize != 0)
|
||||
{
|
||||
vm->minNextGC = configuration->minHeapSize;
|
||||
}
|
||||
|
||||
vm->heapScalePercent = 150;
|
||||
if (configuration->heapGrowthPercent != 0)
|
||||
{
|
||||
// +100 here because the configuration gives us the *additional* size of
|
||||
// the heap relative to the in-use memory, while heapScalePercent is the
|
||||
// *total* size of the heap relative to in-use.
|
||||
vm->heapScalePercent = 100 + configuration->heapGrowthPercent;
|
||||
}
|
||||
|
||||
vm->first = NULL;
|
||||
vm->pinned = NULL;
|
||||
|
||||
// Clear out the global variables. This ensures they are NULL before being
|
||||
@@ -35,7 +66,7 @@ WrenVM* wrenNewVM(WrenReallocateFn reallocateFn)
|
||||
vm->globals[i] = NULL_VAL;
|
||||
}
|
||||
|
||||
vm->reallocate = reallocateFn;
|
||||
vm->reallocate = reallocate;
|
||||
|
||||
wrenInitializeCore(vm);
|
||||
|
||||
@@ -88,7 +119,8 @@ void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize)
|
||||
#endif
|
||||
|
||||
collectGarbage(vm);
|
||||
vm->nextGC = vm->bytesAllocated * 3 / 2;
|
||||
vm->nextGC = vm->bytesAllocated * vm->heapScalePercent / 100;
|
||||
if (vm->nextGC < vm->minNextGC) vm->nextGC = vm->minNextGC;
|
||||
|
||||
#if WREN_TRACE_MEMORY
|
||||
printf("GC %ld before, %ld after (%ld collected), next at %ld\n",
|
||||
|
||||
@@ -222,6 +222,14 @@ struct WrenVM
|
||||
// The number of total allocated bytes that will trigger the next GC.
|
||||
size_t nextGC;
|
||||
|
||||
// The minimum value for [nextGC] when recalculated after a collection.
|
||||
size_t minNextGC;
|
||||
|
||||
// The scale factor used to calculate [nextGC] from the current number of in
|
||||
// use bytes, as a percent. For example, 150 here means that nextGC will be
|
||||
// 50% larger than the current number of in-use bytes.
|
||||
int heapScalePercent;
|
||||
|
||||
// The first object in the linked list of all currently allocated objects.
|
||||
Obj* first;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user