-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[wasm] Lazy init of [JSExport] bindings #77293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Tagging subscribers to 'arch-wasm': @lewing Issue DetailsThe original code was generating the initializer into the same class as the exported method. Next step could be to remove
|
...braries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs
Outdated
Show resolved
Hide resolved
...braries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/JSExportGenerator.cs
Outdated
Show resolved
Hide resolved
|
The results look very good: These are close to times before regression: |
This comment was marked as resolved.
This comment was marked as resolved.
|
Generated code looks like this // <auto-generated/>
namespace System.Runtime.InteropServices.JavaScript
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute]
unsafe class __GeneratedInitializer
{
static bool initialized;
[global::System.Runtime.CompilerServices.ModuleInitializerAttribute]
static internal void __Net7SelfInit_()
{
if (Environment.Version.Major == 7)
{
__Register_();
}
}
[global::System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute(
"__Wrapper_ConsoleWriteLine_695648116", "System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper",
"System.Runtime.InteropServices.JavaScript.Tests")]
static void __Register_()
{
if (initialized || global::System.Runtime.InteropServices.RuntimeInformation.OSArchitecture != global::System.Runtime.InteropServices.Architecture.Wasm)
return;
initialized = true;
global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindManagedFunction(
"[System.Runtime.InteropServices.JavaScript.Tests]System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper:ConsoleWriteLine",
695648116, new global::System.Runtime.InteropServices.JavaScript.JSMarshalerType[]{
global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard,
global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.String});
}
}
}
namespace System.Runtime.InteropServices.JavaScript.Tests
{
public unsafe partial class JavaScriptTestHelper
{
internal static unsafe void __Wrapper_ConsoleWriteLine_695648116(global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument* __arguments_buffer)
{
string message;
ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __arg_exception = ref __arguments_buffer[0];
ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __arg_return = ref __arguments_buffer[1];
// Setup - Perform required setup.
ref global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument __message_native__js_arg = ref __arguments_buffer[2];
// Unmarshal - Convert native data to managed data.
__message_native__js_arg.ToManaged(out message);
try
{
System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper.ConsoleWriteLine(message);
}
catch (global::System.Exception ex)
{
__arg_exception.ToJS(ex);
}
}
}
} |
|
@jkoritzinsky when net8 SDK is targeting Net7, does it use the analyzers from the net7 targeting pack or from net8 targeting pack ? |
global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding.BindManagedFunction(
"[System.Runtime.InteropServices.JavaScript.Tests]System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper:ConsoleWriteLine",
695648116, new global::System.Runtime.InteropServices.JavaScript.JSMarshalerType[]{
global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.Discard,
global::System.Runtime.InteropServices.JavaScript.JSMarshalerType.String});I assume the magical number is some kind of hash which we use to make sure to generate unique method name for the given method "wrapper". |
|
The magical number is there just to differentiate multiple methods with same name but different signature. Could we pass delegate to It also has to work in AOT scenarios. |
|
This is currently blocked on Net7/Net8 of |
|
To make this friendly to memory snapshot, we need to allow the JS side to enforce the binding refresh. Maybe |
|
I tested forward and backward compatibility with Net7. I will leave fixing muti-threading for the next PR. |
|
/azp run runtime-wasm |
|
Azure Pipelines successfully started running 1 pipeline(s). |
maraf
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM

The original code was generating the initializer into the same class as the exported method.
It triggers static constructors on classes with exported members.
That could be unexpected side-effect for the developers with performance or behavioral consequences.
__Register_System.Runtime.InteropServices.JavaScript.__GeneratedInitializer.__Register_method is now called when JS side requests bindings viagetAssemblyExportsAPI__Net7SelfInit_method with[ModuleInitializer].__Register_from trimming.__Register_on Net7 runtime because it doesn't call__Register_from JS.This considers following combinations
__GeneratedInitializerclass in the assembly and call module cctor instead.__Register_on when on Net7__GeneratedInitializerclass in the assembly and module cctor will be cheap empty operationFixes #75598