diff --git a/src/include/wren.h b/src/include/wren.h index 53cdc1a9..f107f6e3 100644 --- a/src/include/wren.h +++ b/src/include/wren.h @@ -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 diff --git a/src/module/io.c b/src/module/io.c index bd03bd52..d118e6e1 100644 --- a/src/module/io.c +++ b/src/module/io.c @@ -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) diff --git a/src/optional/wren_opt_meta.c b/src/optional/wren_opt_meta.c index 5428cc23..6bebcd3e 100644 --- a/src/optional/wren_opt_meta.c +++ b/src/optional/wren_opt_meta.c @@ -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, diff --git a/src/optional/wren_opt_random.c b/src/optional/wren_opt_random.c index 3735a4db..120f5850 100644 --- a/src/optional/wren_opt_random.c +++ b/src/optional/wren_opt_random.c @@ -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 diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index 4d44d49f..3ce874ff 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -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); } diff --git a/test/api/benchmark.c b/test/api/benchmark.c index d5c84a8f..afc1a9af 100644 --- a/test/api/benchmark.c +++ b/test/api/benchmark.c @@ -11,7 +11,7 @@ static void arguments(WrenVM* vm) result += wrenGetSlotDouble(vm, 3); result += wrenGetSlotDouble(vm, 4); - wrenReturnDouble(vm, result); + wrenSetSlotDouble(vm, 0, result); } WrenForeignMethodFn benchmarkBindMethod(const char* signature) diff --git a/test/api/foreign_class.c b/test/api/foreign_class.c index cd544def..119a5879 100644 --- a/test/api/foreign_class.c +++ b/test/api/foreign_class.c @@ -7,7 +7,7 @@ static int finalized = 0; static void apiFinalized(WrenVM* vm) { - wrenReturnDouble(vm, finalized); + wrenSetSlotDouble(vm, 0, finalized); } static void counterAllocate(WrenVM* vm) @@ -27,7 +27,7 @@ static void counterIncrement(WrenVM* vm) static void counterValue(WrenVM* vm) { double value = *(double*)wrenGetSlotForeign(vm, 0); - wrenReturnDouble(vm, value); + wrenSetSlotDouble(vm, 0, value); } static void pointAllocate(WrenVM* vm) @@ -64,7 +64,7 @@ static void pointToString(WrenVM* vm) char result[100]; sprintf(result, "(%g, %g, %g)", coordinates[0], coordinates[1], coordinates[2]); - wrenReturnString(vm, result, (int)strlen(result)); + wrenSetSlotString(vm, 0, result); } static void resourceAllocate(WrenVM* vm) diff --git a/test/api/main.c b/test/api/main.c index 7674db05..dbff716a 100644 --- a/test/api/main.c +++ b/test/api/main.c @@ -7,7 +7,7 @@ #include "benchmark.h" #include "call.h" #include "foreign_class.h" -#include "returns.h" +#include "slots.h" #include "value.h" // The name of the currently executing API test. @@ -36,7 +36,7 @@ static WrenForeignMethodFn bindForeignMethod( method = foreignClassBindMethod(fullName); if (method != NULL) return method; - method = returnsBindMethod(fullName); + method = slotsBindMethod(fullName); if (method != NULL) return method; method = valueBindMethod(fullName); diff --git a/test/api/returns.c b/test/api/returns.c deleted file mode 100644 index f622ded9..00000000 --- a/test/api/returns.c +++ /dev/null @@ -1,51 +0,0 @@ -#include - -#include "returns.h" - -static void implicitNull(WrenVM* vm) -{ - // Do nothing. -} - -static void returnInt(WrenVM* vm) -{ - wrenReturnDouble(vm, 123456); -} - -static void returnFloat(WrenVM* vm) -{ - wrenReturnDouble(vm, 123.456); -} - -static void returnTrue(WrenVM* vm) -{ - wrenReturnBool(vm, true); -} - -static void returnFalse(WrenVM* vm) -{ - wrenReturnBool(vm, false); -} - -static void returnString(WrenVM* vm) -{ - wrenReturnString(vm, "a string", -1); -} - -static void returnBytes(WrenVM* vm) -{ - wrenReturnString(vm, "a\0b\0c", 5); -} - -WrenForeignMethodFn returnsBindMethod(const char* signature) -{ - if (strcmp(signature, "static Returns.implicitNull") == 0) return implicitNull; - if (strcmp(signature, "static Returns.returnInt") == 0) return returnInt; - if (strcmp(signature, "static Returns.returnFloat") == 0) return returnFloat; - if (strcmp(signature, "static Returns.returnTrue") == 0) return returnTrue; - if (strcmp(signature, "static Returns.returnFalse") == 0) return returnFalse; - if (strcmp(signature, "static Returns.returnString") == 0) return returnString; - if (strcmp(signature, "static Returns.returnBytes") == 0) return returnBytes; - - return NULL; -} diff --git a/test/api/returns.h b/test/api/returns.h deleted file mode 100644 index 21fa57cd..00000000 --- a/test/api/returns.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "wren.h" - -WrenForeignMethodFn returnsBindMethod(const char* signature); diff --git a/test/api/returns.wren b/test/api/returns.wren deleted file mode 100644 index 16a07e5e..00000000 --- a/test/api/returns.wren +++ /dev/null @@ -1,23 +0,0 @@ -class Returns { - foreign static implicitNull - - foreign static returnInt - foreign static returnFloat - - foreign static returnTrue - foreign static returnFalse - - foreign static returnString - foreign static returnBytes -} - -System.print(Returns.implicitNull == null) // expect: true - -System.print(Returns.returnInt) // expect: 123456 -System.print(Returns.returnFloat) // expect: 123.456 - -System.print(Returns.returnTrue) // expect: true -System.print(Returns.returnFalse) // expect: false - -System.print(Returns.returnString) // expect: a string -System.print(Returns.returnBytes.bytes.toList) // expect: [97, 0, 98, 0, 99] diff --git a/test/api/slots.c b/test/api/slots.c new file mode 100644 index 00000000..8a2c7308 --- /dev/null +++ b/test/api/slots.c @@ -0,0 +1,83 @@ +#include + +#include "slots.h" + +static void noSet(WrenVM* vm) +{ + // Do nothing. +} + +static void getSlots(WrenVM* vm) +{ + bool result = true; + if (wrenGetSlotBool(vm, 1) != true) result = false; + // TODO: Test wrenGetSlotForeign(). + + int length; + const char* bytes = wrenGetSlotBytes(vm, 2, &length); + if (length != 5) result = false; + if (memcmp(bytes, "by\0te", length) != 0) result = false; + + if (wrenGetSlotDouble(vm, 3) != 12.34) result = false; + if (strcmp(wrenGetSlotString(vm, 4), "str") != 0) result = false; + + WrenValue* value = wrenGetSlotValue(vm, 5); + + if (result) + { + // Otherwise, return the value so we can tell if we captured it correctly. + wrenSetSlotValue(vm, 0, value); + wrenReleaseValue(vm, value); + } + else + { + // If anything failed, return false. + wrenSetSlotBool(vm, 0, false); + } +} + +static void setSlots(WrenVM* vm) +{ + WrenValue* value = wrenGetSlotValue(vm, 1); + + wrenSetSlotBool(vm, 1, true); + wrenSetSlotBytes(vm, 2, "by\0te", 5); + wrenSetSlotDouble(vm, 3, 12.34); + wrenSetSlotString(vm, 4, "str"); + + // TODO: wrenSetSlotNull(). + + // Read the slots back to make sure they were set correctly. + + bool result = true; + if (wrenGetSlotBool(vm, 1) != true) result = false; + + int length; + const char* bytes = wrenGetSlotBytes(vm, 2, &length); + if (length != 5) result = false; + if (memcmp(bytes, "by\0te", length) != 0) result = false; + + if (wrenGetSlotDouble(vm, 3) != 12.34) result = false; + if (strcmp(wrenGetSlotString(vm, 4), "str") != 0) result = false; + + if (result) + { + // Move the value into the return position. + wrenSetSlotValue(vm, 0, value); + wrenReleaseValue(vm, value); + } + else + { + // If anything failed, return false. + wrenSetSlotBool(vm, 0, false); + } +} + +WrenForeignMethodFn slotsBindMethod(const char* signature) +{ + if (strcmp(signature, "static Slots.noSet") == 0) return noSet; + if (strcmp(signature, "static Slots.getSlots(_,_,_,_,_)") == 0) return getSlots; + if (strcmp(signature, "static Slots.setSlots(_,_,_,_)") == 0) return setSlots; + + return NULL; +} diff --git a/test/api/slots.h b/test/api/slots.h new file mode 100644 index 00000000..cf4392fa --- /dev/null +++ b/test/api/slots.h @@ -0,0 +1,3 @@ +#include "wren.h" + +WrenForeignMethodFn slotsBindMethod(const char* signature); diff --git a/test/api/slots.wren b/test/api/slots.wren new file mode 100644 index 00000000..119251d5 --- /dev/null +++ b/test/api/slots.wren @@ -0,0 +1,16 @@ +class Slots { + foreign static noSet + + foreign static getSlots(bool, num, string, bytes, value) + + foreign static setSlots(a, b, c, d) +} + +// If nothing is set in the return slot, it retains its previous value, the +// receiver. +System.print(Slots.noSet == Slots) // expect: true + +var value = ["value"] +System.print(Slots.getSlots(true, "by\0te", 12.34, "str", value) == value) // expect: true + +System.print(Slots.setSlots(value, 0, 0, 0) == value) // expect: true diff --git a/test/api/value.c b/test/api/value.c index e26d4978..837e8ce2 100644 --- a/test/api/value.c +++ b/test/api/value.c @@ -11,7 +11,7 @@ static void setValue(WrenVM* vm) static void getValue(WrenVM* vm) { - wrenReturnValue(vm, value); + wrenSetSlotValue(vm, 0, value); wrenReleaseValue(vm, value); } diff --git a/util/xcode/wren.xcodeproj/project.pbxproj b/util/xcode/wren.xcodeproj/project.pbxproj index fe7b67a4..a1fb096b 100644 --- a/util/xcode/wren.xcodeproj/project.pbxproj +++ b/util/xcode/wren.xcodeproj/project.pbxproj @@ -47,7 +47,7 @@ 29DC14A91BBA302F008A8274 /* wren_vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29205C981AB4E6430073018D /* wren_vm.c */; }; 29DC14AA1BBA3032008A8274 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009A61B7E3993000CE58C /* main.c */; }; 29DC14AB1BBA3038008A8274 /* foreign_class.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009A81B7E39A8000CE58C /* foreign_class.c */; }; - 29DC14AC1BBA303D008A8274 /* returns.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009AA1B7E39A8000CE58C /* returns.c */; }; + 29DC14AC1BBA303D008A8274 /* slots.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009AA1B7E39A8000CE58C /* slots.c */; }; 29DC14AD1BBA3040008A8274 /* value.c in Sources */ = {isa = PBXBuildFile; fileRef = 29D009AC1B7E39A8000CE58C /* value.c */; }; /* End PBXBuildFile section */ @@ -118,8 +118,8 @@ 29D009A61B7E3993000CE58C /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../../test/api/main.c; sourceTree = ""; }; 29D009A81B7E39A8000CE58C /* foreign_class.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = foreign_class.c; path = ../../test/api/foreign_class.c; sourceTree = ""; }; 29D009A91B7E39A8000CE58C /* foreign_class.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = foreign_class.h; path = ../../test/api/foreign_class.h; sourceTree = ""; }; - 29D009AA1B7E39A8000CE58C /* returns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = returns.c; path = ../../test/api/returns.c; sourceTree = ""; }; - 29D009AB1B7E39A8000CE58C /* returns.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = returns.h; path = ../../test/api/returns.h; sourceTree = ""; }; + 29D009AA1B7E39A8000CE58C /* slots.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = slots.c; path = ../../test/api/slots.c; sourceTree = ""; }; + 29D009AB1B7E39A8000CE58C /* slots.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = slots.h; path = ../../test/api/slots.h; sourceTree = ""; }; 29D009AC1B7E39A8000CE58C /* value.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = value.c; path = ../../test/api/value.c; sourceTree = ""; }; 29D009AD1B7E39A8000CE58C /* value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = value.h; path = ../../test/api/value.h; sourceTree = ""; }; 29F384111BD19706002F84E0 /* io.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = io.h; path = ../../src/module/io.h; sourceTree = ""; }; @@ -249,8 +249,8 @@ 293D46951BB43F9900200083 /* call.h */, 29D009A81B7E39A8000CE58C /* foreign_class.c */, 29D009A91B7E39A8000CE58C /* foreign_class.h */, - 29D009AA1B7E39A8000CE58C /* returns.c */, - 29D009AB1B7E39A8000CE58C /* returns.h */, + 29D009AA1B7E39A8000CE58C /* slots.c */, + 29D009AB1B7E39A8000CE58C /* slots.h */, 29D009AC1B7E39A8000CE58C /* value.c */, 29D009AD1B7E39A8000CE58C /* value.h */, ); @@ -376,7 +376,7 @@ 293D46961BB43F9900200083 /* call.c in Sources */, 29A427351BDBE435001E6E22 /* wren_opt_meta.c in Sources */, 29DC14AB1BBA3038008A8274 /* foreign_class.c in Sources */, - 29DC14AC1BBA303D008A8274 /* returns.c in Sources */, + 29DC14AC1BBA303D008A8274 /* slots.c in Sources */, 29DC14AD1BBA3040008A8274 /* value.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0;