refactor: replace wrenReturn___() with wrenSetSlot___() for writing values to arbitrary slots
The old wrenReturn___() functions only wrote to slot 0 for return values. The new wrenSetSlot___() functions allow writing to any slot index, making them general-purpose for manipulating the foreign call stack. This change updates all call sites, removes the dedicated returns test suite in favor of slots tests, and adjusts the VM internals to treat slot 0 as the return position rather than using a separate return mechanism.
This commit is contained in:
+57
-36
@@ -349,18 +349,14 @@ static void callForeign(WrenVM* vm, ObjFiber* fiber,
|
||||
WrenForeignMethodFn foreign, int numArgs)
|
||||
{
|
||||
vm->foreignStackStart = fiber->stackTop - numArgs;
|
||||
|
||||
foreign(vm);
|
||||
|
||||
// Discard the stack slots for the arguments (but leave one for
|
||||
// the result).
|
||||
fiber->stackTop -= numArgs - 1;
|
||||
|
||||
// If nothing was returned, implicitly return null.
|
||||
if (vm->foreignStackStart != NULL)
|
||||
{
|
||||
*vm->foreignStackStart = NULL_VAL;
|
||||
vm->foreignStackStart = NULL;
|
||||
}
|
||||
// Discard the stack slots for the arguments and temporaries but leave one
|
||||
// for the result.
|
||||
fiber->stackTop = vm->foreignStackStart + 1;
|
||||
|
||||
vm->foreignStackStart = NULL;
|
||||
}
|
||||
|
||||
// Handles the current fiber having aborted because of an error. Switches to
|
||||
@@ -475,6 +471,11 @@ static inline void callFunction(
|
||||
{
|
||||
upvalue->value += offset;
|
||||
}
|
||||
|
||||
if (vm->foreignStackStart != NULL)
|
||||
{
|
||||
vm->foreignStackStart += offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,7 +735,7 @@ void wrenFinalizeForeign(WrenVM* vm, ObjForeign* foreign)
|
||||
|
||||
ASSERT(method->type == METHOD_FOREIGN, "Finalizer should be foreign.");
|
||||
|
||||
// Pass the constructor arguments to the allocator as well.
|
||||
// Pass the foreign object to the finalizer.
|
||||
Value slot = OBJ_VAL(foreign);
|
||||
vm->foreignStackStart = &slot;
|
||||
|
||||
@@ -1628,9 +1629,15 @@ int wrenGetSlotCount(WrenVM* vm)
|
||||
{
|
||||
ASSERT(vm->foreignStackStart != NULL, "Must be in foreign call.");
|
||||
|
||||
// If no fiber is executing, we must be in a finalizer, in which case the
|
||||
// "stack" just has one object, the object being finalized.
|
||||
if (vm->fiber == NULL) return 1;
|
||||
// If no fiber is executing or the foreign stack is not in it, we must be in
|
||||
// a finalizer, in which case the "stack" just has one object, the object
|
||||
// being finalized.
|
||||
if (vm->fiber == NULL ||
|
||||
vm->foreignStackStart < vm->fiber->stack ||
|
||||
vm->foreignStackStart > vm->fiber->stackTop)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return (int)(vm->fiber->stackTop - vm->foreignStackStart);
|
||||
}
|
||||
@@ -1651,6 +1658,16 @@ bool wrenGetSlotBool(WrenVM* vm, int slot)
|
||||
return AS_BOOL(vm->foreignStackStart[slot]);
|
||||
}
|
||||
|
||||
const char* wrenGetSlotBytes(WrenVM* vm, int slot, int* length)
|
||||
{
|
||||
validateForeignSlot(vm, slot);
|
||||
ASSERT(IS_STRING(vm->foreignStackStart[slot]), "Slot must hold a string.");
|
||||
|
||||
ObjString* string = AS_STRING(vm->foreignStackStart[slot]);
|
||||
*length = string->length;
|
||||
return string->value;
|
||||
}
|
||||
|
||||
double wrenGetSlotDouble(WrenVM* vm, int slot)
|
||||
{
|
||||
validateForeignSlot(vm, slot);
|
||||
@@ -1683,39 +1700,43 @@ WrenValue* wrenGetSlotValue(WrenVM* vm, int slot)
|
||||
return wrenCaptureValue(vm, vm->foreignStackStart[slot]);
|
||||
}
|
||||
|
||||
void wrenReturnBool(WrenVM* vm, bool value)
|
||||
// Stores [value] in [slot] in the foreign call stack.
|
||||
static void setSlot(WrenVM* vm, int slot, Value value)
|
||||
{
|
||||
ASSERT(vm->foreignStackStart != NULL, "Must be in foreign call.");
|
||||
|
||||
*vm->foreignStackStart = BOOL_VAL(value);
|
||||
vm->foreignStackStart = NULL;
|
||||
validateForeignSlot(vm, slot);
|
||||
vm->foreignStackStart[slot] = value;
|
||||
}
|
||||
|
||||
void wrenReturnDouble(WrenVM* vm, double value)
|
||||
void wrenSetSlotBool(WrenVM* vm, int slot, bool value)
|
||||
{
|
||||
ASSERT(vm->foreignStackStart != NULL, "Must be in foreign call.");
|
||||
|
||||
*vm->foreignStackStart = NUM_VAL(value);
|
||||
vm->foreignStackStart = NULL;
|
||||
setSlot(vm, slot, BOOL_VAL(value));
|
||||
}
|
||||
|
||||
void wrenReturnString(WrenVM* vm, const char* text, int length)
|
||||
void wrenSetSlotBytes(WrenVM* vm, int slot, const char* bytes, int length)
|
||||
{
|
||||
ASSERT(bytes != NULL, "Byte arraybytes cannot be NULL.");
|
||||
setSlot(vm, slot, wrenNewString(vm, bytes, (size_t)length));
|
||||
}
|
||||
|
||||
void wrenSetSlotDouble(WrenVM* vm, int slot, double value)
|
||||
{
|
||||
setSlot(vm, slot, NUM_VAL(value));
|
||||
}
|
||||
|
||||
void wrenSetSlotNull(WrenVM* vm, int slot)
|
||||
{
|
||||
setSlot(vm, slot, NULL_VAL);
|
||||
}
|
||||
|
||||
void wrenSetSlotString(WrenVM* vm, int slot, const char* text)
|
||||
{
|
||||
ASSERT(vm->foreignStackStart != NULL, "Must be in foreign call.");
|
||||
ASSERT(text != NULL, "String cannot be NULL.");
|
||||
|
||||
size_t size = length;
|
||||
if (length == -1) size = strlen(text);
|
||||
|
||||
*vm->foreignStackStart = wrenNewString(vm, text, size);
|
||||
vm->foreignStackStart = NULL;
|
||||
setSlot(vm, slot, wrenNewString(vm, text, strlen(text)));
|
||||
}
|
||||
|
||||
void wrenReturnValue(WrenVM* vm, WrenValue* value)
|
||||
void wrenSetSlotValue(WrenVM* vm, int slot, WrenValue* value)
|
||||
{
|
||||
ASSERT(vm->foreignStackStart != NULL, "Must be in foreign call.");
|
||||
ASSERT(value != NULL, "Value cannot be NULL.");
|
||||
|
||||
*vm->foreignStackStart = value->value;
|
||||
vm->foreignStackStart = NULL;
|
||||
setSlot(vm, slot, value->value);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user