in WorkbookApps/Xamarin.Workbooks.WebAssembly/Client/runtime.ts [132:207]
private callMethod(method: MonoMethod, thisArg: (Handle | null), argsMarshal: MarshalType[], ...args: (Handle | number | string)[]) {
let extraArgsMemSize = 0
for (var i = 0; i < args.length; ++i) {
// long/double memory must be 8 bytes aligned and I'm being lazy here. - kumpera
// allocate extra memory size for all but string and handle, to keep the conditional more readable - bojan
if (argsMarshal[i] !== MarshalType.String && argsMarshal[i] !== MarshalType.Handle)
extraArgsMemSize += 8
}
const extraArgsMem = extraArgsMemSize ? Module._malloc(extraArgsMemSize) : 0
let extraArgIndex = 0;
const argsMemory = Module._malloc(args.length * 4)
var ehThrow = Module._malloc(4)
for (var i = 0; i < args.length; ++i) {
if (argsMarshal[i] === MarshalType.String) {
if (typeof args[i] !== "string")
throw new Error(`Type of argument ${i} is ${typeof args[i]}, but string marshalling was requested!`)
Module.setValue(argsMemory + i * 4, this.runtime.convertStringToMonoString(<string>args[i]), "i32")
} else if (argsMarshal[i] === MarshalType.Handle) {
if (typeof args[i] === "string" || typeof args[i] === "number")
throw new Error(`Type of argument ${i} is ${typeof args[i]}, but handle marshalling was requested!`)
Module.setValue(argsMemory + i * 4, (<Handle>args[i]).value, "i32")
} else {
if (typeof args[i] !== "number")
throw new Error(`Type of argument ${i} is ${typeof args[i]}, but number marshalling was requested!`)
// upstream has an else if here with a bigger conditional, but having limited the
// enum here, we don't need to do that. we'll need to treat the extra cell
// specially for int/long/float/double values, but for handles (the remaining enum member)
// we can ignore the extra cell bit and just set the arg memory normally - bojan
const extraCell = extraArgsMemSize + extraArgIndex
extraArgIndex += 8
if (argsMarshal[i] === MarshalType.Int)
Module.setValue(extraCell, <number>args[i], "i32")
else if (argsMarshal[i] === MarshalType.Long)
Module.setValue(extraCell, <number>args[i], "i64")
else if (argsMarshal[i] === MarshalType.Float)
Module.setValue(extraCell, <number>args[i], "float")
else if (argsMarshal[i] === MarshalType.Double)
Module.setValue(extraCell, <number>args[i], "double")
Module.setValue(argsMemory + i * 4, extraCell, "i32")
}
}
Module.setValue(ehThrow, 0, "i32")
const res = this.runtime.invokeMethod(method.handle.value, (thisArg ? thisArg.value : null), argsMemory, ehThrow)
const ehRes = Module.getValue(ehThrow, "i32")
if (extraArgsMemSize)
Module._free(extraArgsMem)
Module._free(argsMemory)
Module._free(ehThrow)
if (ehRes != 0) {
const msg = new MonoString(new Handle(res), this.runtime).toString()
throw new Error(msg)
}
if (!res)
return res
const objectType = this.runtime.getObjectType(res)
switch (objectType) {
case MonoObjectType.Integer:
return this.runtime.unboxInteger(res)
case MonoObjectType.FloatingPoint:
return this.runtime.unboxFloat(res)
case MonoObjectType.String:
return new MonoString(new Handle(res), this.runtime).toString()
default:
return new Handle(res);
}
}