feat: replace wrenGetMethod with slot-based wrenCall API using wrenMakeCallHandle and wrenEnsureSlots
Refactor the C API for invoking Wren methods from C code. Remove the old wrenGetMethod and wrenCallVarArgs functions that used a type-string-based argument marshalling system. Introduce a new slot-based approach where callers first call wrenEnsureSlots to reserve space, then use wrenSetSlot___ functions to place the receiver and arguments on the stack, and finally call wrenCall with a handle created by wrenMakeCallHandle. Results are retrieved via wrenGetSlot___. This change simplifies the VM internals, eliminates varargs parsing overhead, and yields a 185% speed improvement in the call benchmark. Update all internal modules (scheduler, io, timer) and test files to use the new API. Also fix fiber suspension to clear the API stack pointer and adjust the interpreter to store the final fiber result at stack[0] for C API access.
This commit is contained in:
+16
-5
@@ -32,21 +32,32 @@ static void call(WrenVM* vm)
|
||||
|
||||
wrenInterpret(otherVM, testScript);
|
||||
|
||||
WrenValue* method = wrenGetMethod(otherVM, "main", "Test", "method(_,_,_,_)");
|
||||
WrenValue* method = wrenMakeCallHandle(otherVM, "method(_,_,_,_)");
|
||||
|
||||
wrenEnsureSlots(otherVM, 1);
|
||||
wrenGetVariable(otherVM, "main", "Test", 0);
|
||||
WrenValue* testClass = wrenGetSlotValue(otherVM, 0);
|
||||
|
||||
double startTime = (double)clock() / CLOCKS_PER_SEC;
|
||||
|
||||
double result = 0;
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
WrenValue* resultValue;
|
||||
wrenCall(otherVM, method, &resultValue, "dddd", 1.0, 2.0, 3.0, 4.0);
|
||||
result += wrenGetValueDouble(otherVM, resultValue);
|
||||
wrenReleaseValue(otherVM, resultValue);
|
||||
wrenEnsureSlots(otherVM, 5);
|
||||
wrenSetSlotValue(otherVM, 0, testClass);
|
||||
wrenSetSlotDouble(otherVM, 1, 1.0);
|
||||
wrenSetSlotDouble(otherVM, 2, 2.0);
|
||||
wrenSetSlotDouble(otherVM, 3, 3.0);
|
||||
wrenSetSlotDouble(otherVM, 4, 4.0);
|
||||
|
||||
wrenCall(otherVM, method);
|
||||
|
||||
result += wrenGetSlotDouble(otherVM, 0);
|
||||
}
|
||||
|
||||
double elapsed = (double)clock() / CLOCKS_PER_SEC - startTime;
|
||||
|
||||
wrenReleaseValue(otherVM, testClass);
|
||||
wrenReleaseValue(otherVM, method);
|
||||
wrenFreeVM(otherVM);
|
||||
|
||||
|
||||
+60
-18
@@ -5,33 +5,75 @@
|
||||
|
||||
void callRunTests(WrenVM* vm)
|
||||
{
|
||||
WrenValue* noParams = wrenGetMethod(vm, "main", "Call", "noParams");
|
||||
WrenValue* zero = wrenGetMethod(vm, "main", "Call", "zero()");
|
||||
WrenValue* one = wrenGetMethod(vm, "main", "Call", "one(_)");
|
||||
WrenValue* two = wrenGetMethod(vm, "main", "Call", "two(_,_)");
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenGetVariable(vm, "main", "Call", 0);
|
||||
WrenValue* callClass = wrenGetSlotValue(vm, 0);
|
||||
|
||||
WrenValue* noParams = wrenMakeCallHandle(vm, "noParams");
|
||||
WrenValue* zero = wrenMakeCallHandle(vm, "zero()");
|
||||
WrenValue* one = wrenMakeCallHandle(vm, "one(_)");
|
||||
WrenValue* two = wrenMakeCallHandle(vm, "two(_,_)");
|
||||
|
||||
// Different arity.
|
||||
wrenCall(vm, noParams, NULL, "");
|
||||
wrenCall(vm, zero, NULL, "");
|
||||
wrenCall(vm, one, NULL, "i", 1);
|
||||
wrenCall(vm, two, NULL, "ii", 1, 2);
|
||||
|
||||
WrenValue* getValue = wrenGetMethod(vm, "main", "Call", "getValue(_)");
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenCall(vm, noParams);
|
||||
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenCall(vm, zero);
|
||||
|
||||
wrenEnsureSlots(vm, 2);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenSetSlotDouble(vm, 1, 1.0);
|
||||
wrenCall(vm, one);
|
||||
|
||||
wrenEnsureSlots(vm, 3);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenSetSlotDouble(vm, 1, 1.0);
|
||||
wrenSetSlotDouble(vm, 2, 2.0);
|
||||
wrenCall(vm, two);
|
||||
|
||||
// Returning a value.
|
||||
WrenValue* value = NULL;
|
||||
wrenCall(vm, getValue, &value, "v", NULL);
|
||||
WrenValue* getValue = wrenMakeCallHandle(vm, "getValue()");
|
||||
wrenEnsureSlots(vm, 1);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenCall(vm, getValue);
|
||||
WrenValue* value = wrenGetSlotValue(vm, 0);
|
||||
|
||||
// Different argument types.
|
||||
wrenCall(vm, two, NULL, "bb", true, false);
|
||||
wrenCall(vm, two, NULL, "dd", 1.2, 3.4);
|
||||
wrenCall(vm, two, NULL, "ii", 3, 4);
|
||||
wrenCall(vm, two, NULL, "ss", "string", "another");
|
||||
wrenCall(vm, two, NULL, "vv", NULL, value);
|
||||
wrenEnsureSlots(vm, 3);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenSetSlotBool(vm, 1, true);
|
||||
wrenSetSlotBool(vm, 2, false);
|
||||
wrenCall(vm, two);
|
||||
|
||||
wrenEnsureSlots(vm, 3);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenSetSlotDouble(vm, 1, 1.2);
|
||||
wrenSetSlotDouble(vm, 2, 3.4);
|
||||
wrenCall(vm, two);
|
||||
|
||||
wrenEnsureSlots(vm, 3);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenSetSlotString(vm, 1, "string");
|
||||
wrenSetSlotString(vm, 2, "another");
|
||||
wrenCall(vm, two);
|
||||
|
||||
wrenEnsureSlots(vm, 3);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenSetSlotNull(vm, 1);
|
||||
wrenSetSlotValue(vm, 2, value);
|
||||
wrenCall(vm, two);
|
||||
|
||||
// Truncate a string, or allow null bytes.
|
||||
wrenCall(vm, two, NULL, "aa", "string", 3, "b\0y\0t\0e", 7);
|
||||
wrenEnsureSlots(vm, 3);
|
||||
wrenSetSlotValue(vm, 0, callClass);
|
||||
wrenSetSlotBytes(vm, 1, "string", 3);
|
||||
wrenSetSlotBytes(vm, 2, "b\0y\0t\0e", 7);
|
||||
wrenCall(vm, two);
|
||||
|
||||
wrenReleaseValue(vm, callClass);
|
||||
wrenReleaseValue(vm, noParams);
|
||||
wrenReleaseValue(vm, zero);
|
||||
wrenReleaseValue(vm, one);
|
||||
|
||||
+1
-8
@@ -20,13 +20,7 @@ class Call {
|
||||
System.print("two %(one) %(two)")
|
||||
}
|
||||
|
||||
static getValue(value) {
|
||||
// Return a new value if we aren't given one.
|
||||
if (value == null) return ["a", "b"]
|
||||
|
||||
// Otherwise print it.
|
||||
System.print(value)
|
||||
}
|
||||
static getValue() { ["a", "b"] }
|
||||
}
|
||||
|
||||
// expect: noParams
|
||||
@@ -36,7 +30,6 @@ class Call {
|
||||
|
||||
// expect: two true false
|
||||
// expect: two 1.2 3.4
|
||||
// expect: two 3 4
|
||||
// expect: two string another
|
||||
// expect: two null [a, b]
|
||||
// expect: two str [98, 0, 121, 0, 116, 0, 101]
|
||||
|
||||
Reference in New Issue
Block a user