-
Notifications
You must be signed in to change notification settings - Fork 200
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
[NativeAOT LLVM] Enable JS interop #2440
Conversation
@maraf Sorry if I'm asking something irrelevant here, but do I understand correctly that there are plans to move WASM target from Mono to NativeAOT/LLVM? If that's the case, will the existing "high-level" JS interop API (the |
There is no such plan at the moment. Anyway NativeAOT/LLVM has come a long way and we are looking at comparison
The goal of the #2434 is to have the same/close as possible API for both Mono and NativeAOT/LLVM in the context of the browser, so that is possible try to wasmbrowser based apps on NativeAOT/LLVM. |
@@ -22,7 +22,8 @@ | |||
</ItemGroup> | |||
|
|||
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'browser'"> | |||
<Compile Include="$(CommonPath)Interop\Browser\Interop.Runtime.cs" Link="System\Runtime\InteropServices\JavaScript\Interop\Interop.Runtime.cs" /> | |||
<Compile Include="$(CommonPath)Interop\Browser\Interop.Runtime.cs" Link="System\Runtime\InteropServices\JavaScript\Interop\Interop.Runtime.cs" Condition="'$(RuntimeFlavor)' != 'CoreCLR'" /> |
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.
libraries build system is not setup to build different binaries per runtime flavor. We have all libraries (except CoreLib) 100% shared between all runtimes flavors.
This change is ok as a quick hack for runtimelab, but it would not be upstreamable. Add a comment about it?
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.
(The proper way to do this would be to come up with a scheme that works for all runtime flavors and/or move any runtime specific parts into CoreLib.)
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.
I would expect this can be solved similar to Linq.Expressions, with an internal feature switch (always off for Mono, always on for NativeAOT).
internal static partial int Math(int a, int b, int c); | ||
|
||
[JSExport] | ||
internal static int Square(int x) | ||
{ | ||
Console.WriteLine($"Computing square of {x}"); | ||
return x^2; | ||
} |
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.
Could you write more tests? For JSExport
, you can take inspiration (aka copy code) from the SharedLibrary
test - the main items of interest are EH and GC exercising methods.
For both JSExport
and JSImport
, it would be good to have some number of methods that exercise the actual marshaling (strings, arrays, tasks, delegates, basically, challening cases from the table in https://learn.microsoft.com/en-us/aspnet/core/blazor/javascript-interoperability/import-export-interop?view=aspnetcore-8.0). Perhaps these tests are already written somewhere and too could be copied...
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.
I guess it will take some time yet before you are able to run this https://github.com/dotnet/runtime/blob/main/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs
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.
Right. We don't need super-comprehensive testing here, but something that would fail if some basic aspect of the system gets broken.
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.
I would rather use standard JS interop tests when we get there. I don't see value in duplicating them here. This is just a smoke test.
Also, a lot of JS interop scenarios don't work yet and are out of scope for this PR
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.
Also, a lot of JS interop scenarios don't work yet and are out of scope for this PR
Right. I would expect that as they are enabled, they get added to this test. Could you add a few simple ones that already work then (like I would expect strings to work)?
One of the reasons why it is valuable to have this testing is that even when you enable the full libraries test suite, it will take > minute to compile, while this test will take much less. Libraries tests are not suitable for inner loop.
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.
Strings for example don't work
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.
Interesting that they don't. Well, let's leave this be until they do.
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.
We need dotnet/runtime#95180 for strings
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.
We need dotnet/runtime#95180 for strings
Not in time for this PR, but I will start the next merge soon.
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.
It's ok, no rush on that one, I have other things to do :)
src/libraries/Common/src/Interop/Browser/Interop.Runtime.NativeAOT.cs
Outdated
Show resolved
Hide resolved
BindJSFunction(function_name, function_name.Length, module_name, module_name.Length, signature, out bound_function_js_handle, out is_exception); | ||
if (is_exception != 0) | ||
result = "Runtime.BindJSFunction failed"; | ||
else | ||
result = ""; |
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.
The original Mono functions were internal calls and would run in cooperative GC mode (i. e. as if they were managed code). DllImport
is PInvoke, which puts the code into preemptive mode. I wonder if this will cause problems.
(Code in preemptive mode moslty cannot touch managed state).
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.
what's the plan for running GC for NAOT on browser ? What would trigger it and what would schedule finalizers ?
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.
what's the plan for running GC for NAOT on browser ? What would trigger it and what would schedule finalizers ?
Same as on other platforms - you GC whenever GC decides its time to GC. Practically, this will happens on allocations, or explicit GC.Collect
s.
Finalization is a little bit NYI right now (#2240), but it could follow the same plan (nice because WASI would have to do that), or be hooked into the event loop.
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.
I guess we need to make decision about yielding to browser event loop.
Big part of JS interop is moot without it (promises, network events, UI).
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.
Well, I would expect the yielding to happen naturally in async code, as you hit await
s and such. GC shouldn't really play much into it? We would of course have the Browser-specific thread pool implementation.
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.
Just a few comments, we are quite close. Thank you for collapsing back TS changes!
src/libraries/Common/src/Interop/Browser/Interop.Runtime.NativeAOT.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Browser/Interop.Runtime.NativeAOT.cs
Outdated
Show resolved
Hide resolved
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 modulo two questions and assuming green CI. Thank you!
I would also ask to add a note about the JSInterop library build workaround to #2434.
@@ -60,6 +61,15 @@ export function mono_wasm_new_root_buffer_from_pointer(offset: VoidPtr, capacity | |||
* Releasing this root will not de-allocate the root space. You still need to call .release(). | |||
*/ | |||
export function mono_wasm_new_external_root<T extends MonoObject>(address: VoidPtr | MonoObjectRef): WasmRoot<T> { | |||
if (NativeAOT) { |
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.
Since we don't need GC roots for MonoString*
and we will delete legacy interop soon, I hope that we could figure out way how to get rid of all roots too (on main). That would make your life easier.
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.
I'm looking forward to it
mono_wasm_bind_js_function
andmono_wasm_bind_cs_function
are duplicated for NativeAOT caseDisableImplicitFrameworkReferences=true
in tests, generators are added as explicit referencesContributes to #2434