Skip to content

Commit

Permalink
Attempt to bypass emscripten's generated wrappers for cwraps (#85919)
Browse files Browse the repository at this point in the history
Bypass emscripten's generated js wrappers when invoking cwraps, this may improve cross-language inlining
Fix signature for a cwrap that was missing an arg
  • Loading branch information
kg authored May 9, 2023
1 parent b2d730c commit f576c78
Showing 1 changed file with 43 additions and 13 deletions.
56 changes: 43 additions & 13 deletions src/mono/wasm/runtime/cwraps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const fn_signatures: SigLine[] = [
[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
Expand Down Expand Up @@ -98,10 +98,10 @@ const fn_signatures: SigLine[] = [
[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"]],
Expand Down Expand Up @@ -268,6 +268,42 @@ export const enum I52Error {
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];
Expand All @@ -277,18 +313,12 @@ export function init_c_exports(): void {
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;
}
}
Expand Down

0 comments on commit f576c78

Please sign in to comment.