Add an API for storing handles to values outside of the VM.
It's pretty bare bones now, but it lets you get a reference to an object from a foreign call and then return it later.
This commit is contained in:
+66
-11
@@ -112,11 +112,12 @@ void wrenFreeVM(WrenVM* vm)
|
||||
obj = next;
|
||||
}
|
||||
|
||||
// Tell the user if they didn't free any method handles. We don't want to
|
||||
// just free them here because the host app may still have pointers to them
|
||||
// that they may try to use. Better to tell them about the bug early.
|
||||
// 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
|
||||
// may try to use. Better to tell them about the bug early.
|
||||
ASSERT(vm->methodHandles == NULL, "All methods have not been released.");
|
||||
|
||||
ASSERT(vm->valueHandles == NULL, "All values have not been released.");
|
||||
|
||||
wrenSymbolTableClear(vm, &vm->methodNames);
|
||||
|
||||
DEALLOCATE(vm, vm);
|
||||
@@ -166,6 +167,14 @@ static void collectGarbage(WrenVM* vm)
|
||||
{
|
||||
wrenMarkObj(vm, (Obj*)handle->fiber);
|
||||
}
|
||||
|
||||
// The value handles.
|
||||
for (WrenValue* value = vm->valueHandles;
|
||||
value != NULL;
|
||||
value = value->next)
|
||||
{
|
||||
wrenMarkValue(vm, value->value);
|
||||
}
|
||||
|
||||
// Any object the compiler is using (if there is one).
|
||||
if (vm->compiler != NULL) wrenMarkCompiler(vm, vm->compiler);
|
||||
@@ -1289,6 +1298,25 @@ void wrenReleaseMethod(WrenVM* vm, WrenMethod* method)
|
||||
DEALLOCATE(vm, method);
|
||||
}
|
||||
|
||||
void wrenReleaseValue(WrenVM* vm, WrenValue* value)
|
||||
{
|
||||
ASSERT(value != NULL, "NULL value.");
|
||||
|
||||
// Update the VM's head pointer if we're releasing the first handle.
|
||||
if (vm->valueHandles == value) vm->valueHandles = value->next;
|
||||
|
||||
// Unlink it from the list.
|
||||
if (value->prev != NULL) value->prev->next = value->next;
|
||||
if (value->next != NULL) value->next->prev = value->prev;
|
||||
|
||||
// Clear it out. This isn't strictly necessary since we're going to free it,
|
||||
// but it makes for easier debugging.
|
||||
value->prev = NULL;
|
||||
value->next = NULL;
|
||||
value->value = NULL_VAL;
|
||||
DEALLOCATE(vm, value);
|
||||
}
|
||||
|
||||
// Execute [source] in the context of the core module.
|
||||
static WrenInterpretResult loadIntoCore(WrenVM* vm, const char* source)
|
||||
{
|
||||
@@ -1426,11 +1454,16 @@ void wrenPopRoot(WrenVM* vm)
|
||||
vm->numTempRoots--;
|
||||
}
|
||||
|
||||
bool wrenGetArgumentBool(WrenVM* vm, int index)
|
||||
static void validateForeignArgument(WrenVM* vm, int index)
|
||||
{
|
||||
ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call.");
|
||||
ASSERT(index >= 0, "index cannot be negative.");
|
||||
ASSERT(index < vm->foreignCallNumArgs, "Not that many arguments.");
|
||||
}
|
||||
|
||||
bool wrenGetArgumentBool(WrenVM* vm, int index)
|
||||
{
|
||||
validateForeignArgument(vm, index);
|
||||
|
||||
if (!IS_BOOL(*(vm->foreignCallSlot + index))) return false;
|
||||
|
||||
@@ -1439,9 +1472,7 @@ bool wrenGetArgumentBool(WrenVM* vm, int index)
|
||||
|
||||
double wrenGetArgumentDouble(WrenVM* vm, int index)
|
||||
{
|
||||
ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call.");
|
||||
ASSERT(index >= 0, "index cannot be negative.");
|
||||
ASSERT(index < vm->foreignCallNumArgs, "Not that many arguments.");
|
||||
validateForeignArgument(vm, index);
|
||||
|
||||
if (!IS_NUM(*(vm->foreignCallSlot + index))) return 0.0;
|
||||
|
||||
@@ -1450,15 +1481,30 @@ double wrenGetArgumentDouble(WrenVM* vm, int index)
|
||||
|
||||
const char* wrenGetArgumentString(WrenVM* vm, int index)
|
||||
{
|
||||
ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call.");
|
||||
ASSERT(index >= 0, "index cannot be negative.");
|
||||
ASSERT(index < vm->foreignCallNumArgs, "Not that many arguments.");
|
||||
validateForeignArgument(vm, index);
|
||||
|
||||
if (!IS_STRING(*(vm->foreignCallSlot + index))) return NULL;
|
||||
|
||||
return AS_CSTRING(*(vm->foreignCallSlot + index));
|
||||
}
|
||||
|
||||
WrenValue* wrenGetArgumentValue(WrenVM* vm, int index)
|
||||
{
|
||||
validateForeignArgument(vm, index);
|
||||
|
||||
// Make a handle for it.
|
||||
WrenValue* value = ALLOCATE(vm, WrenValue);
|
||||
value->value = *(vm->foreignCallSlot + index);
|
||||
|
||||
// Add it to the front of the linked list of handles.
|
||||
if (vm->valueHandles != NULL) vm->valueHandles->prev = value;
|
||||
value->prev = NULL;
|
||||
value->next = vm->valueHandles;
|
||||
vm->valueHandles = value;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void wrenReturnBool(WrenVM* vm, bool value)
|
||||
{
|
||||
ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call.");
|
||||
@@ -1486,3 +1532,12 @@ void wrenReturnString(WrenVM* vm, const char* text, int length)
|
||||
*vm->foreignCallSlot = wrenNewString(vm, text, size);
|
||||
vm->foreignCallSlot = NULL;
|
||||
}
|
||||
|
||||
void wrenReturnValue(WrenVM* vm, WrenValue* value)
|
||||
{
|
||||
ASSERT(vm->foreignCallSlot != NULL, "Must be in foreign call.");
|
||||
ASSERT(value != NULL, "Value cannot be NULL.");
|
||||
|
||||
*vm->foreignCallSlot = value->value;
|
||||
vm->foreignCallSlot = NULL;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,11 @@ typedef enum
|
||||
#undef OPCODE
|
||||
} Code;
|
||||
|
||||
// A handle to a method.
|
||||
//
|
||||
// It is a node in the doubly-linked list of currently allocate method handles.
|
||||
// Each node has a reference to the fiber containing the method stub to call
|
||||
// the method.
|
||||
struct WrenMethod
|
||||
{
|
||||
// The fiber that invokes the method. Its stack is pre-populated with the
|
||||
@@ -28,6 +33,17 @@ struct WrenMethod
|
||||
WrenMethod* next;
|
||||
};
|
||||
|
||||
// A handle to a value, basically just a linked list of extra GC roots.
|
||||
//
|
||||
// Note that even non-heap-allocated values can be stored here.
|
||||
struct WrenValue
|
||||
{
|
||||
Value value;
|
||||
|
||||
WrenValue* prev;
|
||||
WrenValue* next;
|
||||
};
|
||||
|
||||
struct WrenVM
|
||||
{
|
||||
ObjClass* boolClass;
|
||||
@@ -99,6 +115,10 @@ struct WrenVM
|
||||
// Pointer to the first node in the linked list of active method handles or
|
||||
// NULL if there are no handles.
|
||||
WrenMethod* methodHandles;
|
||||
|
||||
// Pointer to the first node in the linked list of active value handles or
|
||||
// NULL if there are no handles.
|
||||
WrenValue* valueHandles;
|
||||
|
||||
// During a foreign function call, this will contain the number of arguments
|
||||
// to the function.
|
||||
|
||||
Reference in New Issue
Block a user