Wasm: Provide implementation for InternalCall in external project
yowl opened this issue · comments
To get interoperability with mono WebAssembly, some methods that are InternalCall
are needed , such as https://github.com/mono/WebAssembly.JSInterop/blob/9e65a41cf1043ce29c7d722bd3885648a653e734/src/WebAssembly.JSInterop/InternalCalls.cs#L14-L15.
I'm currently working around this with something like
if (callee.IsInternalCall)
{
if (callee.Name == "InvokeJS")
{
var coreRtJsInternalCallsType = _compilation.TypeSystemContext
.GetModuleForSimpleName("CoreRT.WebAssembly.Interop")
.GetKnownType("CoreRT.WebAssembly.Interop", "InternalCalls");
callee = coreRtJsInternalCallsType.GetMethod("InvokeJS", null);
}
in ILToWebAssemblyImporter.cs
, ImportCall
but can I do this in a separate dll without substituting the method in Ilc?
The mapping needs to be somewhere. We usually place the mapping on the InternalCall
itself, like so:
Then the compiler just substitutes calls to this method with "call to an external symbol named in the RuntimeImportAttribute
". We sometimes define the symbol in managed code again, using a RuntimeExportAttribute. But sometimes it's defined in C/C++/asm.
Since I assume you're not building your own WebAssembly.JSinterop (but that would be an option), a thing that comes to my mind would be a convention-based approach: if there's an InternalCall in an assembly named WebAssembly.JSinterop, look for a method with the same name and signature, on a type with the same name, but in the CoreRT.WebAssembly.Interop assembly. That way you don't have to hardcode the full list in the compiler.
I can't really do the same as the InternalCall is in an external project: https://github.com/unoplatform/uno/blob/024eebddd33ac0dfa6b6d8ea0871d5c6effc9f12/src/Uno.Foundation/Runtime.wasm.cs#L40.
" you're not building your own WebAssembly.JSinterop" I am trying this route:
namespace WebAssembly
{
namespace JSInterop
{
public static class InternalCalls
{
// Matches this signature:
// https://github.com/mono/mono/blob/f24d652d567c4611f9b4e3095be4e2a1a2ab23a4/sdks/wasm/driver.c#L21
[RuntimeExport("InvokeJSUnmarshalled")]
public static IntPtr InvokeJSUnmarshalled(out string exception, string js, IntPtr p1, IntPtr p2, IntPtr p3)
{
// convention : if the methodId is known, then js is null and p1 is the method id
return CoreRT.WebAssembly.Interop.InternalCalls.InvokeJSUnmarshalledInternal(js, js?.Length ?? 0, p1, p2, p3, out exception);
}
}
}
}
However that doesn't get found as the mapping as it seems to want to find it in Uno.Foundation.Runtime.WebAssembly
Oh, okay. I guess you'll need to keep this hardcoded as-is, to get compatibility with Mono:
The Mono team always prefers whatever quick hack gets the job done (TODO: what happens when two types in different assemblies have the same FQN?
) - here the hack is to hardcode a name/namespace in the runtime, which means we need to hardcode in the compiler - there's no opportunity to inject an indirection.