wrenReturn___() -> wrenSlotSet___().

This turns those functions into general-purpose functions for writing
raw C values into slots on the foreign call stack.

Writing a return just means writing a value to slot 0.
This commit is contained in:
Bob Nystrom
2015-12-16 13:00:13 -08:00
parent 4b3c818ec5
commit 7fcdcf2f1a
16 changed files with 215 additions and 152 deletions
+37 -18
View File
@@ -240,6 +240,8 @@ void* wrenAllocateForeign(WrenVM* vm, size_t size);
// Returns the number of slots available to the current foreign method.
int wrenGetSlotCount(WrenVM* vm);
// TODO: Update docs.
// The following functions read one of the arguments passed to a foreign call.
// They may only be called while within a function provided to
// [wrenDefineMethod] or [wrenDefineStaticMethod] that Wren has invoked.
@@ -265,6 +267,18 @@ int wrenGetSlotCount(WrenVM* vm);
// It is an error to call this if the slot does not contain a boolean value.
bool wrenGetSlotBool(WrenVM* vm, int slot);
// Reads a byte array from [slot].
//
// The memory for the returned string is owned by Wren. You can inspect it
// while in your foreign method, but cannot keep a pointer to it after the
// function returns, since the garbage collector may reclaim it.
//
// Returns a pointer to the first byte of the array and fill [length] with the
// number of bytes in the array.
//
// It is an error to call this if the slot does not contain a string.
const char* wrenGetSlotBytes(WrenVM* vm, int slot, int* length);
// Reads a number from [slot].
//
// It is an error to call this if the slot does not contain a number.
@@ -301,27 +315,32 @@ WrenValue* wrenGetSlotValue(WrenVM* vm, int slot);
// call one of these once. It is an error to access any of the foreign calls
// arguments after one of these has been called.
// Provides a boolean return value for a foreign call.
void wrenReturnBool(WrenVM* vm, bool value);
// Stores the boolean [value] in [slot].
void wrenSetSlotBool(WrenVM* vm, int slot, bool value);
// Provides a numeric return value for a foreign call.
void wrenReturnDouble(WrenVM* vm, double value);
// Stores the array [length] of [bytes] in [slot].
//
// The bytes are copied to a new string within Wren's heap, so you can free
// memory used by them after this is called.
void wrenSetSlotBytes(WrenVM* vm, int slot, const char* bytes, int length);
// Provides a string return value for a foreign call.
//
// The [text] will be copied to a new string within Wren's heap, so you can
// free memory used by it after this is called.
//
// If [length] is non-zero, Wren copies that many bytes from [text], including
// any null bytes. If it is -1, then the length of [text] is calculated using
// `strlen()`. If the string may contain any null bytes in the middle, then you
// must pass an explicit length.
void wrenReturnString(WrenVM* vm, const char* text, int length);
// Stores the numeric [value] in [slot].
void wrenSetSlotDouble(WrenVM* vm, int slot, double value);
// Provides the return value for a foreign call.
// Stores null in [slot].
void wrenSetSlotNull(WrenVM* vm, int slot);
// Stores the string [text] in [slot].
//
// This uses the value referred to by the handle as the return value, but it
// does not release the handle.
void wrenReturnValue(WrenVM* vm, WrenValue* value);
// The [text] is copied to a new string within Wren's heap, so you can free
// memory used by it after this is called. The length is calculated using
// [strlen()]. If the string may contain any null bytes in the middle, then you
// should use [wrenSetSlotBytes()] instead.
void wrenSetSlotString(WrenVM* vm, int slot, const char* text);
// Stores the value captured in [value] in [slot].
//
// This does not release the handle for the value.
void wrenSetSlotValue(WrenVM* vm, int slot, WrenValue* value);
#endif
+3 -3
View File
@@ -165,7 +165,7 @@ void fileClose(WrenVM* vm)
// If it's already closed, we're done.
if (fd == -1)
{
wrenReturnBool(vm, true);
wrenSetSlotBool(vm, 0, true);
return;
}
@@ -174,14 +174,14 @@ void fileClose(WrenVM* vm)
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 1));
uv_fs_close(getLoop(), request, fd, closeCallback);
wrenReturnBool(vm, false);
wrenSetSlotBool(vm, 0, false);
}
void fileDescriptor(WrenVM* vm)
{
int* foreign = (int*)wrenGetSlotForeign(vm, 0);
int fd = *foreign;
wrenReturnDouble(vm, fd);
wrenSetSlotDouble(vm, 0, fd);
}
static void fileReadBytesCallback(uv_fs_t* request)
+1 -3
View File
@@ -19,12 +19,10 @@ void metaCompile(WrenVM* vm)
// Compile it.
ObjFn* fn = wrenCompile(vm, module, wrenGetSlotString(vm, 1), false);
if (fn == NULL) return;
// Return the result. We can't use the public API for this since we have a
// bare ObjFn.
*vm->foreignStackStart = OBJ_VAL(fn);
vm->foreignStackStart = NULL;
vm->foreignStackStart[0] = fn != NULL ? OBJ_VAL(fn) : NULL_VAL;
}
static WrenForeignMethodFn bindMetaForeignMethods(WrenVM* vm,
+2 -2
View File
@@ -92,14 +92,14 @@ static void randomFloat(WrenVM* vm)
// from 0 to 1.0 (half-inclusive).
result /= 9007199254740992.0;
wrenReturnDouble(vm, result);
wrenSetSlotDouble(vm, 0, result);
}
static void randomInt0(WrenVM* vm)
{
Well512* well = (Well512*)wrenGetSlotForeign(vm, 0);
wrenReturnDouble(vm, (double)advanceState(well));
wrenSetSlotDouble(vm, 0, (double)advanceState(well));
}
// TODO: The way these are wired up is pretty verbose and tedious. Also, the
+57 -36
View File
@@ -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);
}