[false, "mono_wasm_invoke_method_ref", "void", ["number", "number", "number", "number", "number"]],
[true, "mono_wasm_string_from_utf16_ref", "void", ["number", "number", "number"]],
[true, "mono_wasm_intern_string_ref", "void", ["number"]],
- [true, "mono_wasm_assembly_get_entry_point", "number", ["number"]],
+ [true, "mono_wasm_assembly_get_entry_point", "number", ["number", "number"]],
[true, "mono_wasm_class_get_type", "number", ["number"]],
// MONO.diagnostics
[true, "mono_jiterp_get_trace_bailout_count", "number", ["number"]],
[true, "mono_jiterp_value_copy", "void", ["number", "number", "number"]],
[true, "mono_jiterp_get_member_offset", "number", ["number"]],
- [false, "mono_jiterp_encode_leb52", "number", ["number", "number", "number"]],
- [false, "mono_jiterp_encode_leb64_ref", "number", ["number", "number", "number"]],
- [false, "mono_jiterp_encode_leb_signed_boundary", "number", ["number", "number", "number"]],
- [false, "mono_jiterp_write_number_unaligned", "void", ["number", "number", "number"]],
+ [true, "mono_jiterp_encode_leb52", "number", ["number", "number", "number"]],
+ [true, "mono_jiterp_encode_leb64_ref", "number", ["number", "number", "number"]],
+ [true, "mono_jiterp_encode_leb_signed_boundary", "number", ["number", "number", "number"]],
+ [true, "mono_jiterp_write_number_unaligned", "void", ["number", "number", "number"]],
[true, "mono_jiterp_type_is_byref", "number", ["number"]],
[true, "mono_jiterp_get_size_of_stackval", "number", []],
[true, "mono_jiterp_parse_option", "number", ["string"]],
OUT_OF_RANGE = 2,
}
+const fastCwrapTypes = ["void", "number", null];
+
+function cwrap (name: string, returnType: string | null, argTypes: string[] | undefined, opts: any, throwOnError: boolean) : Function {
+ // Attempt to bypass emscripten's generated wrapper if it is safe to do so
+ let fce =
+ // Special cwrap options disable the fast path
+ (typeof (opts) === "undefined") &&
+ // Only attempt to do fast calls if all the args and the return type are either number or void
+ (fastCwrapTypes.indexOf(returnType) >= 0) &&
+ (!argTypes || argTypes.every(atype => fastCwrapTypes.indexOf(atype) >= 0)) &&
+ // Module["asm"] may not be defined yet if we are early enough in the startup process
+ // in that case, we need to rely on emscripten's lazy wrappers
+ Module["asm"]
+ ? <Function>((<any>Module["asm"])[name])
+ : undefined;
+
+ // If the argument count for the wasm function doesn't match the signature, fall back to cwrap
+ if (fce && argTypes && (fce.length !== argTypes.length)) {
+ console.error(`MONO_WASM: argument count mismatch for cwrap ${name}`);
+ fce = undefined;
+ }
+
+ // We either failed to find the raw wasm func or for some reason we can't use it directly
+ if (typeof (fce) !== "function")
+ fce = Module.cwrap(name, returnType, argTypes, opts);
+
+ if (typeof (fce) !== "function") {
+ const msg = `cwrap ${name} not found or not a function`;
+ if (throwOnError)
+ throw new Error(msg);
+ else
+ console.error("MONO_WASM: " + msg);
+ }
+ return fce;
+}
+
export function init_c_exports(): void {
const lfns = WasmEnableLegacyJsInterop && !disableLegacyJsInterop ? legacy_interop_cwraps : [];
const fns = [...fn_signatures, ...lfns];
if (lazy) {
// lazy init on first run
wf[name] = function (...args: any[]) {
- const fce = Module.cwrap(name, returnType, argTypes, opts);
- if (typeof (fce) !== "function")
- throw new Error(`cwrap ${name} not found or not a function`);
+ const fce = cwrap(name, returnType, argTypes, opts, true);
wf[name] = fce;
return fce(...args);
};
} else {
- const fce = Module.cwrap(name, returnType, argTypes, opts);
- // throw would be preferable, but it causes really hard to debug startup errors and
- // unhandled promise rejections so this is more useful
- if (typeof (fce) !== "function")
- console.error(`cwrap ${name} not found or not a function`);
+ const fce = cwrap(name, returnType, argTypes, opts, false);
wf[name] = fce;
}
}