Wasm: Efficient calls from Javascript to Dotnet
Mono has these methods
https://github.com/vargaz/mono/blob/be4037c2a3e70fdc6517e6aa0adb41981323639d/sdks/wasm/src/driver.c#L414-L426
Which allow the javascript to query via strings for classes and methods and then use those references to invoke dotnet methods (static and instance) from javascript. I'm not sure how exactly it's allowing that lookup at runtime, through reflection is the obvious way from user land, but I imagine Mono is doing something better. Could the same be done for CoreRT without reflection? Mono is returning mono specific types, e.g. MonoMethod* but might be better to make those just opaque IntPtrs as in java script land they are just number type anyway. I presume to start the methods would be implemented in CoreRT as somethinglike
[UnmanagedCallersOnly(EntryPoint = "corert_wasm_invoke_method", CallingConvention = CallingConvention.Cdecl)]
public static int InvokeMethod(IntPtr method, IntPtr this_arg, IntPtr methodParams, IntPtr out_exc)
{
throw new Exception("NYI");
}
Frameworks like Uno and Blazor do a lot of interop right now, especially as interface-types is still to be specified in Wasm, but even when interface-types make it to the browser I would think there would still be a need for this.
If its not possible, then I guess the user could just create a bunch of UnmanagedCallersOnly methods for all the known entry points. Wouldn't be dynamic, but might be enough. I don't know the whole set of use cases for Blazor/Uno to answer that.
We would need to use reflection for this, at least as the first approximation. My first thought would be to simply represent the IntPtr method as a GCHandle to a normal reflection MethodInfo.
Reflection invoke is relatively fast in CoreRT (once you have the MethodInfo - last time I measured it, it was 4x faster than CoreCLR).
Depending on how the semantics of InvokeMethod are defined, we could eventually replace MethodInfo.Invoke with something more customized if needed. (E.g. if InvokeMethod doesn't do the implicit widenings and type conversions that reflection does for you - where you can pass a boxed sbyte to a method that takes an int and Invoke will widen that for you - that's one of the places that could be stripped to make things faster).