forked from Mirror/wren
Make pinned list a linked list instead of hardcoded array.
This commit is contained in:
@ -1542,7 +1542,8 @@ ObjFn* wrenCompile(WrenVM* vm, const char* source)
|
||||
Compiler compiler;
|
||||
initCompiler(&compiler, &parser, NULL, 0);
|
||||
|
||||
pinObj(vm, (Obj*)compiler.fn);
|
||||
PinnedObj pinned;
|
||||
pinObj(vm, (Obj*)compiler.fn, &pinned);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@ -1563,7 +1564,7 @@ ObjFn* wrenCompile(WrenVM* vm, const char* source)
|
||||
|
||||
emit(&compiler, CODE_END);
|
||||
|
||||
unpinObj(vm, (Obj*)compiler.fn);
|
||||
unpinObj(vm);
|
||||
|
||||
return parser.hasError ? NULL : compiler.fn;
|
||||
}
|
||||
|
||||
@ -53,12 +53,13 @@ ObjClass* wrenNewClass(WrenVM* vm, ObjClass* superclass, int numFields)
|
||||
ObjClass* metaclass = newClass(vm, NULL, vm->classClass, 0);
|
||||
|
||||
// Make sure it isn't collected when we allocate the metaclass.
|
||||
pinObj(vm, (Obj*)metaclass);
|
||||
PinnedObj pinned;
|
||||
pinObj(vm, (Obj*)metaclass, &pinned);
|
||||
|
||||
ObjClass* classObj = newClass(vm, metaclass, superclass, numFields);
|
||||
classObj->numFields = numFields;
|
||||
|
||||
unpinObj(vm, (Obj*)metaclass);
|
||||
unpinObj(vm);
|
||||
|
||||
return classObj;
|
||||
}
|
||||
|
||||
@ -23,7 +23,10 @@ WrenVM* wrenNewVM(WrenReallocateFn reallocateFn)
|
||||
|
||||
// TODO(bob): Make this configurable.
|
||||
vm->nextGC = 1024 * 1024 * 10;
|
||||
vm->first = NULL;
|
||||
|
||||
vm->pinned = NULL;
|
||||
|
||||
// Clear out the global variables. This ensures they are NULL before being
|
||||
// initialized in case we do a garbage collection before one gets initialized.
|
||||
for (int i = 0; i < MAX_SYMBOLS; i++)
|
||||
@ -284,9 +287,11 @@ static void collectGarbage(WrenVM* vm)
|
||||
}
|
||||
|
||||
// Pinned objects.
|
||||
for (int j = 0; j < vm->numPinned; j++)
|
||||
PinnedObj* pinned = vm->pinned;
|
||||
while (pinned != NULL)
|
||||
{
|
||||
markObj(vm->pinned[j]);
|
||||
markObj(pinned->obj);
|
||||
pinned = pinned->previous;
|
||||
}
|
||||
|
||||
// Stack functions.
|
||||
@ -1086,14 +1091,14 @@ void callFunction(Fiber* fiber, ObjFn* fn, int numArgs)
|
||||
fiber->numFrames++;
|
||||
}
|
||||
|
||||
void pinObj(WrenVM* vm, Obj* obj)
|
||||
void pinObj(WrenVM* vm, Obj* obj, PinnedObj* pinned)
|
||||
{
|
||||
ASSERT(vm->numPinned < MAX_PINNED - 1, "Too many pinned objects.");
|
||||
vm->pinned[vm->numPinned++] = obj;
|
||||
pinned->obj = obj;
|
||||
pinned->previous = vm->pinned;
|
||||
vm->pinned = pinned;
|
||||
}
|
||||
|
||||
void unpinObj(WrenVM* vm, Obj* obj)
|
||||
void unpinObj(WrenVM* vm)
|
||||
{
|
||||
ASSERT(vm->pinned[vm->numPinned - 1] == obj, "Unpinning out of stack order.");
|
||||
vm->numPinned--;
|
||||
vm->pinned = vm->pinned->previous;
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
// TODO(bob): Make these externally controllable.
|
||||
#define STACK_SIZE 1024
|
||||
#define MAX_CALL_FRAMES 256
|
||||
#define MAX_PINNED 16
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@ -117,6 +116,23 @@ typedef struct
|
||||
int count;
|
||||
} SymbolTable;
|
||||
|
||||
// A pinned object is an Obj that has been temporarily made an explicit GC root.
|
||||
// This is for temporary or new objects that are not otherwise reachable but
|
||||
// should not be collected.
|
||||
//
|
||||
// They are organized as linked list of these objects stored on the stack. The
|
||||
// WrenVM has a pointer to the head of the list and walks it if a collection
|
||||
// occurs. This implies that pinned objects need to have stack semantics: only
|
||||
// the most recently pinned object can be unpinned.
|
||||
typedef struct sPinnedObj
|
||||
{
|
||||
// The pinned object.
|
||||
Obj* obj;
|
||||
|
||||
// The next pinned object.
|
||||
struct sPinnedObj* previous;
|
||||
} PinnedObj;
|
||||
|
||||
struct WrenVM
|
||||
{
|
||||
SymbolTable methods;
|
||||
@ -151,13 +167,9 @@ struct WrenVM
|
||||
// The first object in the linked list of all currently allocated objects.
|
||||
Obj* first;
|
||||
|
||||
// How many pinned objects are in the stack.
|
||||
int numPinned;
|
||||
|
||||
// The stack "pinned" objects. These are temporary explicit GC roots so that
|
||||
// the collector can find them before they are reachable through a normal
|
||||
// root.
|
||||
Obj* pinned[MAX_PINNED];
|
||||
// The head of the list of pinned objects. Will be `NULL` if nothing is
|
||||
// pinned.
|
||||
PinnedObj* pinned;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
@ -221,10 +233,11 @@ Value interpret(WrenVM* vm, ObjFn* fn);
|
||||
// arguments (including the receiver) to be on the top of the stack already.
|
||||
void callFunction(Fiber* fiber, ObjFn* fn, int numArgs);
|
||||
|
||||
// Mark [obj] as a GC root so that it doesn't get collected.
|
||||
void pinObj(WrenVM* vm, Obj* obj);
|
||||
// Mark [obj] as a GC root so that it doesn't get collected. Initializes
|
||||
// [pinned], which must be then passed to [unpinObj].
|
||||
void pinObj(WrenVM* vm, Obj* obj, PinnedObj* pinned);
|
||||
|
||||
// Unmark [obj] as a GC root so that it doesn't get collected.
|
||||
void unpinObj(WrenVM* vm, Obj* obj);
|
||||
// Remove the most recently pinned object from the list of pinned GC roots.
|
||||
void unpinObj(WrenVM* vm);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user