From cac6aef7322e4930b20049ddaff59eae3e308b3a Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 4 May 2023 13:55:26 +0200 Subject: [PATCH 01/25] wip --- eng/liveBuilds.targets | 8 +- eng/testing/tests.browser.targets | 2 +- .../Directory.Build.props | 10 +- src/mono/sample/wasm/Directory.Build.targets | 2 +- .../sample/wasm/browser-advanced/index.html | 4 +- .../wasm/browser-bench/appstart-frame.html | 4 +- .../Wasm.Browser.WebPack.Sample.csproj | 8 +- .../Wasm.Node.WebPack.Sample.csproj | 8 +- src/mono/wasm/README.md | 6 +- .../wasm/Wasm.Build.Tests/BuildTestBase.cs | 42 +- .../FlagsChangeRebuildTest.cs | 2 +- .../NativeRebuildTestsBase.cs | 6 +- .../NoopNativeRebuildTest.cs | 2 +- .../SimpleSourceChangeRebuildTest.cs | 2 +- .../Wasm.Build.Tests/WasmTemplateTests.cs | 2 +- src/mono/wasm/build/WasmApp.Native.targets | 22 +- src/mono/wasm/build/WasmApp.targets | 18 +- src/mono/wasm/runtime/CMakeLists.txt | 22 +- src/mono/wasm/runtime/assets.ts | 447 +----------- src/mono/wasm/runtime/cancelable-promise.ts | 8 +- src/mono/wasm/runtime/class-loader.ts | 22 +- src/mono/wasm/runtime/config.ts | 28 - src/mono/wasm/runtime/cwraps.ts | 2 +- src/mono/wasm/runtime/diagnostics-mock.d.ts | 3 +- .../wasm/runtime/diagnostics-mock.d.ts.sha256 | 2 +- src/mono/wasm/runtime/diagnostics/index.ts | 2 +- .../runtime/diagnostics/mock/environment.ts | 7 +- .../runtime/diagnostics/mock/export-types.ts | 2 +- .../wasm/runtime/diagnostics/mock/index.ts | 2 +- .../wasm/runtime/diagnostics/mock/types.ts | 2 +- .../diagnostics/server_pthread/index.ts | 5 +- .../server_pthread/ipc-protocol/serializer.ts | 1 - .../diagnostics/server_pthread/mock-remote.ts | 4 +- .../server_pthread/protocol-socket.ts | 2 +- .../server_pthread/socket-connection.ts | 2 +- src/mono/wasm/runtime/dotnet.d.ts | 60 +- .../wasm/runtime/es6/dotnet.es6.extpost.js | 4 - src/mono/wasm/runtime/es6/dotnet.es6.lib.js | 18 +- src/mono/wasm/runtime/es6/dotnet.es6.pre.js | 2 +- src/mono/wasm/runtime/export-api.ts | 6 +- src/mono/wasm/runtime/exports.ts | 31 +- src/mono/wasm/runtime/gc-handles.ts | 2 +- src/mono/wasm/runtime/globals.ts | 68 +- src/mono/wasm/runtime/http.ts | 5 +- src/mono/wasm/runtime/hybrid-globalization.ts | 10 +- src/mono/wasm/runtime/icu.ts | 68 -- src/mono/wasm/runtime/invoke-cs.ts | 6 +- src/mono/wasm/runtime/invoke-js.ts | 12 +- .../wasm/runtime/jiterpreter-interp-entry.ts | 2 +- src/mono/wasm/runtime/jiterpreter-jit-call.ts | 2 +- src/mono/wasm/runtime/jiterpreter-support.ts | 1 - .../runtime/jiterpreter-trace-generator.ts | 662 +++++++++--------- src/mono/wasm/runtime/jiterpreter.ts | 4 +- src/mono/wasm/runtime/loader/assets.ts | 416 +++++++++++ .../runtime/{ => loader}/blazor/BootConfig.ts | 52 +- .../blazor/WebAssemblyResourceLoader.ts | 4 +- .../{ => loader}/blazor/_Integration.ts | 131 ++-- .../runtime/{ => loader}/blazor/_Polyfill.ts | 5 +- src/mono/wasm/runtime/loader/config.ts | 110 +++ src/mono/wasm/runtime/loader/exit.ts | 154 ++++ src/mono/wasm/runtime/loader/globals.ts | 62 ++ src/mono/wasm/runtime/loader/icu.ts | 71 ++ src/mono/wasm/runtime/loader/index.ts | 14 + src/mono/wasm/runtime/loader/logging.ts | 88 +++ src/mono/wasm/runtime/loader/polyfills.ts | 128 ++++ .../{ => loader}/promise-controller.ts | 31 +- .../runtime/{run-outer.ts => loader/run.ts} | 83 ++- src/mono/wasm/runtime/logging.ts | 89 +-- src/mono/wasm/runtime/managed-exports.ts | 2 +- src/mono/wasm/runtime/marshal-to-cs.ts | 2 +- src/mono/wasm/runtime/marshal-to-js.ts | 13 +- src/mono/wasm/runtime/marshal.ts | 2 +- src/mono/wasm/runtime/memory.ts | 2 +- src/mono/wasm/runtime/modularize-dotnet.md | 2 +- src/mono/wasm/runtime/net6-legacy/buffers.ts | 2 +- .../wasm/runtime/net6-legacy/corebindings.ts | 3 +- src/mono/wasm/runtime/net6-legacy/cs-to-js.ts | 6 +- .../wasm/runtime/net6-legacy/export-types.ts | 2 +- .../runtime/net6-legacy/exports-legacy.ts | 8 +- src/mono/wasm/runtime/net6-legacy/globals.ts | 2 +- src/mono/wasm/runtime/net6-legacy/js-to-cs.ts | 2 +- .../runtime/net6-legacy/method-binding.ts | 2 +- .../wasm/runtime/net6-legacy/method-calls.ts | 2 +- src/mono/wasm/runtime/polyfills.ts | 225 ++---- src/mono/wasm/runtime/profiler.ts | 3 +- src/mono/wasm/runtime/promise-utils.ts | 8 - .../wasm/runtime/pthreads/browser/index.ts | 9 +- .../shared/emscripten-replacements.ts | 10 +- .../wasm/runtime/pthreads/shared/index.ts | 2 +- .../wasm/runtime/pthreads/worker/index.ts | 19 +- src/mono/wasm/runtime/rollup.config.js | 38 +- src/mono/wasm/runtime/roots.ts | 2 +- src/mono/wasm/runtime/run.ts | 139 +--- src/mono/wasm/runtime/snapshot.ts | 6 +- src/mono/wasm/runtime/startup.ts | 313 +++------ src/mono/wasm/runtime/strings.ts | 2 +- src/mono/wasm/runtime/types/blazor.ts | 48 ++ src/mono/wasm/runtime/types/consts.d.ts | 4 +- .../wasm/runtime/{ => types}/export-types.ts | 10 +- .../runtime/{types-api.ts => types/index.ts} | 8 +- .../runtime/{types.ts => types/internal.ts} | 151 ++-- src/mono/wasm/runtime/web-socket.ts | 5 +- src/mono/wasm/runtime/workers/README.md | 2 +- src/mono/wasm/symbolicator/Program.cs | 2 +- src/mono/wasm/wasm.proj | 10 +- .../ComputeWasmPublishAssets.cs | 6 +- src/tasks/WasmAppBuilder/WasmAppBuilder.cs | 31 +- .../WasmAppBuilder/WasmAppBuilderBaseTask.cs | 2 +- 108 files changed, 2186 insertions(+), 2033 deletions(-) delete mode 100644 src/mono/wasm/runtime/config.ts create mode 100644 src/mono/wasm/runtime/loader/assets.ts rename src/mono/wasm/runtime/{ => loader}/blazor/BootConfig.ts (50%) rename src/mono/wasm/runtime/{ => loader}/blazor/WebAssemblyResourceLoader.ts (98%) rename src/mono/wasm/runtime/{ => loader}/blazor/_Integration.ts (75%) rename src/mono/wasm/runtime/{ => loader}/blazor/_Polyfill.ts (87%) create mode 100644 src/mono/wasm/runtime/loader/config.ts create mode 100644 src/mono/wasm/runtime/loader/exit.ts create mode 100644 src/mono/wasm/runtime/loader/globals.ts create mode 100644 src/mono/wasm/runtime/loader/icu.ts create mode 100644 src/mono/wasm/runtime/loader/index.ts create mode 100644 src/mono/wasm/runtime/loader/logging.ts create mode 100644 src/mono/wasm/runtime/loader/polyfills.ts rename src/mono/wasm/runtime/{ => loader}/promise-controller.ts (69%) rename src/mono/wasm/runtime/{run-outer.ts => loader/run.ts} (78%) delete mode 100644 src/mono/wasm/runtime/promise-utils.ts create mode 100644 src/mono/wasm/runtime/types/blazor.ts rename src/mono/wasm/runtime/{ => types}/export-types.ts (80%) rename src/mono/wasm/runtime/{types-api.ts => types/index.ts} (96%) rename src/mono/wasm/runtime/{types.ts => types/internal.ts} (77%) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 5f7dcb8c43b47c..18453b2ae119dc 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -195,11 +195,13 @@ @@ -231,7 +233,7 @@ diff --git a/eng/testing/tests.browser.targets b/eng/testing/tests.browser.targets index ac4796a41af24d..dbb7205910b10c 100644 --- a/eng/testing/tests.browser.targets +++ b/eng/testing/tests.browser.targets @@ -105,7 +105,7 @@ <_XHarnessArgs Condition="'$(IsFunctionalTest)' == 'true'" >$(_XHarnessArgs) --expected-exit-code=$(ExpectedExitCode) <_XHarnessArgs Condition="'$(WasmXHarnessArgs)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgs) <_XHarnessArgs Condition="('$(WasmEnableThreads)' == 'true' or '$(WasmEnablePerfTracing)' == 'true') and '$(_XHarnessArs.Contains("--web-server-use-cop")' != 'true'">$(_XHarnessArgs) --web-server-use-cop - <_XHarnessArgs >$(_XHarnessArgs) -s dotnet.js.symbols + <_XHarnessArgs >$(_XHarnessArgs) -s dotnet.native.js.symbols <_XHarnessArgs Condition="'$(_UseWasmSymbolicator)' == 'true'" >$(_XHarnessArgs) --symbol-patterns wasm-symbol-patterns.txt <_XHarnessArgs Condition="'$(_UseWasmSymbolicator)' == 'true'" >$(_XHarnessArgs) --symbolicator WasmSymbolicator.dll,Microsoft.WebAssembly.Internal.SymbolicatorWrapperForXHarness <_XHarnessArgs Condition="'$(_WasmBrowserPathForTests)' != ''" >$(_XHarnessArgs) "--browser-path=$(_WasmBrowserPathForTests)" diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props index 5760758d70ecb5..14c9aa9b4213dc 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props @@ -237,11 +237,13 @@ - - + + + + - + @@ -250,7 +252,6 @@ - @@ -271,6 +272,7 @@ + diff --git a/src/mono/sample/wasm/Directory.Build.targets b/src/mono/sample/wasm/Directory.Build.targets index 7ff3c4d09a7514..448b2e65c0893f 100644 --- a/src/mono/sample/wasm/Directory.Build.targets +++ b/src/mono/sample/wasm/Directory.Build.targets @@ -31,7 +31,7 @@ $(TargetFileName) " Outputs=" - bin/$(Configuration)/AppBundle/dotnet.wasm; + bin/$(Configuration)/AppBundle/dotnet.native.wasm; bin/$(Configuration)/AppBundle/$(_WasmMainJSFileName); "> diff --git a/src/mono/sample/wasm/browser-advanced/index.html b/src/mono/sample/wasm/browser-advanced/index.html index 0532ef8fcef32d..3489dafc9474a6 100644 --- a/src/mono/sample/wasm/browser-advanced/index.html +++ b/src/mono/sample/wasm/browser-advanced/index.html @@ -10,7 +10,9 @@ - + + + diff --git a/src/mono/sample/wasm/browser-bench/appstart-frame.html b/src/mono/sample/wasm/browser-bench/appstart-frame.html index 4a1945c9aad6d5..fbb1c162849337 100644 --- a/src/mono/sample/wasm/browser-bench/appstart-frame.html +++ b/src/mono/sample/wasm/browser-bench/appstart-frame.html @@ -10,7 +10,9 @@ - + + + diff --git a/src/mono/sample/wasm/browser-webpack/Wasm.Browser.WebPack.Sample.csproj b/src/mono/sample/wasm/browser-webpack/Wasm.Browser.WebPack.Sample.csproj index cc956fb3e9ef4d..bb694f24f38f5f 100644 --- a/src/mono/sample/wasm/browser-webpack/Wasm.Browser.WebPack.Sample.csproj +++ b/src/mono/sample/wasm/browser-webpack/Wasm.Browser.WebPack.Sample.csproj @@ -10,13 +10,17 @@ - + + + diff --git a/src/mono/sample/wasm/node-webpack/Wasm.Node.WebPack.Sample.csproj b/src/mono/sample/wasm/node-webpack/Wasm.Node.WebPack.Sample.csproj index c8e021906c4e8e..b10e78238aef41 100644 --- a/src/mono/sample/wasm/node-webpack/Wasm.Node.WebPack.Sample.csproj +++ b/src/mono/sample/wasm/node-webpack/Wasm.Node.WebPack.Sample.csproj @@ -5,13 +5,17 @@ - + + + diff --git a/src/mono/wasm/README.md b/src/mono/wasm/README.md index cfeea4b099526e..e266fe31f6917a 100644 --- a/src/mono/wasm/README.md +++ b/src/mono/wasm/README.md @@ -133,13 +133,13 @@ The wrapper script used to actually run these tests, accepts: Exceptions thrown after the runtime starts get symbolicating from js itself. Exceptions before that, like asserts containing native traces get symbolicated by xharness using `src/mono/wasm/symbolicator`. -If you need to symbolicate some traces manually, then you need the corresponding `dotnet.js.symbols` file. Then: +If you need to symbolicate some traces manually, then you need the corresponding `dotnet.native.js.symbols` file. Then: ```console -src/mono/wasm/symbolicator$ dotnet run /path/to/dotnet.js.symbols /path/to/file/with/traces +src/mono/wasm/symbolicator$ dotnet run /path/to/dotnet.native.js.symbols /path/to/file/with/traces ``` -When not relinking, or not building with AOT, you can find `dotnet.js.symbols` in the runtime pack. +When not relinking, or not building with AOT, you can find `dotnet.native.js.symbols` in the runtime pack. ## Debugger tests on macOS diff --git a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs index 6dc3e5e525468d..931fb97bc92099 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs @@ -621,7 +621,7 @@ protected void AssertDotNetNativeFiles(NativeFilesType type, string config, bool _ => throw new ArgumentOutOfRangeException(nameof(type)) }; - AssertSameFile(Path.Combine(srcDir, "dotnet.wasm"), Path.Combine(binFrameworkDir, "dotnet.wasm"), label); + AssertSameFile(Path.Combine(srcDir, "dotnet.native.wasm"), Path.Combine(binFrameworkDir, "dotnet.native.wasm"), label); // find dotnet*js string? dotnetJsPath = Directory.EnumerateFiles(binFrameworkDir) @@ -630,13 +630,13 @@ protected void AssertDotNetNativeFiles(NativeFilesType type, string config, bool .SingleOrDefault(); Assert.True(!string.IsNullOrEmpty(dotnetJsPath), $"[{label}] Expected to find dotnet*js in {binFrameworkDir}"); - AssertSameFile(Path.Combine(srcDir, "dotnet.js"), dotnetJsPath!, label); + AssertSameFile(Path.Combine(srcDir, "dotnet.native.js"), dotnetJsPath!, label); if (type != NativeFilesType.FromRuntimePack) { // check that the files are *not* from runtime pack - AssertNotSameFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.wasm"), Path.Combine(binFrameworkDir, "dotnet.wasm"), label); - AssertNotSameFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.js"), dotnetJsPath!, label); + AssertNotSameFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.native.wasm"), Path.Combine(binFrameworkDir, "dotnet.native.wasm"), label); + AssertNotSameFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.native.js"), dotnetJsPath!, label); } } @@ -667,9 +667,11 @@ protected static void AssertBasicAppBundle(string bundleDir, var filesToExist = new List() { mainJS, - "dotnet.wasm", + "dotnet.native.wasm", "mono-config.json", - "dotnet.js" + "dotnet.js", + "dotnet.native.js", + "dotnet.runtime.js" }; if (isBrowserProject) @@ -751,20 +753,20 @@ void AssertIcuAssets() protected static void AssertDotNetWasmJs(string bundleDir, bool fromRuntimePack, string targetFramework) { - AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.wasm"), - Path.Combine(bundleDir, "dotnet.wasm"), - "Expected dotnet.wasm to be same as the runtime pack", + AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.native.wasm"), + Path.Combine(bundleDir, "dotnet.native.wasm"), + "Expected dotnet.native.wasm to be same as the runtime pack", same: fromRuntimePack); - AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.js"), - Path.Combine(bundleDir, "dotnet.js"), - "Expected dotnet.js to be same as the runtime pack", + AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.native.js"), + Path.Combine(bundleDir, "dotnet.native.js"), + "Expected dotnet.native.js to be same as the runtime pack", same: fromRuntimePack); } protected static void AssertDotNetJsSymbols(string bundleDir, bool fromRuntimePack, string targetFramework) - => AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.js.symbols"), - Path.Combine(bundleDir, "dotnet.js.symbols"), + => AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.native.js.symbols"), + Path.Combine(bundleDir, "dotnet.native.js.symbols"), same: fromRuntimePack); protected static void AssertFilesDontExist(string dir, string[] filenames, string? label = null) @@ -820,17 +822,17 @@ protected void AssertBlazorBundle(string config, bool isPublish, bool dotnetWasm binFrameworkDir ??= FindBlazorBinFrameworkDir(config, isPublish, targetFramework); AssertBlazorBootJson(config, isPublish, targetFramework, binFrameworkDir: binFrameworkDir); - AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.wasm"), - Path.Combine(binFrameworkDir, "dotnet.wasm"), - "Expected dotnet.wasm to be same as the runtime pack", + AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.native.wasm"), + Path.Combine(binFrameworkDir, "dotnet.native.wasm"), + "Expected dotnet.native.wasm to be same as the runtime pack", same: dotnetWasmFromRuntimePack); string? dotnetJsPath = Directory.EnumerateFiles(binFrameworkDir, "dotnet.*.js").FirstOrDefault(); Assert.True(dotnetJsPath != null, $"Could not find blazor's dotnet*js in {binFrameworkDir}"); - AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.js"), + AssertFile(Path.Combine(s_buildEnv.GetRuntimeNativeDir(targetFramework), "dotnet.native.js"), dotnetJsPath!, - "Expected dotnet.js to be same as the runtime pack", + "Expected dotnet.native.js to be same as the runtime pack", same: dotnetWasmFromRuntimePack); } @@ -847,7 +849,7 @@ protected void AssertBlazorBootJson(string config, bool isPublish, string target Assert.NotNull(runtimeObj); string msgPrefix=$"[{( isPublish ? "publish" : "build" )}]"; - Assert.True(runtimeObj!.Where(kvp => kvp.Key == "dotnet.wasm").Any(), $"{msgPrefix} Could not find dotnet.wasm entry in blazor.boot.json"); + Assert.True(runtimeObj!.Where(kvp => kvp.Key == "dotnet.native.wasm").Any(), $"{msgPrefix} Could not find dotnet.native.wasm entry in blazor.boot.json"); Assert.True(runtimeObj!.Where(kvp => kvp.Key.StartsWith("dotnet.", StringComparison.OrdinalIgnoreCase) && kvp.Key.EndsWith(".js", StringComparison.OrdinalIgnoreCase)).Any(), $"{msgPrefix} Could not find dotnet.*js in {bootJson}"); diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/FlagsChangeRebuildTest.cs b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/FlagsChangeRebuildTest.cs index ffbc0fd33c6b62..67e7e32aba68bf 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/FlagsChangeRebuildTest.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/FlagsChangeRebuildTest.cs @@ -36,7 +36,7 @@ public void ExtraEmccFlagsSetButNoRealChange(BuildArgs buildArgs, string extraCF (buildArgs, BuildPaths paths) = FirstNativeBuild(s_mainReturns42, nativeRelink: true, invariant: false, buildArgs, id); var pathsDict = GetFilesTable(buildArgs, paths, unchanged: true); if (extraLDFlags.Length > 0) - pathsDict.UpdateTo(unchanged: false, "dotnet.wasm", "dotnet.js"); + pathsDict.UpdateTo(unchanged: false, "dotnet.native.wasm", "dotnet.native.js"); var originalStat = StatFiles(pathsDict.Select(kvp => kvp.Value.fullPath)); diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs index aac389bde66bc2..b6a44542b8fec7 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs @@ -164,8 +164,10 @@ internal void CompareStat(IDictionary oldStat, IDictionary kvp.Value.fullPath)); diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/SimpleSourceChangeRebuildTest.cs b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/SimpleSourceChangeRebuildTest.cs index bbe7d602216717..f2bfb33b7bd0ce 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/SimpleSourceChangeRebuildTest.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/SimpleSourceChangeRebuildTest.cs @@ -28,7 +28,7 @@ public void SimpleStringChangeInSource(BuildArgs buildArgs, bool nativeRelink, b string mainAssembly = $"{buildArgs.ProjectName}.dll"; var pathsDict = GetFilesTable(buildArgs, paths, unchanged: true); pathsDict.UpdateTo(unchanged: false, mainAssembly); - pathsDict.UpdateTo(unchanged: !buildArgs.AOT, "dotnet.wasm", "dotnet.js"); + pathsDict.UpdateTo(unchanged: !buildArgs.AOT, "dotnet.native.wasm", "dotnet.native.js"); if (buildArgs.AOT) pathsDict.UpdateTo(unchanged: false, $"{mainAssembly}.bc", $"{mainAssembly}.o"); diff --git a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTests.cs b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTests.cs index 2d9100b6832d59..ea57866fc86fa0 100644 --- a/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/WasmTemplateTests.cs @@ -401,7 +401,7 @@ public void ConsolePublishAndRun(string config, bool aot, bool relinking) } else { - AssertFilesDontExist(Path.Combine(GetBinDir(config), "AppBundle"), new[] { "dotnet.js.symbols" }); + AssertFilesDontExist(Path.Combine(GetBinDir(config), "AppBundle"), new[] { "dotnet.native.js.symbols" }); } string runArgs = $"run --no-build -c {config}"; diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index d7afe274a1cb2f..85b5e1858cb419 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -448,7 +448,7 @@ <_EmccLinkStepArgs Include=""%(_WasmNativeFileForLinking.Identity)"" /> <_WasmLinkDependencies Include="@(_WasmNativeFileForLinking)" /> - <_EmccLinkStepArgs Include="-o "$(_WasmIntermediateOutputPath)dotnet.js"" /> + <_EmccLinkStepArgs Include="-o "$(_WasmIntermediateOutputPath)dotnet.native.js"" /> <_WasmLinkDependencies Include="$(_EmccLinkRsp)" /> <_EmccLinkStepArgs Include="-s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$(_EmccExportedLibraryFunction)" Condition="'$(_EmccExportedLibraryFunction)' != ''" /> @@ -466,7 +466,7 @@ @@ -478,9 +478,9 @@ - - - + + + @@ -488,8 +488,8 @@ - - + @@ -503,10 +503,10 @@ - - - - + + + + <_WasmAssembliesInternal Remove="$(_WasmDedupAssembly)"/> diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index 0d50ada7ad3a20..50ab15441f4266 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -22,7 +22,7 @@ - $(WasmNativeDebugSymbols) - Build with native debug symbols, useful only with `$(RunAOTCompilation)`, or `$(WasmBuildNative)` Defaults to true. - - $(WasmEmitSymbolMap) - Generates a `dotnet.js.symbols` file with a map of wasm function number to name. + - $(WasmEmitSymbolMap) - Generates a `dotnet.native.js.symbols` file with a map of wasm function number to name. - $(WasmDedup) - Whenever to dedup generic instances when using AOT. Defaults to true. - $(WasmProfilers) - Profilers to use @@ -328,10 +328,12 @@ false - <_HasDotnetWasm Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.wasm'">true + <_HasDotnetWasm Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.wasm'">true <_HasDotnetJsWorker Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.worker.js'">true - <_HasDotnetJsSymbols Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js.symbols'">true + <_HasDotnetJsSymbols Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.js.symbols'">true <_HasDotnetJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js'">true + <_HasDotnetNativeJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.js'">true + <_HasDotnetRuntimeJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.runtime.js'">true <_WasmIcuDataFileName Condition="'$(WasmIcuDataFileName)' != '' and Exists('$(WasmIcuDataFileName)')">$(WasmIcuDataFileName) <_WasmIcuDataFileName Condition="'$(WasmIcuDataFileName)' != '' and !Exists('$(WasmIcuDataFileName)')">$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(WasmIcuDataFileName) @@ -343,13 +345,15 @@ - - - + + + + + Exists('$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.native.js.symbols')" /> diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index 4d3781bb924f68..76027eff859811 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -7,14 +7,14 @@ option(DISABLE_WASM_USER_THREADS "defined if the build does not allow user threa option(DISABLE_LEGACY_JS_INTEROP "defined if the build does not support legacy JavaScript interop" OFF) set(CMAKE_EXECUTABLE_SUFFIX ".js") -add_executable(dotnet corebindings.c driver.c pinvoke.c) +add_executable(dotnet.native corebindings.c driver.c pinvoke.c) -target_include_directories(dotnet PUBLIC ${MONO_INCLUDES} ${MONO_OBJ_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}/include/wasm) -target_compile_options(dotnet PUBLIC @${NATIVE_BIN_DIR}/src/emcc-default.rsp @${NATIVE_BIN_DIR}/src/emcc-compile.rsp -DGEN_PINVOKE=1) +target_include_directories(dotnet.native PUBLIC ${MONO_INCLUDES} ${MONO_OBJ_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}/include/wasm) +target_compile_options(dotnet.native PUBLIC @${NATIVE_BIN_DIR}/src/emcc-default.rsp @${NATIVE_BIN_DIR}/src/emcc-compile.rsp -DGEN_PINVOKE=1) -set_target_properties(dotnet PROPERTIES COMPILE_FLAGS ${CONFIGURATION_EMCC_FLAGS}) +set_target_properties(dotnet.native PROPERTIES COMPILE_FLAGS ${CONFIGURATION_EMCC_FLAGS}) -target_link_libraries(dotnet +target_link_libraries(dotnet.native PRIVATE ${ICU_LIB_DIR}/libicuuc.a ${ICU_LIB_DIR}/libicui18n.a @@ -33,17 +33,17 @@ target_link_libraries(dotnet ${NATIVE_BIN_DIR}/libSystem.Globalization.Native.a ${NATIVE_BIN_DIR}/libSystem.IO.Compression.Native.a) -set_target_properties(dotnet PROPERTIES - LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js;${NATIVE_BIN_DIR}/src/es6/runtime.es6.iffe.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js;" - LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp @${NATIVE_BIN_DIR}/src/emcc-link.rsp ${CONFIGURATION_LINK_FLAGS} --extern-pre-js ${NATIVE_BIN_DIR}/src/es6/runtime.es6.iffe.js --pre-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js --js-library ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --extern-post-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js " +set_target_properties(dotnet.native PROPERTIES + LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js;${NATIVE_BIN_DIR}/src/pal_random.lib.js;${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js;" + LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp @${NATIVE_BIN_DIR}/src/emcc-link.rsp ${CONFIGURATION_LINK_FLAGS} --pre-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.pre.js --js-library ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.lib.js --js-library ${NATIVE_BIN_DIR}/src/pal_random.lib.js --extern-post-js ${NATIVE_BIN_DIR}/src/es6/dotnet.es6.extpost.js " RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}") set(ignoreMeWasmOptFlags "${CONFIGURATION_WASM_OPT_FLAGS}") if(CMAKE_BUILD_TYPE STREQUAL "Release") - add_custom_command(TARGET dotnet - POST_BUILD COMMAND ${EMSDK_PATH}/upstream/bin/wasm-opt --enable-exception-handling ${CONFIGURATION_WASM_OPT_FLAGS} --strip-dwarf ${NATIVE_BIN_DIR}/dotnet.wasm -o ${NATIVE_BIN_DIR}/dotnet.wasm - COMMENT "Stripping debug symbols from dotnet.wasm using wasm-opt") + add_custom_command(TARGET dotnet.native + POST_BUILD COMMAND ${EMSDK_PATH}/upstream/bin/wasm-opt --enable-exception-handling ${CONFIGURATION_WASM_OPT_FLAGS} --strip-dwarf ${NATIVE_BIN_DIR}/dotnet.native.wasm -o ${NATIVE_BIN_DIR}/dotnet.native.wasm + COMMENT "Stripping debug symbols from dotnet.native.wasm using wasm-opt") endif() configure_file(wasm-config.h.in include/wasm/wasm-config.h) diff --git a/src/mono/wasm/runtime/assets.ts b/src/mono/wasm/runtime/assets.ts index 37977538ed3a01..a029ff65ae45ac 100644 --- a/src/mono/wasm/runtime/assets.ts +++ b/src/mono/wasm/runtime/assets.ts @@ -3,411 +3,17 @@ import cwraps from "./cwraps"; import { mono_wasm_load_icu_data } from "./icu"; -import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, ENVIRONMENT_IS_WEB, Module, runtimeHelpers } from "./globals"; +import { ENVIRONMENT_IS_SHELL, ENVIRONMENT_IS_WEB, Module, loaderHelpers, runtimeHelpers } from "./globals"; import { parseSymbolMapFile } from "./logging"; import { mono_wasm_load_bytes_into_heap } from "./memory"; import { endMeasure, MeasuredBlock, startMeasure } from "./profiler"; -import { createPromiseController, PromiseAndController } from "./promise-controller"; -import { delay } from "./promise-utils"; -import { abort_startup, beforeOnRuntimeInitialized, memorySnapshotSkippedOrDone } from "./startup"; -import { AssetEntryInternal, mono_assert } from "./types"; -import { AssetBehaviours, AssetEntry, LoadingResource, ResourceRequest } from "./types-api"; +import { AssetEntryInternal } from "./types/internal"; +import { AssetEntry } from "./types"; import { InstantiateWasmSuccessCallback, VoidPtr } from "./types/emscripten"; -const allAssetsInMemory = createPromiseController(); -const allDownloadsQueued = createPromiseController(); -let actual_downloaded_assets_count = 0; -let actual_instantiated_assets_count = 0; -let expected_downloaded_assets_count = 0; -let expected_instantiated_assets_count = 0; -const loaded_files: { url: string, file: string }[] = []; -// in order to prevent net::ERR_INSUFFICIENT_RESOURCES if we start downloading too many files at same time -let parallel_count = 0; -let throttlingPromise: PromiseAndController | undefined; - -// don't `fetch` javaScript files -const skipDownloadsByAssetTypes: { - [k: string]: boolean -} = { - "js-module-threads": true, - "dotnetwasm": true, -}; - -// `response.arrayBuffer()` can't be called twice. Some usecases are calling it on response in the instantiation. -const skipBufferByAssetTypes: { - [k: string]: boolean -} = { - "dotnetwasm": true, - "symbols": true, -}; - -const containedInSnapshotByAssetTypes: { - [k: string]: boolean -} = { - "resource": true, - "assembly": true, - "pdb": true, - "heap": true, - "icu": true, - "js-module-threads": true, - "dotnetwasm": true, -}; - - -// these assets are instantiated differently than the main flow -const skipInstantiateByAssetTypes: { - [k: string]: boolean -} = { - "js-module-threads": true, - "dotnetwasm": true, - "symbols": true, -}; - -export function shouldLoadIcuAsset(asset: AssetEntryInternal): boolean { - return !(asset.behavior == "icu" && asset.name != runtimeHelpers.preferredIcuAsset); -} - -export function resolve_asset_path(behavior: AssetBehaviours) { - const asset: AssetEntryInternal | undefined = runtimeHelpers.config.assets?.find(a => a.behavior == behavior); - mono_assert(asset, () => `Can't find asset for ${behavior}`); - if (!asset.resolvedUrl) { - asset.resolvedUrl = resolve_path(asset, ""); - } - return asset; -} -export async function mono_download_assets(): Promise { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_download_assets"); - runtimeHelpers.maxParallelDownloads = runtimeHelpers.config.maxParallelDownloads || runtimeHelpers.maxParallelDownloads; - runtimeHelpers.enableDownloadRetry = runtimeHelpers.config.enableDownloadRetry || runtimeHelpers.enableDownloadRetry; - try { - const alwaysLoadedAssets: AssetEntryInternal[] = []; - const containedInSnapshotAssets: AssetEntryInternal[] = []; - const promises_of_assets: Promise[] = []; - - for (const a of runtimeHelpers.config.assets!) { - const asset: AssetEntryInternal = a; - mono_assert(typeof asset === "object", "asset must be object"); - mono_assert(typeof asset.behavior === "string", "asset behavior must be known string"); - mono_assert(typeof asset.name === "string", "asset name must be string"); - mono_assert(!asset.resolvedUrl || typeof asset.resolvedUrl === "string", "asset resolvedUrl could be string"); - mono_assert(!asset.hash || typeof asset.hash === "string", "asset resolvedUrl could be string"); - mono_assert(!asset.pendingDownload || typeof asset.pendingDownload === "object", "asset pendingDownload could be object"); - if (containedInSnapshotByAssetTypes[asset.behavior]) { - containedInSnapshotAssets.push(asset); - } else { - alwaysLoadedAssets.push(asset); - } - } - - const countAndStartDownload = (asset: AssetEntryInternal) => { - if (!skipInstantiateByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { - expected_instantiated_assets_count++; - } - if (!skipDownloadsByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { - expected_downloaded_assets_count++; - promises_of_assets.push(start_asset_download(asset)); - } - }; - - // start fetching assets in parallel, only assets which are not part of memory snapshot - for (const asset of alwaysLoadedAssets) { - countAndStartDownload(asset); - } - - // continue after we know if memory snapshot is available or not - await memorySnapshotSkippedOrDone.promise; - - // start fetching assets in parallel, only if memory snapshot is not available. - for (const asset of containedInSnapshotAssets) { - if (!runtimeHelpers.loadedMemorySnapshot) { - countAndStartDownload(asset); - } else { - // Otherwise cleanup in case we were given pending download. It would be even better if we could abort the download. - cleanupAsset(asset); - // tell the debugger it is loaded - if (asset.behavior == "resource" || asset.behavior == "assembly" || asset.behavior == "pdb") { - const url = resolve_path(asset, ""); - const virtualName: string = typeof (asset.virtualPath) === "string" - ? asset.virtualPath - : asset.name; - loaded_files.push({ url: url, file: virtualName }); - } - } - } - - allDownloadsQueued.promise_control.resolve(); - - const promises_of_asset_instantiation: Promise[] = []; - for (const downloadPromise of promises_of_assets) { - promises_of_asset_instantiation.push((async () => { - const asset = await downloadPromise; - if (asset.buffer) { - if (!skipInstantiateByAssetTypes[asset.behavior]) { - const url = asset.pendingDownloadInternal!.url; - mono_assert(asset.buffer && typeof asset.buffer === "object", "asset buffer must be array or buffer like"); - const data = new Uint8Array(asset.buffer!); - cleanupAsset(asset); - - // wait till after onRuntimeInitialized and after memory snapshot is loaded or skipped - await memorySnapshotSkippedOrDone.promise; - await beforeOnRuntimeInitialized.promise; - _instantiate_asset(asset, url, data); - } - if (asset.behavior === "symbols") { - await instantiate_symbols_asset(asset); - cleanupAsset(asset); - } - } else { - const headersOnly = skipBufferByAssetTypes[asset.behavior]; - if (!headersOnly) { - mono_assert(asset.isOptional, "Expected asset to have the downloaded buffer"); - if (!skipDownloadsByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { - expected_downloaded_assets_count--; - } - if (!skipInstantiateByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { - expected_instantiated_assets_count--; - } - } else { - if (skipBufferByAssetTypes[asset.behavior]) { - ++actual_downloaded_assets_count; - } - } - } - })()); - } - - // this await will get past the onRuntimeInitialized because we are not blocking via addRunDependency - // and we are not awating it here - Promise.all(promises_of_asset_instantiation).then(() => { - allAssetsInMemory.promise_control.resolve(); - }).catch(e => { - Module.err("MONO_WASM: Error in mono_download_assets: " + e); - abort_startup(e, true); - }); - // OPTIMIZATION explained: - // we do it this way so that we could allocate memory immediately after asset is downloaded (and after onRuntimeInitialized which happened already) - // spreading in time - // rather than to block all downloads after onRuntimeInitialized or block onRuntimeInitialized after all downloads are done. That would create allocation burst. - } catch (e: any) { - Module.err("MONO_WASM: Error in mono_download_assets: " + e); - throw e; - } -} - -// FIXME: Connection reset is probably the only good one for which we should retry -export async function start_asset_download(asset: AssetEntryInternal): Promise { - try { - return await start_asset_download_with_throttle(asset); - } catch (err: any) { - if (!runtimeHelpers.enableDownloadRetry) { - // we will not re-try if disabled - throw err; - } - if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { - // we will not re-try on shell - throw err; - } - if (asset.pendingDownload && asset.pendingDownloadInternal == asset.pendingDownload) { - // we will not re-try with external source - throw err; - } - if (asset.resolvedUrl && asset.resolvedUrl.indexOf("file://") != -1) { - // we will not re-try with local file - throw err; - } - if (err && err.status == 404) { - // we will not re-try with 404 - throw err; - } - asset.pendingDownloadInternal = undefined; - // second attempt only after all first attempts are queued - await allDownloadsQueued.promise; - try { - return await start_asset_download_with_throttle(asset); - } catch (err) { - asset.pendingDownloadInternal = undefined; - // third attempt after small delay - await delay(100); - return await start_asset_download_with_throttle(asset); - } - } -} - -async function start_asset_download_with_throttle(asset: AssetEntryInternal): Promise { - // we don't addRunDependency to allow download in parallel with onRuntimeInitialized event! - while (throttlingPromise) { - await throttlingPromise.promise; - } - try { - ++parallel_count; - if (parallel_count == runtimeHelpers.maxParallelDownloads) { - if (runtimeHelpers.diagnosticTracing) - console.debug("MONO_WASM: Throttling further parallel downloads"); - throttlingPromise = createPromiseController(); - } - - const response = await start_asset_download_sources(asset); - if (!response) { - return asset; - } - const skipBuffer = skipBufferByAssetTypes[asset.behavior]; - if (skipBuffer) { - return asset; - } - asset.buffer = await response.arrayBuffer(); - ++actual_downloaded_assets_count; - return asset; - } - finally { - --parallel_count; - if (throttlingPromise && parallel_count == runtimeHelpers.maxParallelDownloads - 1) { - if (runtimeHelpers.diagnosticTracing) - console.debug("MONO_WASM: Resuming more parallel downloads"); - const old_throttling = throttlingPromise; - throttlingPromise = undefined; - old_throttling.promise_control.resolve(); - } - } -} - -async function start_asset_download_sources(asset: AssetEntryInternal): Promise { - // we don't addRunDependency to allow download in parallel with onRuntimeInitialized event! - if (asset.pendingDownload) { - asset.pendingDownloadInternal = asset.pendingDownload; - } - if (asset.pendingDownloadInternal && asset.pendingDownloadInternal.response) { - return asset.pendingDownloadInternal.response; - } - if (asset.buffer) { - const buffer = asset.buffer; - asset.buffer = null as any; // GC - asset.pendingDownloadInternal = { - url: "undefined://" + asset.name, - name: asset.name, - response: Promise.resolve({ - arrayBuffer: () => buffer, - headers: { - get: () => undefined, - } - }) as any - }; - return asset.pendingDownloadInternal.response; - } - - const sourcesList = asset.loadRemote && runtimeHelpers.config.remoteSources ? runtimeHelpers.config.remoteSources : [""]; - let response: Response | undefined = undefined; - for (let sourcePrefix of sourcesList) { - sourcePrefix = sourcePrefix.trim(); - // HACK: Special-case because MSBuild doesn't allow "" as an attribute - if (sourcePrefix === "./") - sourcePrefix = ""; - - const attemptUrl = resolve_path(asset, sourcePrefix); - if (asset.name === attemptUrl) { - if (runtimeHelpers.diagnosticTracing) - console.debug(`MONO_WASM: Attempting to download '${attemptUrl}'`); - } else { - if (runtimeHelpers.diagnosticTracing) - console.debug(`MONO_WASM: Attempting to download '${attemptUrl}' for ${asset.name}`); - } - try { - asset.resolvedUrl = attemptUrl; - const loadingResource = download_resource(asset); - asset.pendingDownloadInternal = loadingResource; - response = await loadingResource.response; - if (!response || !response.ok) { - continue;// next source - } - return response; - } - catch (err) { - if (!response) { - response = { - ok: false, - url: attemptUrl, - status: 0, - statusText: "" + err, - } as any; - } - continue; //next source - } - } - const isOkToFail = asset.isOptional || (asset.name.match(/\.pdb$/) && runtimeHelpers.config.ignorePdbLoadErrors); - mono_assert(response, () => `Response undefined ${asset.name}`); - if (!isOkToFail) { - const err: any = new Error(`MONO_WASM: download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`); - err.status = response.status; - throw err; - } else { - Module.out(`MONO_WASM: optional download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`); - return undefined; - } -} - -function resolve_path(asset: AssetEntry, sourcePrefix: string): string { - mono_assert(sourcePrefix !== null && sourcePrefix !== undefined, () => `sourcePrefix must be provided for ${asset.name}`); - let attemptUrl; - const assemblyRootFolder = runtimeHelpers.config.assemblyRootFolder; - if (!asset.resolvedUrl) { - if (sourcePrefix === "") { - if (asset.behavior === "assembly" || asset.behavior === "pdb") { - attemptUrl = assemblyRootFolder - ? (assemblyRootFolder + "/" + asset.name) - : asset.name; - } - else if (asset.behavior === "resource") { - const path = asset.culture && asset.culture !== "" ? `${asset.culture}/${asset.name}` : asset.name; - attemptUrl = assemblyRootFolder - ? (assemblyRootFolder + "/" + path) - : path; - } - else { - attemptUrl = asset.name; - } - } else { - attemptUrl = sourcePrefix + asset.name; - } - attemptUrl = runtimeHelpers.locateFile(attemptUrl); - } - else { - attemptUrl = asset.resolvedUrl; - } - mono_assert(attemptUrl && typeof attemptUrl == "string", "attemptUrl need to be path or url string"); - return attemptUrl; -} - -function download_resource(request: ResourceRequest): LoadingResource { - try { - if (typeof Module.downloadResource === "function") { - const loading = Module.downloadResource(request); - if (loading) return loading; - } - const options: any = {}; - if (request.hash) { - options.integrity = request.hash; - } - const response = runtimeHelpers.fetch_like(request.resolvedUrl!, options); - return { - name: request.name, url: request.resolvedUrl!, response - }; - } catch (err) { - const response = { - ok: false, - url: request.resolvedUrl, - status: 500, - statusText: "ERR29: " + err, - arrayBuffer: () => { throw err; }, - json: () => { throw err; } - }; - return { - name: request.name, url: request.resolvedUrl!, response: Promise.resolve(response) - }; - } -} - // this need to be run only after onRuntimeInitialized event, when the memory is ready -function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) { - if (runtimeHelpers.diagnosticTracing) +export function instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array): void { + if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: Loaded:${asset.name} as ${asset.behavior} size ${bytes.length} from ${url}`); const mark = startMeasure(); @@ -425,7 +31,7 @@ function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) { case "resource": case "assembly": case "pdb": - loaded_files.push({ url: url, file: virtualName }); + loaderHelpers._loaded_files.push({ url: url, file: virtualName }); // falls through case "heap": case "icu": @@ -444,7 +50,7 @@ function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) { if (fileName.startsWith("/")) fileName = fileName.substr(1); if (parentDirectory) { - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: Creating directory '${parentDirectory}'`); Module.FS_createPath( @@ -454,7 +60,7 @@ function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) { parentDirectory = "/"; } - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: Creating file '${fileName}' in directory '${parentDirectory}'`); if (!mono_wasm_load_data_archive(bytes, parentDirectory)) { @@ -475,8 +81,8 @@ function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) { const hasPpdb = cwraps.mono_wasm_add_assembly(virtualName, offset!, bytes.length); if (!hasPpdb) { - const index = loaded_files.findIndex(element => element.file == virtualName); - loaded_files.splice(index, 1); + const index = loaderHelpers._loaded_files.findIndex(element => element.file == virtualName); + loaderHelpers._loaded_files.splice(index, 1); } } else if (asset.behavior === "pdb") { @@ -490,7 +96,7 @@ function _instantiate_asset(asset: AssetEntry, url: string, bytes: Uint8Array) { cwraps.mono_wasm_add_satellite_assembly(virtualName, asset.culture || "", offset!, bytes.length); } endMeasure(mark, MeasuredBlock.instantiateAsset, asset.name); - ++actual_instantiated_assets_count; + ++loaderHelpers.actual_instantiated_assets_count; } export async function instantiate_wasm_asset( @@ -498,13 +104,13 @@ export async function instantiate_wasm_asset( wasmModuleImports: WebAssembly.Imports, successCallback: InstantiateWasmSuccessCallback, ): Promise { - mono_assert(pendingAsset && pendingAsset.pendingDownloadInternal && pendingAsset.pendingDownloadInternal.response, "Can't load dotnet.wasm"); + mono_assert(pendingAsset && pendingAsset.pendingDownloadInternal && pendingAsset.pendingDownloadInternal.response, "Can't load dotnet.native.wasm"); const response = await pendingAsset.pendingDownloadInternal.response; const contentType = response.headers && response.headers.get ? response.headers.get("Content-Type") : undefined; let compiledInstance: WebAssembly.Instance; let compiledModule: WebAssembly.Module; if (typeof WebAssembly.instantiateStreaming === "function" && contentType === "application/wasm") { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module streaming"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module streaming"); const streamingResult = await WebAssembly.instantiateStreaming(response, wasmModuleImports!); compiledInstance = streamingResult.instance; compiledModule = streamingResult.module; @@ -513,7 +119,7 @@ export async function instantiate_wasm_asset( console.warn("MONO_WASM: WebAssembly resource does not have the expected content type \"application/wasm\", so falling back to slower ArrayBuffer instantiation."); } const arrayBuffer = await response.arrayBuffer(); - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module buffered"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module buffered"); if (ENVIRONMENT_IS_SHELL) { // workaround for old versions of V8 with https://bugs.chromium.org/p/v8/issues/detail?id=13823 compiledModule = new WebAssembly.Module(arrayBuffer); @@ -527,9 +133,7 @@ export async function instantiate_wasm_asset( successCallback(compiledInstance, compiledModule); } -export async function instantiate_symbols_asset( - pendingAsset: AssetEntryInternal, -): Promise { +export async function instantiate_symbols_asset(pendingAsset: AssetEntryInternal): Promise { try { const response = await pendingAsset.pendingDownloadInternal!.response; const text = await response.text(); @@ -590,23 +194,16 @@ export function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): b export async function wait_for_all_assets() { // wait for all assets in memory - await allAssetsInMemory.promise; - if (runtimeHelpers.config.assets) { - mono_assert(actual_downloaded_assets_count == expected_downloaded_assets_count, () => `Expected ${expected_downloaded_assets_count} assets to be downloaded, but only finished ${actual_downloaded_assets_count}`); - mono_assert(actual_instantiated_assets_count == expected_instantiated_assets_count, () => `Expected ${expected_instantiated_assets_count} assets to be in memory, but only instantiated ${actual_instantiated_assets_count}`); - loaded_files.forEach(value => runtimeHelpers.loadedFiles.push(value.url)); - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: all assets are loaded in wasm memory"); + await runtimeHelpers.allAssetsInMemory.promise; + if (loaderHelpers.config.assets) { + mono_assert(loaderHelpers.actual_downloaded_assets_count == loaderHelpers.expected_downloaded_assets_count, () => `Expected ${loaderHelpers.expected_downloaded_assets_count} assets to be downloaded, but only finished ${loaderHelpers.actual_downloaded_assets_count}`); + mono_assert(loaderHelpers.actual_instantiated_assets_count == loaderHelpers.expected_instantiated_assets_count, () => `Expected ${loaderHelpers.expected_instantiated_assets_count} assets to be in memory, but only instantiated ${loaderHelpers.actual_instantiated_assets_count}`); + loaderHelpers._loaded_files.forEach(value => loaderHelpers.loadedFiles.push(value.url)); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: all assets are loaded in wasm memory"); } } // Used by the debugger to enumerate loaded dlls and pdbs export function mono_wasm_get_loaded_files(): string[] { - return runtimeHelpers.loadedFiles; -} - -export function cleanupAsset(asset: AssetEntryInternal) { - // give GC chance to collect resources - asset.pendingDownloadInternal = null as any; // GC - asset.pendingDownload = null as any; // GC - asset.buffer = null as any; // GC + return loaderHelpers.loadedFiles; } \ No newline at end of file diff --git a/src/mono/wasm/runtime/cancelable-promise.ts b/src/mono/wasm/runtime/cancelable-promise.ts index b50e0b0040b69f..1f696a1f31543c 100644 --- a/src/mono/wasm/runtime/cancelable-promise.ts +++ b/src/mono/wasm/runtime/cancelable-promise.ts @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. import { _lookup_js_owned_object } from "./gc-handles"; +import { createPromiseController, loaderHelpers } from "./globals"; import { TaskCallbackHolder } from "./marshal-to-cs"; -import { mono_assert, GCHandle } from "./types"; -import { createPromiseController, getPromiseController, ControllablePromise, assertIsControllablePromise } from "./promise-controller"; +import { ControllablePromise, GCHandle } from "./types/internal"; export const _are_promises_supported = ((typeof Promise === "object") || (typeof Promise === "function")) && (typeof Promise.resolve === "function"); @@ -29,8 +29,8 @@ export function mono_wasm_cancel_promise(task_holder_gc_handle: GCHandle): void const promise = holder.promise; mono_assert(!!promise, () => `Expected Promise for GCHandle ${task_holder_gc_handle}`); - assertIsControllablePromise(promise); - const promise_control = getPromiseController(promise); + loaderHelpers.assertIsControllablePromise(promise); + const promise_control = loaderHelpers.getPromiseController(promise); promise_control.reject("OperationCanceledException"); } diff --git a/src/mono/wasm/runtime/class-loader.ts b/src/mono/wasm/runtime/class-loader.ts index 378b619428a879..892aa7bf024506 100644 --- a/src/mono/wasm/runtime/class-loader.ts +++ b/src/mono/wasm/runtime/class-loader.ts @@ -1,4 +1,4 @@ -import { MonoAssembly, MonoClass, MonoType, MonoTypeNull, MonoAssemblyNull } from "./types"; +import { MonoAssembly, MonoClass, MonoType, MonoTypeNull, MonoAssemblyNull } from "./types/internal"; import cwraps from "./cwraps"; const _assembly_cache_by_name = new Map(); @@ -38,40 +38,40 @@ function _set_cached_class(assembly: MonoAssembly, namespace: string, name: stri classes.set(name, ptr); } -export function find_corlib_class(namespace: string, name: string, throw_on_failure?: boolean | undefined): MonoClass { +export function find_corlib_class(namespace: string, name: string): MonoClass { if (!_corlib) _corlib = cwraps.mono_wasm_get_corlib(); let result = _find_cached_class(_corlib, namespace, name); if (result !== undefined) return result; result = cwraps.mono_wasm_assembly_find_class(_corlib, namespace, name); - if (throw_on_failure && !result) + if (!result) throw new Error(`Failed to find corlib class ${namespace}.${name}`); - _set_cached_class(_corlib, namespace, name, result); + _set_cached_class(_corlib, namespace, name, result!); return result; } -export function find_class_in_assembly(assembly_name: string, namespace: string, name: string, throw_on_failure?: boolean | undefined): MonoClass { +export function find_class_in_assembly(assembly_name: string, namespace: string, name: string): MonoClass { const assembly = assembly_load(assembly_name); let result = _find_cached_class(assembly, namespace, name); if (result !== undefined) return result; result = cwraps.mono_wasm_assembly_find_class(assembly, namespace, name); - if (throw_on_failure && !result) + if (!result) throw new Error(`Failed to find class ${namespace}.${name} in ${assembly_name}`); - _set_cached_class(assembly, namespace, name, result); + _set_cached_class(assembly, namespace, name, result!); return result; } -export function find_corlib_type(namespace: string, name: string, throw_on_failure?: boolean | undefined): MonoType { - const classPtr = find_corlib_class(namespace, name, throw_on_failure); +export function find_corlib_type(namespace: string, name: string): MonoType { + const classPtr = find_corlib_class(namespace, name); if (!classPtr) return MonoTypeNull; return cwraps.mono_wasm_class_get_type(classPtr); } -export function find_type_in_assembly(assembly_name: string, namespace: string, name: string, throw_on_failure?: boolean | undefined): MonoType { - const classPtr = find_class_in_assembly(assembly_name, namespace, name, throw_on_failure); +export function find_type_in_assembly(assembly_name: string, namespace: string, name: string): MonoType { + const classPtr = find_class_in_assembly(assembly_name, namespace, name); if (!classPtr) return MonoTypeNull; return cwraps.mono_wasm_class_get_type(classPtr); diff --git a/src/mono/wasm/runtime/config.ts b/src/mono/wasm/runtime/config.ts deleted file mode 100644 index 34e92f032cbaa2..00000000000000 --- a/src/mono/wasm/runtime/config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { DotnetModuleInternal, MonoConfigInternal } from "./types"; -import { DotnetModuleConfig } from "./types-api"; - -export function deep_merge_config(target: MonoConfigInternal, source: MonoConfigInternal): MonoConfigInternal { - const providedConfig: MonoConfigInternal = { ...source }; - if (providedConfig.assets) { - providedConfig.assets = [...(target.assets || []), ...(providedConfig.assets || [])]; - } - if (providedConfig.environmentVariables) { - providedConfig.environmentVariables = { ...(target.environmentVariables || {}), ...(providedConfig.environmentVariables || {}) }; - } - if (providedConfig.startupOptions) { - providedConfig.startupOptions = { ...(target.startupOptions || {}), ...(providedConfig.startupOptions || {}) }; - } - if (providedConfig.runtimeOptions) { - providedConfig.runtimeOptions = [...(target.runtimeOptions || []), ...(providedConfig.runtimeOptions || [])]; - } - return Object.assign(target, providedConfig); -} - -export function deep_merge_module(target: DotnetModuleInternal, source: DotnetModuleConfig): DotnetModuleInternal { - const providedConfig: DotnetModuleConfig = { ...source }; - if (providedConfig.config) { - if (!target.config) target.config = {}; - providedConfig.config = deep_merge_config(target.config, providedConfig.config); - } - return Object.assign(target, providedConfig); -} \ No newline at end of file diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts index 6c6912fd6b6c99..a5a90b56d1ae2b 100644 --- a/src/mono/wasm/runtime/cwraps.ts +++ b/src/mono/wasm/runtime/cwraps.ts @@ -5,7 +5,7 @@ import type { MonoArray, MonoAssembly, MonoClass, MonoMethod, MonoObject, MonoString, MonoType, MonoObjectRef, MonoStringRef, JSMarshalerArguments -} from "./types"; +} from "./types/internal"; import type { VoidPtr, CharPtrPtr, Int32Ptr, CharPtr, ManagedPointer } from "./types/emscripten"; import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop"; import { disableLegacyJsInterop, Module } from "./globals"; diff --git a/src/mono/wasm/runtime/diagnostics-mock.d.ts b/src/mono/wasm/runtime/diagnostics-mock.d.ts index b7153249ebc4df..59686e8797399e 100644 --- a/src/mono/wasm/runtime/diagnostics-mock.d.ts +++ b/src/mono/wasm/runtime/diagnostics-mock.d.ts @@ -5,7 +5,6 @@ //! This is not considered public API with backward compatibility guarantees. -declare const promise_control_symbol: unique symbol; interface PromiseController { isDone: boolean; readonly promise: Promise; @@ -13,7 +12,7 @@ interface PromiseController { reject: (reason?: any) => void; } interface ControllablePromise extends Promise { - [promise_control_symbol]: PromiseController; + __brand: "ControllablePromise"; } interface PromiseAndController { promise: ControllablePromise; diff --git a/src/mono/wasm/runtime/diagnostics-mock.d.ts.sha256 b/src/mono/wasm/runtime/diagnostics-mock.d.ts.sha256 index 1b6e1a2ae0e544..0cfcc26b86906d 100644 --- a/src/mono/wasm/runtime/diagnostics-mock.d.ts.sha256 +++ b/src/mono/wasm/runtime/diagnostics-mock.d.ts.sha256 @@ -1 +1 @@ -90231971bda6e6a32b2c5239c60176b9126469d29478f572b8a15ab7476cd791 \ No newline at end of file +6d0ff454946223f77abe8e6c1e377489c33b2914da86120f6b2952b739ebec20 \ No newline at end of file diff --git a/src/mono/wasm/runtime/diagnostics/index.ts b/src/mono/wasm/runtime/diagnostics/index.ts index 4987795e001677..2dea3bf0f2e083 100644 --- a/src/mono/wasm/runtime/diagnostics/index.ts +++ b/src/mono/wasm/runtime/diagnostics/index.ts @@ -5,7 +5,7 @@ import monoWasmThreads from "consts:monoWasmThreads"; import type { DiagnosticOptions, } from "./shared/types"; -import { is_nullish } from "../types"; +import { is_nullish } from "../types/internal"; import type { VoidPtr } from "../types/emscripten"; import { getController, startDiagnosticServer } from "./browser/controller"; import * as memory from "../memory"; diff --git a/src/mono/wasm/runtime/diagnostics/mock/environment.ts b/src/mono/wasm/runtime/diagnostics/mock/environment.ts index c0508ca8335379..d3d4822aacf69f 100644 --- a/src/mono/wasm/runtime/diagnostics/mock/environment.ts +++ b/src/mono/wasm/runtime/diagnostics/mock/environment.ts @@ -1,14 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { createPromiseController } from "../../promise-controller"; import type { RemoveCommandSetAndId, EventPipeCommandCollectTracing2, EventPipeCommandStopTracing } from "../server_pthread/protocol-client-commands"; import type { FilterPredicate, MockEnvironment } from "./types"; import Serializer from "../server_pthread/ipc-protocol/base-serializer"; import { CommandSetId, EventPipeCommandId, ProcessCommandId } from "../server_pthread/ipc-protocol/types"; -import { assertNever, mono_assert } from "../../types"; -import { delay } from "../../promise-utils"; +import { assertNever } from "../../types/internal"; import { pthread_self } from "../../pthreads/worker"; +import { createPromiseController } from "../../globals"; function expectAdvertise(data: ArrayBuffer): boolean { @@ -133,7 +132,7 @@ export function createMockEnvironment(): MockEnvironment { postMessageToBrowser, addEventListenerFromBrowser, createPromiseController, - delay, + delay: (ms: number) => new Promise(resolve => setTimeout(resolve, ms)), command, reply, expectAdvertise diff --git a/src/mono/wasm/runtime/diagnostics/mock/export-types.ts b/src/mono/wasm/runtime/diagnostics/mock/export-types.ts index 1117fccb5c3735..6628e0c51953a2 100644 --- a/src/mono/wasm/runtime/diagnostics/mock/export-types.ts +++ b/src/mono/wasm/runtime/diagnostics/mock/export-types.ts @@ -8,4 +8,4 @@ export type { export type { PromiseAndController, -} from "../../promise-controller"; +} from "../../types/internal"; diff --git a/src/mono/wasm/runtime/diagnostics/mock/index.ts b/src/mono/wasm/runtime/diagnostics/mock/index.ts index 38f418613967e4..30d08017ebb6fd 100644 --- a/src/mono/wasm/runtime/diagnostics/mock/index.ts +++ b/src/mono/wasm/runtime/diagnostics/mock/index.ts @@ -5,7 +5,7 @@ import monoDiagnosticsMock from "consts:monoDiagnosticsMock"; import { createMockEnvironment } from "./environment"; import type { MockEnvironment, MockScriptConnection } from "./export-types"; -import { assertNever } from "../../types"; +import { assertNever } from "../../types/internal"; export interface MockRemoteSocket extends EventTarget { addEventListener(type: T, listener: (this: MockRemoteSocket, ev: WebSocketEventMap[T]) => any, options?: boolean | AddEventListenerOptions): void; diff --git a/src/mono/wasm/runtime/diagnostics/mock/types.ts b/src/mono/wasm/runtime/diagnostics/mock/types.ts index 92f8fe4b017de0..30c533595413c0 100644 --- a/src/mono/wasm/runtime/diagnostics/mock/types.ts +++ b/src/mono/wasm/runtime/diagnostics/mock/types.ts @@ -1,6 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import type { PromiseAndController } from "../../promise-controller"; +import type { PromiseAndController } from "../../types/internal"; import type { RemoveCommandSetAndId, EventPipeCommandCollectTracing2, diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts index 9d55897033a652..6180834a90650e 100644 --- a/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts +++ b/src/mono/wasm/runtime/diagnostics/server_pthread/index.ts @@ -4,9 +4,9 @@ /// import monoDiagnosticsMock from "consts:monoDiagnosticsMock"; -import { assertNever } from "../../types"; +import { PromiseAndController, assertNever } from "../../types/internal"; import { pthread_self } from "../../pthreads/worker"; -import { Module } from "../../globals"; +import { Module, createPromiseController } from "../../globals"; import cwraps from "../../cwraps"; import { EventPipeSessionIDImpl } from "../shared/types"; import { CharPtr } from "../../types/emscripten"; @@ -17,7 +17,6 @@ import { import { importAndInstantiateMock } from "./mock-remote"; import type { Mock, MockRemoteSocket } from "../mock"; -import { PromiseAndController, createPromiseController } from "../../promise-controller"; import { isEventPipeCommand, isProcessCommand, diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/ipc-protocol/serializer.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/ipc-protocol/serializer.ts index 8f83d1253bc0a2..0a4af3544a66ce 100644 --- a/src/mono/wasm/runtime/diagnostics/server_pthread/ipc-protocol/serializer.ts +++ b/src/mono/wasm/runtime/diagnostics/server_pthread/ipc-protocol/serializer.ts @@ -3,7 +3,6 @@ import Serializer from "./base-serializer"; import { CommandSetId, ServerCommandId } from "./types"; -import { mono_assert } from "../../../types"; export function createBinaryCommandOKReply(payload?: Uint8Array): Uint8Array { const len = Serializer.computeMessageByteLength(payload); diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts index f30b99175de857..0355e0ccef7942 100644 --- a/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts +++ b/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import monoDiagnosticsMock from "consts:monoDiagnosticsMock"; -import { runtimeHelpers } from "../../globals"; +import { loaderHelpers } from "../../globals"; import type { Mock } from "../mock"; import { mock } from "../mock"; @@ -12,7 +12,7 @@ export function importAndInstantiateMock(mockURL: string): Promise { const scriptURL = mockURL.substring(mockPrefix.length); return import(scriptURL).then((mockModule) => { const script = mockModule.default; - return mock(script, { trace: runtimeHelpers.diagnosticTracing }); + return mock(script, { trace: loaderHelpers.diagnosticTracing }); }); } else { return Promise.resolve(undefined as unknown as Mock); diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/protocol-socket.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/protocol-socket.ts index e66d24a681ed16..ffa8ce47bca10d 100644 --- a/src/mono/wasm/runtime/diagnostics/server_pthread/protocol-socket.ts +++ b/src/mono/wasm/runtime/diagnostics/server_pthread/protocol-socket.ts @@ -9,7 +9,7 @@ import { } from "./ipc-protocol/types"; import Magic from "./ipc-protocol/magic"; import Parser from "./ipc-protocol/base-parser"; -import { assertNever } from "../../types"; +import { assertNever } from "../../types/internal"; export const dotnetDiagnosticsServerProtocolCommandEvent = "dotnet:diagnostics:protocolCommand" as const; diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/socket-connection.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/socket-connection.ts index cc3a8d838524dc..c2f8aae007f107 100644 --- a/src/mono/wasm/runtime/diagnostics/server_pthread/socket-connection.ts +++ b/src/mono/wasm/runtime/diagnostics/server_pthread/socket-connection.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { assertNever } from "../../types"; +import { assertNever } from "../../types/internal"; import { VoidPtr } from "../../types/emscripten"; import { Module } from "../../globals"; import type { CommonSocket } from "./common-socket"; diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts index 8b8f2e9d4d01e6..c1f6826b051959 100644 --- a/src/mono/wasm/runtime/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -179,7 +179,7 @@ interface AssetEntry extends ResourceRequest { */ pendingDownload?: LoadingResource; } -type AssetBehaviours = "resource" | "assembly" | "pdb" | "heap" | "icu" | "vfs" | "dotnetwasm" | "js-module-threads" | "symbols"; +type AssetBehaviours = "resource" | "assembly" | "pdb" | "heap" | "icu" | "vfs" | "dotnetwasm" | "js-module-threads" | "js-module-runtime" | "js-module-dotnet" | "js-module-native" | "symbols"; type GlobalizationMode = "icu" | // load ICU globalization data from any runtime assets with behavior "icu". "invariant" | // operate in invariant globalization mode. "hybrid" | // operate in hybrid globalization mode with small ICU files, using native platform functions @@ -252,6 +252,35 @@ type ModuleAPI = { }; type CreateDotnetRuntimeType = (moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)) => Promise; +interface IDisposable { + dispose(): void; + get isDisposed(): boolean; +} +interface IMemoryView extends IDisposable { + /** + * copies elements from provided source to the wasm memory. + * target has to have the elements of the same type as the underlying C# array. + * same as TypedArray.set() + */ + set(source: TypedArray, targetOffset?: number): void; + /** + * copies elements from wasm memory to provided target. + * target has to have the elements of the same type as the underlying C# array. + */ + copyTo(target: TypedArray, sourceOffset?: number): void; + /** + * same as TypedArray.slice() + */ + slice(start?: number, end?: number): TypedArray; + get length(): number; + get byteLength(): number; +} + +declare function mono_exit(exit_code: number, reason?: any): void; + +declare const dotnet: DotnetHostBuilder; +declare const exit: typeof mono_exit; + interface BootJsonData { readonly entryAssembly: string; readonly resources: ResourceGroups; @@ -297,35 +326,6 @@ declare enum ICUDataMode { Custom = 3 } -interface IDisposable { - dispose(): void; - get isDisposed(): boolean; -} -interface IMemoryView extends IDisposable { - /** - * copies elements from provided source to the wasm memory. - * target has to have the elements of the same type as the underlying C# array. - * same as TypedArray.set() - */ - set(source: TypedArray, targetOffset?: number): void; - /** - * copies elements from wasm memory to provided target. - * target has to have the elements of the same type as the underlying C# array. - */ - copyTo(target: TypedArray, sourceOffset?: number): void; - /** - * same as TypedArray.slice() - */ - slice(start?: number, end?: number): TypedArray; - get length(): number; - get byteLength(): number; -} - -declare function mono_exit(exit_code: number, reason?: any): void; - -declare const dotnet: DotnetHostBuilder; -declare const exit: typeof mono_exit; - declare global { function getDotnetRuntime(runtimeId: number): RuntimeAPI | undefined; } diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js b/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js index 7c42d93dd9c138..7fdd5d0ef8023d 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js @@ -1,6 +1,2 @@ var fetch = fetch || undefined; var require = require || undefined; var __dirname = __dirname || ''; -var createEmscripten = createDotnetRuntime; -var unifyModuleConfig = __dotnet_runtime.unifyModuleConfig; -export const dotnet = __dotnet_runtime.dotnet; -export const exit = __dotnet_runtime.exit; \ No newline at end of file diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js index b23d1981049550..c7564ada640791 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js @@ -27,30 +27,21 @@ function setup(disableLegacyJsInterop) { #else const ENVIRONMENT_IS_PTHREAD = false; #endif - if (ENVIRONMENT_IS_NODE) { - dotnet_replacements.requirePromise = import(/* webpackIgnore: true */'module').then(mod => mod.createRequire(import.meta.url)); - dotnet_replacements.requirePromise.then(someRequire => { - require = someRequire; - }); - } - __dotnet_runtime.passEmscriptenInternals({ - isWorker: ENVIRONMENT_IS_WORKER, - isShell: ENVIRONMENT_IS_SHELL, + Module.__dotnet_runtime.passEmscriptenInternals({ isPThread: ENVIRONMENT_IS_PTHREAD, disableLegacyJsInterop, quit_, ExitStatus }); + Module.__dotnet_runtime.initializeReplacements(dotnet_replacements); #if USE_PTHREADS if (ENVIRONMENT_IS_PTHREAD) { Module.config = {}; - __dotnet_runtime.initializeReplacements(dotnet_replacements); - __dotnet_runtime.configureWorkerStartup(Module); + Module.__dotnet_runtime.configureWorkerStartup(Module); } else { #endif - __dotnet_runtime.initializeReplacements(dotnet_replacements); - __dotnet_runtime.configureEmscriptenStartup(Module); + Module.__dotnet_runtime.configureEmscriptenStartup(Module); #if USE_PTHREADS } #endif @@ -58,6 +49,7 @@ function setup(disableLegacyJsInterop) { updateMemoryViews = dotnet_replacements.updateMemoryViews; noExitRuntime = dotnet_replacements.noExitRuntime; fetch = dotnet_replacements.fetch; + require = dotnet_replacements.require; _scriptDir = __dirname = scriptDirectory = dotnet_replacements.scriptDirectory; #if USE_PTHREADS PThread.loadWasmModuleToWorker = pthreadReplacements.loadWasmModuleToWorker; diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js index 3ecc1bcdc9be79..8c2a0e6472917a 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js @@ -1 +1 @@ -createDotnetRuntime = Module = unifyModuleConfig(Module, createDotnetRuntime); \ No newline at end of file +createDotnetRuntime = Module = createDotnetRuntime(Module); \ No newline at end of file diff --git a/src/mono/wasm/runtime/export-api.ts b/src/mono/wasm/runtime/export-api.ts index e258beaa3801bc..2b6134c0ea0da1 100644 --- a/src/mono/wasm/runtime/export-api.ts +++ b/src/mono/wasm/runtime/export-api.ts @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import type { MonoConfig, APIType } from "./types-api"; +import type { MonoConfig, APIType } from "./types"; -import { runtimeHelpers } from "./globals"; +import { loaderHelpers } from "./globals"; import { mono_wasm_get_assembly_exports } from "./invoke-cs"; import { mono_wasm_set_module_imports } from "./invoke-js"; import { getB32, getF32, getF64, getI16, getI32, getI52, getI64Big, getI8, getU16, getU32, getU52, getU8, setB32, setF32, setF64, setI16, setI32, setI52, setI64Big, setI8, setU16, setU32, setU52, setU8 } from "./memory"; @@ -18,7 +18,7 @@ export function export_api(): any { getAssemblyExports: mono_wasm_get_assembly_exports, setModuleImports: mono_wasm_set_module_imports, getConfig: (): MonoConfig => { - return runtimeHelpers.config; + return loaderHelpers.config; }, setHeapB32: setB32, setHeapU8: setU8, diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index c7ea64155b8e54..c82a1a38962612 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -5,34 +5,33 @@ import ProductVersion from "consts:productVersion"; import GitHash from "consts:gitHash"; import BuildConfiguration from "consts:configuration"; import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop"; -import type { DotnetHostBuilder, RuntimeAPI } from "./types-api"; +import type { RuntimeAPI } from "./types"; -import { Module, disableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, } from "./globals"; -import { is_nullish } from "./types"; +import { Module, disableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setGlobalObjects, } from "./globals"; +import { GlobalObjects, is_nullish } from "./types/internal"; import { configureEmscriptenStartup, configureWorkerStartup } from "./startup"; import { create_weak_ref } from "./weak-ref"; import { export_internal } from "./exports-internal"; import { export_api } from "./export-api"; -import { mono_exit } from "./run"; -import { globalObjectsRoot, unifyModuleConfig } from "./run-outer"; -import { HostBuilder } from "./run-outer"; -import { initializeReplacements, init_polyfills } from "./polyfills"; +import { initializeReplacements } from "./polyfills"; // legacy import { mono_bind_static_method } from "./net6-legacy/method-calls"; import { export_binding_api, export_internal_api, export_mono_api } from "./net6-legacy/exports-legacy"; import { initializeLegacyExports } from "./net6-legacy/globals"; +import { mono_wasm_stringify_as_error_with_stack } from "./logging"; +import { instantiate_asset, instantiate_symbols_asset } from "./assets"; +import { jiterpreter_dump_stats } from "./jiterpreter"; -function initializeExports(): RuntimeAPI { +function initializeExports(globalObjects: GlobalObjects): RuntimeAPI { const module = Module; - const globals = globalObjectsRoot; + const globals = globalObjects; const globalThisAny = globalThis as any; if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop) { initializeLegacyExports(globals); } - init_polyfills(); // here we merge methods from the local objects into exported objects if (WasmEnableLegacyJsInterop && !disableLegacyJsInterop) { @@ -41,6 +40,13 @@ function initializeExports(): RuntimeAPI { Object.assign(globals.internal, export_internal_api()); } Object.assign(globals.internal, export_internal()); + Object.assign(runtimeHelpers, { + stringify_as_error_with_stack: mono_wasm_stringify_as_error_with_stack, + instantiate_symbols_asset, + instantiate_asset, + jiterpreter_dump_stats, + }); + const API = export_api(); Object.assign(exportedRuntimeAPI, { INTERNAL: globals.internal, @@ -135,9 +141,6 @@ class RuntimeList { } // export external API -const dotnet: DotnetHostBuilder = new HostBuilder(); -const exit = mono_exit; export { - dotnet, exit, - globalObjectsRoot as earlyExports, passEmscriptenInternals, initializeExports, initializeReplacements, unifyModuleConfig, configureEmscriptenStartup, configureWorkerStartup + passEmscriptenInternals, initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setGlobalObjects }; \ No newline at end of file diff --git a/src/mono/wasm/runtime/gc-handles.ts b/src/mono/wasm/runtime/gc-handles.ts index b1bc580d931b36..500b4626c697c5 100644 --- a/src/mono/wasm/runtime/gc-handles.ts +++ b/src/mono/wasm/runtime/gc-handles.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import { runtimeHelpers } from "./globals"; -import { GCHandle, GCHandleNull, JSHandle, JSHandleDisposed, JSHandleNull, mono_assert } from "./types"; +import { GCHandle, GCHandleNull, JSHandle, JSHandleDisposed, JSHandleNull } from "./types/internal"; import { create_weak_ref } from "./weak-ref"; const _use_finalization_registry = typeof globalThis.FinalizationRegistry === "function"; diff --git a/src/mono/wasm/runtime/globals.ts b/src/mono/wasm/runtime/globals.ts index 1f032e37c966ab..b2fa7bdf80bf44 100644 --- a/src/mono/wasm/runtime/globals.ts +++ b/src/mono/wasm/runtime/globals.ts @@ -5,66 +5,64 @@ /// /// -import { RuntimeAPI } from "./types-api"; -import type { DotnetModule, GlobalObjects, EmscriptenInternals, EmscriptenModuleInternal, RuntimeHelpers } from "./types"; -import type { EmscriptenModule } from "./types/emscripten"; +import { RuntimeAPI } from "./types/index"; +import type { GlobalObjects, EmscriptenInternals, RuntimeHelpers, LoaderHelpers, DotnetModuleInternal, PromiseAndController } from "./types/internal"; // these are our public API (except internal) -export let Module: EmscriptenModule & DotnetModule & EmscriptenModuleInternal; +export let Module: DotnetModuleInternal; export let INTERNAL: any; -// these are imported and re-exported from emscripten internals export const ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string"; export const ENVIRONMENT_IS_WEB = typeof window == "object"; -export let ENVIRONMENT_IS_SHELL: boolean; -export let ENVIRONMENT_IS_WORKER: boolean; +export const ENVIRONMENT_IS_WORKER = typeof importScripts == "function"; +export const ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; +// these are imported and re-exported from emscripten internals export let ENVIRONMENT_IS_PTHREAD: boolean; export let exportedRuntimeAPI: RuntimeAPI = null as any; export let runtimeHelpers: RuntimeHelpers = null as any; +export let loaderHelpers: LoaderHelpers = null as any; // this is when we link with workload tools. The consts:WasmEnableLegacyJsInterop is when we compile with rollup. export let disableLegacyJsInterop = false; -export let earlyExports: GlobalObjects; -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export function passEmscriptenInternals( - internals: EmscriptenInternals, -): void { - ENVIRONMENT_IS_SHELL = internals.isShell; - ENVIRONMENT_IS_WORKER = internals.isWorker; +export function passEmscriptenInternals(internals: EmscriptenInternals): void { ENVIRONMENT_IS_PTHREAD = internals.isPThread; disableLegacyJsInterop = internals.disableLegacyJsInterop; runtimeHelpers.quit = internals.quit_; runtimeHelpers.ExitStatus = internals.ExitStatus; } -export function setGlobalObjects( - globalObjects: GlobalObjects, -) { - earlyExports = globalObjects; +export function setGlobalObjects(globalObjects: GlobalObjects) { Module = globalObjects.module; INTERNAL = globalObjects.internal; - runtimeHelpers = globalObjects.helpers; + runtimeHelpers = globalObjects.runtimeHelpers; + loaderHelpers = globalObjects.loaderHelpers; exportedRuntimeAPI = globalObjects.api; - Object.assign(globalObjects.module, { - disableDotnet6Compatibility: true, - config: { environmentVariables: {} } + Object.assign(runtimeHelpers, { + mono_wasm_bindings_is_ready: false, + javaScriptExports: {} as any, + enablePerfMeasure: true, + allAssetsInMemory: createPromiseController(), + dotnetReady: createPromiseController(), + memorySnapshotSkippedOrDone: createPromiseController(), + afterInstantiateWasm: createPromiseController(), + beforePreInit: createPromiseController(), + afterPreInit: createPromiseController(), + afterPreRun: createPromiseController(), + beforeOnRuntimeInitialized: createPromiseController(), + afterOnRuntimeInitialized: createPromiseController(), + afterPostRun: createPromiseController(), }); + Object.assign(globalObjects.module.config!, {}) as any; - Object.assign(earlyExports.api, { + Object.assign(globalObjects.api, { Module: globalObjects.module, ...globalObjects.module }); - Object.assign(earlyExports.api, { - INTERNAL: earlyExports.internal, + Object.assign(globalObjects.api, { + INTERNAL: globalObjects.internal, }); - Object.assign(runtimeHelpers, { - javaScriptExports: {} as any, - mono_wasm_bindings_is_ready: false, - maxParallelDownloads: 16, - enableDownloadRetry: true, - config: globalObjects.module.config, - diagnosticTracing: false, - enablePerfMeasure: true, - loadedFiles: [] - } as Partial); } + +export function createPromiseController(afterResolve?: () => void, afterReject?: () => void): PromiseAndController { + return loaderHelpers.createPromiseController(afterResolve, afterReject); +} \ No newline at end of file diff --git a/src/mono/wasm/runtime/http.ts b/src/mono/wasm/runtime/http.ts index a3d676e91a90dc..38e747f26ea798 100644 --- a/src/mono/wasm/runtime/http.ts +++ b/src/mono/wasm/runtime/http.ts @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. import { wrap_as_cancelable_promise } from "./cancelable-promise"; -import { Module, runtimeHelpers } from "./globals"; +import { Module, loaderHelpers } from "./globals"; import { MemoryViewType, Span } from "./marshal"; -import { mono_assert } from "./types"; import type { VoidPtr } from "./types/emscripten"; export function http_wasm_supports_streaming_response(): boolean { @@ -56,7 +55,7 @@ export function http_wasm_fetch(url: string, header_names: string[], header_valu } return wrap_as_cancelable_promise(async () => { - const res = await runtimeHelpers.fetch_like(url, options) as ResponseExtension; + const res = await loaderHelpers.fetch_like(url, options) as ResponseExtension; res.__abort_controller = abort_controller; return res; }); diff --git a/src/mono/wasm/runtime/hybrid-globalization.ts b/src/mono/wasm/runtime/hybrid-globalization.ts index 66cc3ebafb371a..8e068a6fb66605 100644 --- a/src/mono/wasm/runtime/hybrid-globalization.ts +++ b/src/mono/wasm/runtime/hybrid-globalization.ts @@ -2,14 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. import { mono_wasm_new_external_root } from "./roots"; -import { MonoString, MonoStringRef } from "./types"; +import { MonoString, MonoStringRef } from "./types/internal"; import { Int32Ptr } from "./types/emscripten"; import { conv_string_root, js_string_to_mono_string_root, string_decoder } from "./strings"; import { setU16_unchecked } from "./memory"; -export function mono_wasm_change_case_invariant(exceptionMessage: Int32Ptr, src: number, srcLength: number, dst: number, dstLength: number, toUpper: number) : void{ - try{ - const input = string_decoder.decode(src, (src + 2*srcLength)); +export function mono_wasm_change_case_invariant(exceptionMessage: Int32Ptr, src: number, srcLength: number, dst: number, dstLength: number, toUpper: number): void { + try { + const input = string_decoder.decode(src, (src + 2 * srcLength)); let result = toUpper ? input.toUpperCase() : input.toLowerCase(); // Unicode defines some codepoints which expand into multiple codepoints, // originally we do not support this expansion @@ -30,7 +30,7 @@ export function mono_wasm_change_case(exceptionMessage: Int32Ptr, culture: MonoS const cultureName = conv_string_root(cultureRoot); if (!cultureName) throw new Error("Cannot change case, the culture name is null."); - const input = string_decoder.decode(src, (src + 2*srcLength)); + const input = string_decoder.decode(src, (src + 2 * srcLength)); let result = toUpper ? input.toLocaleUpperCase(cultureName) : input.toLocaleLowerCase(cultureName); if (result.length > destLength) result = input; diff --git a/src/mono/wasm/runtime/icu.ts b/src/mono/wasm/runtime/icu.ts index f3b5b4586b164e..28aa01ad727cfd 100644 --- a/src/mono/wasm/runtime/icu.ts +++ b/src/mono/wasm/runtime/icu.ts @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. import cwraps from "./cwraps"; -import { ENVIRONMENT_IS_WEB, Module, runtimeHelpers } from "./globals"; import { VoidPtr } from "./types/emscripten"; // @offset must be the address of an ICU data archive in the native heap. @@ -10,70 +9,3 @@ import { VoidPtr } from "./types/emscripten"; export function mono_wasm_load_icu_data(offset: VoidPtr): boolean { return (cwraps.mono_wasm_load_icu_data(offset)) === 1; } - -export function init_globalization() { - runtimeHelpers.invariantMode = runtimeHelpers.config.globalizationMode === "invariant"; - runtimeHelpers.preferredIcuAsset = get_preferred_icu_asset(); - - if (!runtimeHelpers.invariantMode) { - if (runtimeHelpers.preferredIcuAsset) { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: ICU data archive(s) available, disabling invariant mode"); - } else if (runtimeHelpers.config.globalizationMode !== "icu") { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: ICU data archive(s) not available, using invariant globalization mode"); - runtimeHelpers.invariantMode = true; - runtimeHelpers.preferredIcuAsset = null; - } else { - const msg = "invariant globalization mode is inactive and no ICU data archives are available"; - Module.err(`MONO_WASM: ERROR: ${msg}`); - throw new Error(msg); - } - } - - const invariantEnv = "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"; - const hybridEnv = "DOTNET_SYSTEM_GLOBALIZATION_HYBRID"; - const env_variables = runtimeHelpers.config.environmentVariables!; - if (env_variables[hybridEnv] === undefined && runtimeHelpers.config.globalizationMode === "hybrid") { - env_variables[hybridEnv] = "1"; - } - else if (env_variables[invariantEnv] === undefined && runtimeHelpers.invariantMode) { - env_variables[invariantEnv] = "1"; - } - if (env_variables["TZ"] === undefined) { - try { - // this call is relatively expensive, so we call it during download of other assets - const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || null; - if (timezone) { - env_variables!["TZ"] = timezone; - } - } catch { - console.info("MONO_WASM: failed to detect timezone, will fallback to UTC"); - } - } -} - -export function get_preferred_icu_asset(): string | null { - if (!runtimeHelpers.config.assets || runtimeHelpers.invariantMode) - return null; - - // By setting user can define what ICU source file they want to load. - // There is no need to check application's culture when is set. - // If it was not set, then we have 3 "icu" assets in config and we should choose - // only one for loading, the one that matches the application's locale. - const icuAssets = runtimeHelpers.config.assets.filter(a => a["behavior"] == "icu"); - if (icuAssets.length === 1) - return icuAssets[0].name; - - // reads the browsers locale / the OS's locale - const preferredCulture = ENVIRONMENT_IS_WEB ? navigator.language : Intl.DateTimeFormat().resolvedOptions().locale; - const prefix = preferredCulture.split("-")[0]; - const CJK = "icudt_CJK.dat"; - const EFIGS = "icudt_EFIGS.dat"; - const OTHERS = "icudt_no_CJK.dat"; - - // not all "fr-*", "it-*", "de-*", "es-*" are in EFIGS, only the one that is mostly used - if (prefix == "en" || ["fr", "fr-FR", "it", "it-IT", "de", "de-DE", "es", "es-ES"].includes(preferredCulture)) - return EFIGS; - if (["zh", "ko", "ja"].includes(prefix)) - return CJK; - return OTHERS; -} diff --git a/src/mono/wasm/runtime/invoke-cs.ts b/src/mono/wasm/runtime/invoke-cs.ts index 340b3afa414052..990d258e40d1c8 100644 --- a/src/mono/wasm/runtime/invoke-cs.ts +++ b/src/mono/wasm/runtime/invoke-cs.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import MonoWasmThreads from "consts:monoWasmThreads"; -import { Module, runtimeHelpers } from "./globals"; +import { Module, loaderHelpers, runtimeHelpers } from "./globals"; import { bind_arg_marshal_to_cs } from "./marshal-to-cs"; import { marshal_exception_to_js, bind_arg_marshal_to_js } from "./marshal-to-js"; import { @@ -11,7 +11,7 @@ import { } from "./marshal"; import { mono_wasm_new_external_root, mono_wasm_new_root } from "./roots"; import { conv_string, conv_string_root } from "./strings"; -import { mono_assert, MonoObjectRef, MonoStringRef, MonoString, MonoObject, MonoMethod, JSMarshalerArguments, JSFunctionSignature, BoundMarshalerToCs, BoundMarshalerToJs, VoidPtrNull, MonoObjectRefNull, MonoObjectNull } from "./types"; +import { MonoObjectRef, MonoStringRef, MonoString, MonoObject, MonoMethod, JSMarshalerArguments, JSFunctionSignature, BoundMarshalerToCs, BoundMarshalerToJs, VoidPtrNull, MonoObjectRefNull, MonoObjectNull } from "./types/internal"; import { Int32Ptr } from "./types/emscripten"; import cwraps from "./cwraps"; import { assembly_load } from "./class-loader"; @@ -29,7 +29,7 @@ export function mono_wasm_bind_cs_function(fully_qualified_name: MonoStringRef, const js_fqn = conv_string_root(fqn_root)!; mono_assert(js_fqn, "fully_qualified_name must be string"); - if (runtimeHelpers.diagnosticTracing) { + if (loaderHelpers.diagnosticTracing) { console.debug(`MONO_WASM: Binding [JSExport] ${js_fqn}`); } diff --git a/src/mono/wasm/runtime/invoke-js.ts b/src/mono/wasm/runtime/invoke-js.ts index 6cb566f024aa15..47b47e5810f508 100644 --- a/src/mono/wasm/runtime/invoke-js.ts +++ b/src/mono/wasm/runtime/invoke-js.ts @@ -5,9 +5,9 @@ import { marshal_exception_to_cs, bind_arg_marshal_to_cs } from "./marshal-to-cs import { get_signature_argument_count, bound_js_function_symbol, get_sig, get_signature_version, get_signature_type, imported_js_function_symbol } from "./marshal"; import { setI32_unchecked } from "./memory"; import { conv_string_root, js_string_to_mono_string_root } from "./strings"; -import { mono_assert, MonoObject, MonoObjectRef, MonoString, MonoStringRef, JSFunctionSignature, JSMarshalerArguments, WasmRoot, BoundMarshalerToJs, JSFnHandle, BoundMarshalerToCs, JSHandle, MarshalerType } from "./types"; +import { MonoObject, MonoObjectRef, MonoString, MonoStringRef, JSFunctionSignature, JSMarshalerArguments, WasmRoot, BoundMarshalerToJs, JSFnHandle, BoundMarshalerToCs, JSHandle, MarshalerType } from "./types/internal"; import { Int32Ptr } from "./types/emscripten"; -import { INTERNAL, Module, runtimeHelpers } from "./globals"; +import { INTERNAL, Module, loaderHelpers } from "./globals"; import { bind_arg_marshal_to_js } from "./marshal-to-js"; import { mono_wasm_new_external_root } from "./roots"; import { mono_wasm_symbolicate_string } from "./logging"; @@ -28,7 +28,7 @@ export function mono_wasm_bind_js_function(function_name: MonoStringRef, module_ const js_function_name = conv_string_root(function_name_root)!; const mark = startMeasure(); const js_module_name = conv_string_root(module_name_root)!; - if (runtimeHelpers.diagnosticTracing) { + if (loaderHelpers.diagnosticTracing) { console.debug(`MONO_WASM: Binding [JSImport] ${js_function_name} from ${js_module_name}`); } const fn = mono_wasm_lookup_function(js_function_name, js_module_name); @@ -249,7 +249,7 @@ export function mono_wasm_invoke_import(fn_handle: JSFnHandle, args: JSMarshaler export function mono_wasm_set_module_imports(module_name: string, moduleImports: any) { importedModules.set(module_name, moduleImports); - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: added module imports '${module_name}'`); } @@ -324,7 +324,7 @@ export function dynamic_import(module_name: string, module_url: string): Promise let promise = importedModulesPromises.get(module_name); const newPromise = !promise; if (newPromise) { - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: importing ES6 module '${module_name}' from '${module_url}'`); promise = import(/* webpackIgnore: true */module_url); importedModulesPromises.set(module_name, promise); @@ -334,7 +334,7 @@ export function dynamic_import(module_name: string, module_url: string): Promise const module = await promise; if (newPromise) { importedModules.set(module_name, module); - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: imported ES6 module '${module_name}' from '${module_url}'`); } return module; diff --git a/src/mono/wasm/runtime/jiterpreter-interp-entry.ts b/src/mono/wasm/runtime/jiterpreter-interp-entry.ts index aad65e7ad4841c..fd6e196ecc5782 100644 --- a/src/mono/wasm/runtime/jiterpreter-interp-entry.ts +++ b/src/mono/wasm/runtime/jiterpreter-interp-entry.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { mono_assert, MonoMethod, MonoType } from "./types"; +import { MonoMethod, MonoType } from "./types/internal"; import { NativePointer } from "./types/emscripten"; import { Module } from "./globals"; import { diff --git a/src/mono/wasm/runtime/jiterpreter-jit-call.ts b/src/mono/wasm/runtime/jiterpreter-jit-call.ts index 3f016adc005108..0c57cca13ee44c 100644 --- a/src/mono/wasm/runtime/jiterpreter-jit-call.ts +++ b/src/mono/wasm/runtime/jiterpreter-jit-call.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { mono_assert, MonoType, MonoMethod } from "./types"; +import { MonoType, MonoMethod } from "./types/internal"; import { NativePointer, Int32Ptr, VoidPtr } from "./types/emscripten"; import { Module, runtimeHelpers } from "./globals"; import { diff --git a/src/mono/wasm/runtime/jiterpreter-support.ts b/src/mono/wasm/runtime/jiterpreter-support.ts index 010e67496b19b5..c6e244e7ebb305 100644 --- a/src/mono/wasm/runtime/jiterpreter-support.ts +++ b/src/mono/wasm/runtime/jiterpreter-support.ts @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { mono_assert } from "./types"; import { NativePointer, ManagedPointer, VoidPtr } from "./types/emscripten"; import { Module, runtimeHelpers } from "./globals"; import { WasmOpcode } from "./jiterpreter-opcodes"; diff --git a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts index 0f80f0661ee977..42350899958fe0 100644 --- a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { mono_assert, MonoMethod } from "./types"; +import { MonoMethod } from "./types/internal"; import { NativePointer } from "./types/emscripten"; import { getU16, getI16, @@ -37,25 +37,25 @@ import { /* struct MonoVTable { - MonoClass *klass; // 0 - MonoGCDescriptor gc_descr; // 4 - MonoDomain *domain; // 8 - gpointer type; // 12 - guint8 *interface_bitmap; // 16 - guint32 max_interface_id; // 20 - guint8 rank; // 21 - guint8 initialized; // 22 - guint8 flags; + MonoClass *klass; // 0 + MonoGCDescriptor gc_descr; // 4 + MonoDomain *domain; // 8 + gpointer type; // 12 + guint8 *interface_bitmap; // 16 + guint32 max_interface_id; // 20 + guint8 rank; // 21 + guint8 initialized; // 22 + guint8 flags; */ /* struct InterpFrame { - InterpFrame *parent; // 0 - InterpMethod *imethod; // 4 - stackval *retval; // 8 - stackval *stack; // 12 - InterpFrame *next_free; // 16 - InterpState state; // 20 + InterpFrame *parent; // 0 + InterpMethod *imethod; // 4 + stackval *retval; // 8 + stackval *stack; // 12 + InterpFrame *next_free; // 16 + InterpState state; // 20 }; struct InterpMethod { @@ -80,55 +80,55 @@ const enum JiterpSpecialOpcode { } // indexPlusOne so that ip[1] in the interpreter becomes getArgU16(ip, 1) -function getArgU16 (ip: MintOpcodePtr, indexPlusOne: number) { +function getArgU16(ip: MintOpcodePtr, indexPlusOne: number) { return getU16(ip + (2 * indexPlusOne)); } -function getArgI16 (ip: MintOpcodePtr, indexPlusOne: number) { +function getArgI16(ip: MintOpcodePtr, indexPlusOne: number) { return getI16(ip + (2 * indexPlusOne)); } -function getArgI32 (ip: MintOpcodePtr, indexPlusOne: number) { +function getArgI32(ip: MintOpcodePtr, indexPlusOne: number) { const src = ip + (2 * indexPlusOne); return getI32_unaligned(src); } -function getArgU32 (ip: MintOpcodePtr, indexPlusOne: number) { +function getArgU32(ip: MintOpcodePtr, indexPlusOne: number) { const src = ip + (2 * indexPlusOne); return getU32_unaligned(src); } -function getArgF32 (ip: MintOpcodePtr, indexPlusOne: number) { +function getArgF32(ip: MintOpcodePtr, indexPlusOne: number) { const src = ip + (2 * indexPlusOne); return getF32_unaligned(src); } -function getArgF64 (ip: MintOpcodePtr, indexPlusOne: number) { +function getArgF64(ip: MintOpcodePtr, indexPlusOne: number) { const src = ip + (2 * indexPlusOne); return getF64_unaligned(src); } -function get_imethod (frame: NativePointer) { +function get_imethod(frame: NativePointer) { // FIXME: Encoding this data directly into the trace will prevent trace reuse const iMethod = getU32_unaligned(frame + getMemberOffset(JiterpMember.Imethod)); return iMethod; } -function get_imethod_data (frame: NativePointer, index: number) { +function get_imethod_data(frame: NativePointer, index: number) { // FIXME: Encoding this data directly into the trace will prevent trace reuse const pData = getU32_unaligned(get_imethod(frame) + getMemberOffset(JiterpMember.DataItems)); const dataOffset = pData + (index * sizeOfDataItem); return getU32_unaligned(dataOffset); } -function get_imethod_clause_data_offset (frame: NativePointer, index: number) { +function get_imethod_clause_data_offset(frame: NativePointer, index: number) { // FIXME: Encoding this data directly into the trace will prevent trace reuse const pData = getU32_unaligned(get_imethod(frame) + getMemberOffset(JiterpMember.ClauseDataOffsets)); const dataOffset = pData + (index * sizeOfDataItem); return getU32_unaligned(dataOffset); } -function is_backward_branch_target ( +function is_backward_branch_target( ip: MintOpcodePtr, startOfBody: MintOpcodePtr, backwardBranchTable: Uint16Array | null ) { @@ -146,16 +146,16 @@ function is_backward_branch_target ( const knownConstantValues = new Map(); -function get_known_constant_value (localOffset: number) : number | undefined { +function get_known_constant_value(localOffset: number): number | undefined { return knownConstantValues.get(localOffset); } -export function generateWasmBody ( +export function generateWasmBody( frame: NativePointer, traceName: string, ip: MintOpcodePtr, startOfBody: MintOpcodePtr, endOfBody: MintOpcodePtr, builder: WasmBuilder, instrumentedTraceId: number, backwardBranchTable: Uint16Array | null -) : number { +): number { const abort = 0; let isFirstInstruction = true, isConditionallyExecuted = false, firstOpcodeInBlock = true; @@ -342,10 +342,10 @@ export function generateWasmBody ( const sizeOffset = getArgU16(ip, 3), valueOffset = getArgU16(ip, 2), destOffset = getArgU16(ip, 1); - /* - constantSize = get_known_constant_value(sizeOffset), - constantValue = get_known_constant_value(valueOffset); - */ + /* + constantSize = get_known_constant_value(sizeOffset), + constantValue = get_known_constant_value(valueOffset); + */ // TODO: Handle constant size initblks. Not sure if they matter though // FIXME: This will cause an erroneous bailout if dest and size are both 0 @@ -1056,7 +1056,7 @@ export function generateWasmBody ( case MintOpcode.MINT_CONV_I8_R4: case MintOpcode.MINT_CONV_I8_R8: { const isF32 = (opcode === MintOpcode.MINT_CONV_I4_R4) || - (opcode === MintOpcode.MINT_CONV_I8_R4), + (opcode === MintOpcode.MINT_CONV_I8_R4), isI64 = (opcode === MintOpcode.MINT_CONV_I8_R4) || (opcode === MintOpcode.MINT_CONV_I8_R8), limit = isI64 @@ -1379,32 +1379,32 @@ export function generateWasmBody ( return result; } -const notNullSince : Map = new Map(); +const notNullSince: Map = new Map(); let cknullOffset = -1; -function eraseInferredState () { +function eraseInferredState() { cknullOffset = -1; notNullSince.clear(); knownConstantValues.clear(); } -function invalidate_local (offset: number) { +function invalidate_local(offset: number) { if (cknullOffset === offset) cknullOffset = -1; notNullSince.delete(offset); knownConstantValues.delete(offset); } -function invalidate_local_range (start: number, bytes: number) { +function invalidate_local_range(start: number, bytes: number) { for (let i = 0; i < bytes; i += 1) invalidate_local(start + i); } -function append_branch_target_block (builder: WasmBuilder, ip: MintOpcodePtr, isBackBranchTarget: boolean) { +function append_branch_target_block(builder: WasmBuilder, ip: MintOpcodePtr, isBackBranchTarget: boolean) { builder.cfg.startBranchBlock(ip, isBackBranchTarget); } -function append_ldloc (builder: WasmBuilder, offset: number, opcode: WasmOpcode) { +function append_ldloc(builder: WasmBuilder, offset: number, opcode: WasmOpcode) { builder.local("pLocals"); builder.appendU8(opcode); // stackval is 8 bytes, but pLocals might not be 8 byte aligned so we use 4 @@ -1418,7 +1418,7 @@ function append_ldloc (builder: WasmBuilder, offset: number, opcode: WasmOpcode) // where the offset+alignment pair is referred to as a 'memarg' by the spec. // The actual store operation is equivalent to `pBase[offset] = value` (alignment has no // observable impact on behavior, other than causing compilation failures if out of range) -function append_stloc_tail (builder: WasmBuilder, offset: number, opcode: WasmOpcode) { +function append_stloc_tail(builder: WasmBuilder, offset: number, opcode: WasmOpcode) { builder.appendU8(opcode); // stackval is 8 bytes, but pLocals might not be 8 byte aligned so we use 4 // wasm spec prohibits alignment higher than natural alignment, just to be annoying @@ -1431,7 +1431,7 @@ function append_stloc_tail (builder: WasmBuilder, offset: number, opcode: WasmOp // used for writes // Pass transient=true if the address will not persist after use (so it can't be used to later // modify the contents of this local) -function append_ldloca (builder: WasmBuilder, localOffset: number, bytesInvalidated?: number) { +function append_ldloca(builder: WasmBuilder, localOffset: number, bytesInvalidated?: number) { if (typeof (bytesInvalidated) !== "number") bytesInvalidated = 512; // FIXME: We need to know how big this variable is so we can invalidate the whole space it occupies @@ -1440,7 +1440,7 @@ function append_ldloca (builder: WasmBuilder, localOffset: number, bytesInvalida builder.lea("pLocals", localOffset); } -function append_memset_local (builder: WasmBuilder, localOffset: number, value: number, count: number) { +function append_memset_local(builder: WasmBuilder, localOffset: number, value: number, count: number) { invalidate_local_range(localOffset, count); // spec: pop n, pop val, pop d, fill from d[0] to d[n] with value val @@ -1452,7 +1452,7 @@ function append_memset_local (builder: WasmBuilder, localOffset: number, value: append_memset_dest(builder, value, count); } -function append_memmove_local_local (builder: WasmBuilder, destLocalOffset: number, sourceLocalOffset: number, count: number) { +function append_memmove_local_local(builder: WasmBuilder, destLocalOffset: number, sourceLocalOffset: number, count: number) { invalidate_local_range(destLocalOffset, count); if (try_append_memmove_fast(builder, destLocalOffset, sourceLocalOffset, count, false)) @@ -1464,12 +1464,12 @@ function append_memmove_local_local (builder: WasmBuilder, destLocalOffset: numb append_memmove_dest_src(builder, count); } -function isAddressTaken (builder: WasmBuilder, localOffset: number) { +function isAddressTaken(builder: WasmBuilder, localOffset: number) { return cwraps.mono_jiterp_is_imethod_var_address_taken(get_imethod(builder.frame), localOffset) !== 0; } // Loads the specified i32 value and then bails out if it is null, leaving it in the cknull_ptr local. -function append_ldloc_cknull (builder: WasmBuilder, localOffset: number, ip: MintOpcodePtr, leaveOnStack: boolean) { +function append_ldloc_cknull(builder: WasmBuilder, localOffset: number, ip: MintOpcodePtr, leaveOnStack: boolean) { const optimize = builder.allowNullCheckOptimization && notNullSince.has(localOffset) && !isAddressTaken(builder, localOffset); @@ -1522,22 +1522,22 @@ function append_ldloc_cknull (builder: WasmBuilder, localOffset: number, ip: Min cknullOffset = -1; } -const ldcTable : { [opcode: number]: [WasmOpcode, number] } = { +const ldcTable: { [opcode: number]: [WasmOpcode, number] } = { [MintOpcode.MINT_LDC_I4_M1]: [WasmOpcode.i32_const, -1], - [MintOpcode.MINT_LDC_I4_0]: [WasmOpcode.i32_const, 0 ], - [MintOpcode.MINT_LDC_I4_1]: [WasmOpcode.i32_const, 1 ], - [MintOpcode.MINT_LDC_I4_2]: [WasmOpcode.i32_const, 2 ], - [MintOpcode.MINT_LDC_I4_3]: [WasmOpcode.i32_const, 3 ], - [MintOpcode.MINT_LDC_I4_4]: [WasmOpcode.i32_const, 4 ], - [MintOpcode.MINT_LDC_I4_5]: [WasmOpcode.i32_const, 5 ], - [MintOpcode.MINT_LDC_I4_6]: [WasmOpcode.i32_const, 6 ], - [MintOpcode.MINT_LDC_I4_7]: [WasmOpcode.i32_const, 7 ], - [MintOpcode.MINT_LDC_I4_8]: [WasmOpcode.i32_const, 8 ], + [MintOpcode.MINT_LDC_I4_0]: [WasmOpcode.i32_const, 0], + [MintOpcode.MINT_LDC_I4_1]: [WasmOpcode.i32_const, 1], + [MintOpcode.MINT_LDC_I4_2]: [WasmOpcode.i32_const, 2], + [MintOpcode.MINT_LDC_I4_3]: [WasmOpcode.i32_const, 3], + [MintOpcode.MINT_LDC_I4_4]: [WasmOpcode.i32_const, 4], + [MintOpcode.MINT_LDC_I4_5]: [WasmOpcode.i32_const, 5], + [MintOpcode.MINT_LDC_I4_6]: [WasmOpcode.i32_const, 6], + [MintOpcode.MINT_LDC_I4_7]: [WasmOpcode.i32_const, 7], + [MintOpcode.MINT_LDC_I4_8]: [WasmOpcode.i32_const, 8], }; -function emit_ldc (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean { +function emit_ldc(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { let storeType = WasmOpcode.i32_store; - let value : number | undefined; + let value: number | undefined; const tableEntry = ldcTable[opcode]; if (tableEntry) { @@ -1607,7 +1607,7 @@ function emit_ldc (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) return true; } -function emit_mov (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean { +function emit_mov(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { let loadOp = WasmOpcode.i32_load, storeOp = WasmOpcode.i32_store; switch (opcode) { case MintOpcode.MINT_MOV_I4_I1: @@ -1670,7 +1670,7 @@ function emit_mov (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) return true; } -function append_vtable_initialize (builder: WasmBuilder, pVtable: NativePointer, ip: MintOpcodePtr) { +function append_vtable_initialize(builder: WasmBuilder, pVtable: NativePointer, ip: MintOpcodePtr) { // TODO: Actually initialize the vtable instead of just checking and bailing out? builder.block(); // FIXME: This will prevent us from reusing traces between runs since the vtables can move @@ -1685,17 +1685,18 @@ function append_vtable_initialize (builder: WasmBuilder, pVtable: NativePointer, builder.endBlock(); } -function emit_fieldop ( +function emit_fieldop( builder: WasmBuilder, frame: NativePointer, ip: MintOpcodePtr, opcode: MintOpcode -) : boolean { +): boolean { const isLoad = ( (opcode >= MintOpcode.MINT_LDFLD_I1) && (opcode <= MintOpcode.MINT_LDFLDA_UNSAFE) - ) || ( - (opcode >= MintOpcode.MINT_LDSFLD_I1) && - (opcode <= MintOpcode.MINT_LDSFLD_W) - ); + ) || + ( + (opcode >= MintOpcode.MINT_LDSFLD_I1) && + (opcode <= MintOpcode.MINT_LDSFLD_W) + ); const objectOffset = getArgU16(ip, isLoad ? 2 : 1), fieldOffset = getArgU16(ip, 3), @@ -1870,17 +1871,18 @@ function emit_fieldop ( } } -function emit_sfieldop ( +function emit_sfieldop( builder: WasmBuilder, frame: NativePointer, ip: MintOpcodePtr, opcode: MintOpcode -) : boolean { +): boolean { const isLoad = ( (opcode >= MintOpcode.MINT_LDFLD_I1) && (opcode <= MintOpcode.MINT_LDFLDA_UNSAFE) - ) || ( - (opcode >= MintOpcode.MINT_LDSFLD_I1) && - (opcode <= MintOpcode.MINT_LDSFLD_W) - ); + ) || + ( + (opcode >= MintOpcode.MINT_LDSFLD_I1) && + (opcode <= MintOpcode.MINT_LDSFLD_W) + ); const localOffset = getArgU16(ip, 1), pVtable = get_imethod_data(frame, getArgU16(ip, 2)), @@ -1981,7 +1983,7 @@ type OpRec3 = [WasmOpcode, WasmOpcode, WasmOpcode]; // operator, lhsLoadOperator, rhsLoadOperator, storeOperator type OpRec4 = [WasmOpcode, WasmOpcode, WasmOpcode, WasmOpcode]; -const floatToIntTable : { [opcode: number]: WasmOpcode } = { +const floatToIntTable: { [opcode: number]: WasmOpcode } = { [MintOpcode.MINT_CONV_I4_R4]: WasmOpcode.i32_trunc_s_f32, [MintOpcode.MINT_CONV_I8_R4]: WasmOpcode.i64_trunc_s_f32, [MintOpcode.MINT_CONV_I4_R8]: WasmOpcode.i32_trunc_s_f64, @@ -1989,25 +1991,25 @@ const floatToIntTable : { [opcode: number]: WasmOpcode } = { }; // thanks for making this as complex as possible, typescript -const unopTable : { [opcode: number]: OpRec3 | undefined } = { - [MintOpcode.MINT_CEQ0_I4]: [WasmOpcode.i32_eqz, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD1_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SUB1_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_NEG_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_NOT_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_ADD1_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SUB1_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_NEG_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_NOT_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], - - [MintOpcode.MINT_ADD_I4_IMM]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_MUL_I4_IMM]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD_I8_IMM]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_MUL_I8_IMM]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], - - [MintOpcode.MINT_NEG_R4]: [WasmOpcode.f32_neg, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_NEG_R8]: [WasmOpcode.f64_neg, WasmOpcode.f64_load, WasmOpcode.f64_store], +const unopTable: { [opcode: number]: OpRec3 | undefined } = { + [MintOpcode.MINT_CEQ0_I4]: [WasmOpcode.i32_eqz, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD1_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SUB1_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_NEG_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_NOT_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_ADD1_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SUB1_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_NEG_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_NOT_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], + + [MintOpcode.MINT_ADD_I4_IMM]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_MUL_I4_IMM]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD_I8_IMM]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_MUL_I8_IMM]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], + + [MintOpcode.MINT_NEG_R4]: [WasmOpcode.f32_neg, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_NEG_R8]: [WasmOpcode.f64_neg, WasmOpcode.f64_load, WasmOpcode.f64_store], [MintOpcode.MINT_CONV_R4_I4]: [WasmOpcode.f32_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f32_store], [MintOpcode.MINT_CONV_R8_I4]: [WasmOpcode.f64_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f64_store], @@ -2015,45 +2017,45 @@ const unopTable : { [opcode: number]: OpRec3 | undefined } = { [MintOpcode.MINT_CONV_R4_I8]: [WasmOpcode.f32_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f32_store], [MintOpcode.MINT_CONV_R8_I8]: [WasmOpcode.f64_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f64_store], [MintOpcode.MINT_CONV_R_UN_I8]: [WasmOpcode.f64_convert_u_i64, WasmOpcode.i64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_CONV_R8_R4]: [WasmOpcode.f64_promote_f32, WasmOpcode.f32_load, WasmOpcode.f64_store], - [MintOpcode.MINT_CONV_R4_R8]: [WasmOpcode.f32_demote_f64, WasmOpcode.f64_load, WasmOpcode.f32_store], - - [MintOpcode.MINT_CONV_I8_I4]: [WasmOpcode.nop, WasmOpcode.i64_load32_s, WasmOpcode.i64_store], - [MintOpcode.MINT_CONV_I8_U4]: [WasmOpcode.nop, WasmOpcode.i64_load32_u, WasmOpcode.i64_store], - - [MintOpcode.MINT_CONV_U1_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_U2_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I1_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I2_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CONV_U1_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_U2_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I1_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I2_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_SHL_I4_IMM]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHL_I8_IMM]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHR_I4_IMM]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHR_I8_IMM]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHR_UN_I4_IMM]: [WasmOpcode.i32_shr_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHR_UN_I8_IMM]: [WasmOpcode.i64_shr_u, WasmOpcode.i64_load, WasmOpcode.i64_store], - - [MintOpcode.MINT_ROL_I4_IMM]: [WasmOpcode.i32_rotl, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ROL_I8_IMM]: [WasmOpcode.i64_rotl, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_ROR_I4_IMM]: [WasmOpcode.i32_rotr, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ROR_I8_IMM]: [WasmOpcode.i64_rotr, WasmOpcode.i64_load, WasmOpcode.i64_store], - - [MintOpcode.MINT_CLZ_I4]: [WasmOpcode.i32_clz, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CTZ_I4]: [WasmOpcode.i32_ctz, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_POPCNT_I4]: [WasmOpcode.i32_popcnt, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLZ_I8]: [WasmOpcode.i64_clz, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_CTZ_I8]: [WasmOpcode.i64_ctz, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_POPCNT_I8]: [WasmOpcode.i64_popcnt, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_R8_R4]: [WasmOpcode.f64_promote_f32, WasmOpcode.f32_load, WasmOpcode.f64_store], + [MintOpcode.MINT_CONV_R4_R8]: [WasmOpcode.f32_demote_f64, WasmOpcode.f64_load, WasmOpcode.f32_store], + + [MintOpcode.MINT_CONV_I8_I4]: [WasmOpcode.nop, WasmOpcode.i64_load32_s, WasmOpcode.i64_store], + [MintOpcode.MINT_CONV_I8_U4]: [WasmOpcode.nop, WasmOpcode.i64_load32_u, WasmOpcode.i64_store], + + [MintOpcode.MINT_CONV_U1_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_U2_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I1_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I2_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CONV_U1_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_U2_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I1_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I2_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_SHL_I4_IMM]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHL_I8_IMM]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHR_I4_IMM]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHR_I8_IMM]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHR_UN_I4_IMM]: [WasmOpcode.i32_shr_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHR_UN_I8_IMM]: [WasmOpcode.i64_shr_u, WasmOpcode.i64_load, WasmOpcode.i64_store], + + [MintOpcode.MINT_ROL_I4_IMM]: [WasmOpcode.i32_rotl, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ROL_I8_IMM]: [WasmOpcode.i64_rotl, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_ROR_I4_IMM]: [WasmOpcode.i32_rotr, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ROR_I8_IMM]: [WasmOpcode.i64_rotr, WasmOpcode.i64_load, WasmOpcode.i64_store], + + [MintOpcode.MINT_CLZ_I4]: [WasmOpcode.i32_clz, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CTZ_I4]: [WasmOpcode.i32_ctz, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_POPCNT_I4]: [WasmOpcode.i32_popcnt, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLZ_I8]: [WasmOpcode.i64_clz, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_CTZ_I8]: [WasmOpcode.i64_ctz, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_POPCNT_I8]: [WasmOpcode.i64_popcnt, WasmOpcode.i32_load, WasmOpcode.i32_store], }; // HACK: Generating correct wasm for these is non-trivial so we hand them off to C. // The opcode specifies whether the operands need to be promoted first. -const intrinsicFpBinops : { [opcode: number] : WasmOpcode } = { +const intrinsicFpBinops: { [opcode: number]: WasmOpcode } = { [MintOpcode.MINT_CEQ_R4]: WasmOpcode.f64_promote_f32, [MintOpcode.MINT_CEQ_R8]: WasmOpcode.nop, [MintOpcode.MINT_CNE_R4]: WasmOpcode.f64_promote_f32, @@ -2078,160 +2080,160 @@ const intrinsicFpBinops : { [opcode: number] : WasmOpcode } = { [JiterpSpecialOpcode.CNE_UN_R8]: WasmOpcode.nop, }; -const binopTable : { [opcode: number]: OpRec3 | OpRec4 | undefined } = { - [MintOpcode.MINT_ADD_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD_OVF_I4]:[WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD_OVF_UN_I4]:[WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SUB_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_MUL_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_MUL_OVF_I4]:[WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_MUL_OVF_UN_I4]:[WasmOpcode.i32_mul,WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_DIV_I4]: [WasmOpcode.i32_div_s, WasmOpcode.i32_load, WasmOpcode.i32_store], +const binopTable: { [opcode: number]: OpRec3 | OpRec4 | undefined } = { + [MintOpcode.MINT_ADD_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD_OVF_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD_OVF_UN_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SUB_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_MUL_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_MUL_OVF_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_MUL_OVF_UN_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_DIV_I4]: [WasmOpcode.i32_div_s, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_DIV_UN_I4]: [WasmOpcode.i32_div_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_REM_I4]: [WasmOpcode.i32_rem_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_REM_I4]: [WasmOpcode.i32_rem_s, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_REM_UN_I4]: [WasmOpcode.i32_rem_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_AND_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_OR_I4]: [WasmOpcode.i32_or, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_XOR_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHL_I4]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHR_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_AND_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_OR_I4]: [WasmOpcode.i32_or, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_XOR_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHL_I4]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHR_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_SHR_UN_I4]: [WasmOpcode.i32_shr_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SUB_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_MUL_I8]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_DIV_I8]: [WasmOpcode.i64_div_s, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_REM_I8]: [WasmOpcode.i64_rem_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_ADD_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SUB_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_MUL_I8]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_DIV_I8]: [WasmOpcode.i64_div_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_REM_I8]: [WasmOpcode.i64_rem_s, WasmOpcode.i64_load, WasmOpcode.i64_store], [MintOpcode.MINT_DIV_UN_I8]: [WasmOpcode.i64_div_u, WasmOpcode.i64_load, WasmOpcode.i64_store], [MintOpcode.MINT_REM_UN_I8]: [WasmOpcode.i64_rem_u, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_AND_I8]: [WasmOpcode.i64_and, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_OR_I8]: [WasmOpcode.i64_or, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_XOR_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHL_I8]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHR_I8]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_AND_I8]: [WasmOpcode.i64_and, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_OR_I8]: [WasmOpcode.i64_or, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_XOR_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHL_I8]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHR_I8]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], [MintOpcode.MINT_SHR_UN_I8]: [WasmOpcode.i64_shr_u, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_ADD_R4]: [WasmOpcode.f32_add, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_SUB_R4]: [WasmOpcode.f32_sub, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_MUL_R4]: [WasmOpcode.f32_mul, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_DIV_R4]: [WasmOpcode.f32_div, WasmOpcode.f32_load, WasmOpcode.f32_store], - - [MintOpcode.MINT_ADD_R8]: [WasmOpcode.f64_add, WasmOpcode.f64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_SUB_R8]: [WasmOpcode.f64_sub, WasmOpcode.f64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_MUL_R8]: [WasmOpcode.f64_mul, WasmOpcode.f64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_DIV_R8]: [WasmOpcode.f64_div, WasmOpcode.f64_load, WasmOpcode.f64_store], - - [MintOpcode.MINT_CEQ_I4]: [WasmOpcode.i32_eq, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CNE_I4]: [WasmOpcode.i32_ne, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLT_I4]: [WasmOpcode.i32_lt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_I4]: [WasmOpcode.i32_gt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_I4]: [WasmOpcode.i32_le_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_I4]: [WasmOpcode.i32_ge_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CLT_UN_I4]: [WasmOpcode.i32_lt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_UN_I4]: [WasmOpcode.i32_gt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_UN_I4]: [WasmOpcode.i32_le_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_UN_I4]: [WasmOpcode.i32_ge_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CEQ_I8]: [WasmOpcode.i64_eq, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CNE_I8]: [WasmOpcode.i64_ne, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLT_I8]: [WasmOpcode.i64_lt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_I8]: [WasmOpcode.i64_gt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_I8]: [WasmOpcode.i64_le_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_I8]: [WasmOpcode.i64_ge_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CLT_UN_I8]: [WasmOpcode.i64_lt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_UN_I8]: [WasmOpcode.i64_gt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_UN_I8]: [WasmOpcode.i64_le_u, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_UN_I8]: [WasmOpcode.i64_ge_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD_R4]: [WasmOpcode.f32_add, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_SUB_R4]: [WasmOpcode.f32_sub, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_MUL_R4]: [WasmOpcode.f32_mul, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_DIV_R4]: [WasmOpcode.f32_div, WasmOpcode.f32_load, WasmOpcode.f32_store], + + [MintOpcode.MINT_ADD_R8]: [WasmOpcode.f64_add, WasmOpcode.f64_load, WasmOpcode.f64_store], + [MintOpcode.MINT_SUB_R8]: [WasmOpcode.f64_sub, WasmOpcode.f64_load, WasmOpcode.f64_store], + [MintOpcode.MINT_MUL_R8]: [WasmOpcode.f64_mul, WasmOpcode.f64_load, WasmOpcode.f64_store], + [MintOpcode.MINT_DIV_R8]: [WasmOpcode.f64_div, WasmOpcode.f64_load, WasmOpcode.f64_store], + + [MintOpcode.MINT_CEQ_I4]: [WasmOpcode.i32_eq, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CNE_I4]: [WasmOpcode.i32_ne, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLT_I4]: [WasmOpcode.i32_lt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_I4]: [WasmOpcode.i32_gt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_I4]: [WasmOpcode.i32_le_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_I4]: [WasmOpcode.i32_ge_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CLT_UN_I4]: [WasmOpcode.i32_lt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_UN_I4]: [WasmOpcode.i32_gt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_UN_I4]: [WasmOpcode.i32_le_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_UN_I4]: [WasmOpcode.i32_ge_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CEQ_I8]: [WasmOpcode.i64_eq, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CNE_I8]: [WasmOpcode.i64_ne, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLT_I8]: [WasmOpcode.i64_lt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_I8]: [WasmOpcode.i64_gt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_I8]: [WasmOpcode.i64_le_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_I8]: [WasmOpcode.i64_ge_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CLT_UN_I8]: [WasmOpcode.i64_lt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_UN_I8]: [WasmOpcode.i64_gt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_UN_I8]: [WasmOpcode.i64_le_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_UN_I8]: [WasmOpcode.i64_ge_u, WasmOpcode.i64_load, WasmOpcode.i32_store], }; -const relopbranchTable : { [opcode: number]: [comparisonOpcode: MintOpcode, immediateOpcode: WasmOpcode | false, isSafepoint: boolean] | MintOpcode | undefined } = { - [MintOpcode.MINT_BEQ_I4_S]: MintOpcode.MINT_CEQ_I4, - [MintOpcode.MINT_BNE_UN_I4_S]: MintOpcode.MINT_CNE_I4, - [MintOpcode.MINT_BGT_I4_S]: MintOpcode.MINT_CGT_I4, - [MintOpcode.MINT_BGT_UN_I4_S]: MintOpcode.MINT_CGT_UN_I4, - [MintOpcode.MINT_BLT_I4_S]: MintOpcode.MINT_CLT_I4, - [MintOpcode.MINT_BLT_UN_I4_S]: MintOpcode.MINT_CLT_UN_I4, - [MintOpcode.MINT_BGE_I4_S]: MintOpcode.MINT_CGE_I4, - [MintOpcode.MINT_BGE_UN_I4_S]: MintOpcode.MINT_CGE_UN_I4, - [MintOpcode.MINT_BLE_I4_S]: MintOpcode.MINT_CLE_I4, - [MintOpcode.MINT_BLE_UN_I4_S]: MintOpcode.MINT_CLE_UN_I4, - - [MintOpcode.MINT_BEQ_I4_SP]: [MintOpcode.MINT_CEQ_I4, false, true], - [MintOpcode.MINT_BNE_UN_I4_SP]: [MintOpcode.MINT_CNE_I4, false, true], - [MintOpcode.MINT_BGT_I4_SP]: [MintOpcode.MINT_CGT_I4, false, true], - [MintOpcode.MINT_BGT_UN_I4_SP]: [MintOpcode.MINT_CGT_UN_I4, false, true], - [MintOpcode.MINT_BLT_I4_SP]: [MintOpcode.MINT_CLT_I4, false, true], - [MintOpcode.MINT_BLT_UN_I4_SP]: [MintOpcode.MINT_CLT_UN_I4, false, true], - [MintOpcode.MINT_BGE_I4_SP]: [MintOpcode.MINT_CGE_I4, false, true], - [MintOpcode.MINT_BGE_UN_I4_SP]: [MintOpcode.MINT_CGE_UN_I4, false, true], - [MintOpcode.MINT_BLE_I4_SP]: [MintOpcode.MINT_CLE_I4, false, true], - [MintOpcode.MINT_BLE_UN_I4_SP]: [MintOpcode.MINT_CLE_UN_I4, false, true], - - [MintOpcode.MINT_BEQ_I4_IMM_SP]: [MintOpcode.MINT_CEQ_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BNE_UN_I4_IMM_SP]: [MintOpcode.MINT_CNE_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BGT_I4_IMM_SP]: [MintOpcode.MINT_CGT_I4, WasmOpcode.i32_const, true], +const relopbranchTable: { [opcode: number]: [comparisonOpcode: MintOpcode, immediateOpcode: WasmOpcode | false, isSafepoint: boolean] | MintOpcode | undefined } = { + [MintOpcode.MINT_BEQ_I4_S]: MintOpcode.MINT_CEQ_I4, + [MintOpcode.MINT_BNE_UN_I4_S]: MintOpcode.MINT_CNE_I4, + [MintOpcode.MINT_BGT_I4_S]: MintOpcode.MINT_CGT_I4, + [MintOpcode.MINT_BGT_UN_I4_S]: MintOpcode.MINT_CGT_UN_I4, + [MintOpcode.MINT_BLT_I4_S]: MintOpcode.MINT_CLT_I4, + [MintOpcode.MINT_BLT_UN_I4_S]: MintOpcode.MINT_CLT_UN_I4, + [MintOpcode.MINT_BGE_I4_S]: MintOpcode.MINT_CGE_I4, + [MintOpcode.MINT_BGE_UN_I4_S]: MintOpcode.MINT_CGE_UN_I4, + [MintOpcode.MINT_BLE_I4_S]: MintOpcode.MINT_CLE_I4, + [MintOpcode.MINT_BLE_UN_I4_S]: MintOpcode.MINT_CLE_UN_I4, + + [MintOpcode.MINT_BEQ_I4_SP]: [MintOpcode.MINT_CEQ_I4, false, true], + [MintOpcode.MINT_BNE_UN_I4_SP]: [MintOpcode.MINT_CNE_I4, false, true], + [MintOpcode.MINT_BGT_I4_SP]: [MintOpcode.MINT_CGT_I4, false, true], + [MintOpcode.MINT_BGT_UN_I4_SP]: [MintOpcode.MINT_CGT_UN_I4, false, true], + [MintOpcode.MINT_BLT_I4_SP]: [MintOpcode.MINT_CLT_I4, false, true], + [MintOpcode.MINT_BLT_UN_I4_SP]: [MintOpcode.MINT_CLT_UN_I4, false, true], + [MintOpcode.MINT_BGE_I4_SP]: [MintOpcode.MINT_CGE_I4, false, true], + [MintOpcode.MINT_BGE_UN_I4_SP]: [MintOpcode.MINT_CGE_UN_I4, false, true], + [MintOpcode.MINT_BLE_I4_SP]: [MintOpcode.MINT_CLE_I4, false, true], + [MintOpcode.MINT_BLE_UN_I4_SP]: [MintOpcode.MINT_CLE_UN_I4, false, true], + + [MintOpcode.MINT_BEQ_I4_IMM_SP]: [MintOpcode.MINT_CEQ_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BNE_UN_I4_IMM_SP]: [MintOpcode.MINT_CNE_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BGT_I4_IMM_SP]: [MintOpcode.MINT_CGT_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BGT_UN_I4_IMM_SP]: [MintOpcode.MINT_CGT_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BLT_I4_IMM_SP]: [MintOpcode.MINT_CLT_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BLT_I4_IMM_SP]: [MintOpcode.MINT_CLT_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BLT_UN_I4_IMM_SP]: [MintOpcode.MINT_CLT_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BGE_I4_IMM_SP]: [MintOpcode.MINT_CGE_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BGE_I4_IMM_SP]: [MintOpcode.MINT_CGE_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BGE_UN_I4_IMM_SP]: [MintOpcode.MINT_CGE_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BLE_I4_IMM_SP]: [MintOpcode.MINT_CLE_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BLE_I4_IMM_SP]: [MintOpcode.MINT_CLE_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BLE_UN_I4_IMM_SP]: [MintOpcode.MINT_CLE_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BEQ_I8_S]: MintOpcode.MINT_CEQ_I8, - [MintOpcode.MINT_BNE_UN_I8_S]: MintOpcode.MINT_CNE_I8, - [MintOpcode.MINT_BGT_I8_S]: MintOpcode.MINT_CGT_I8, - [MintOpcode.MINT_BGT_UN_I8_S]: MintOpcode.MINT_CGT_UN_I8, - [MintOpcode.MINT_BLT_I8_S]: MintOpcode.MINT_CLT_I8, - [MintOpcode.MINT_BLT_UN_I8_S]: MintOpcode.MINT_CLT_UN_I8, - [MintOpcode.MINT_BGE_I8_S]: MintOpcode.MINT_CGE_I8, - [MintOpcode.MINT_BGE_UN_I8_S]: MintOpcode.MINT_CGE_UN_I8, - [MintOpcode.MINT_BLE_I8_S]: MintOpcode.MINT_CLE_I8, - [MintOpcode.MINT_BLE_UN_I8_S]: MintOpcode.MINT_CLE_UN_I8, - - [MintOpcode.MINT_BEQ_I8_IMM_SP]: [MintOpcode.MINT_CEQ_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BEQ_I8_S]: MintOpcode.MINT_CEQ_I8, + [MintOpcode.MINT_BNE_UN_I8_S]: MintOpcode.MINT_CNE_I8, + [MintOpcode.MINT_BGT_I8_S]: MintOpcode.MINT_CGT_I8, + [MintOpcode.MINT_BGT_UN_I8_S]: MintOpcode.MINT_CGT_UN_I8, + [MintOpcode.MINT_BLT_I8_S]: MintOpcode.MINT_CLT_I8, + [MintOpcode.MINT_BLT_UN_I8_S]: MintOpcode.MINT_CLT_UN_I8, + [MintOpcode.MINT_BGE_I8_S]: MintOpcode.MINT_CGE_I8, + [MintOpcode.MINT_BGE_UN_I8_S]: MintOpcode.MINT_CGE_UN_I8, + [MintOpcode.MINT_BLE_I8_S]: MintOpcode.MINT_CLE_I8, + [MintOpcode.MINT_BLE_UN_I8_S]: MintOpcode.MINT_CLE_UN_I8, + + [MintOpcode.MINT_BEQ_I8_IMM_SP]: [MintOpcode.MINT_CEQ_I8, WasmOpcode.i64_const, true], // FIXME: Missing compare opcode // [MintOpcode.MINT_BNE_UN_I8_IMM_SP]: [MintOpcode.MINT_CNE_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BGT_I8_IMM_SP]: [MintOpcode.MINT_CGT_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BGT_I8_IMM_SP]: [MintOpcode.MINT_CGT_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BGT_UN_I8_IMM_SP]: [MintOpcode.MINT_CGT_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BLT_I8_IMM_SP]: [MintOpcode.MINT_CLT_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BLT_I8_IMM_SP]: [MintOpcode.MINT_CLT_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BLT_UN_I8_IMM_SP]: [MintOpcode.MINT_CLT_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BGE_I8_IMM_SP]: [MintOpcode.MINT_CGE_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BGE_I8_IMM_SP]: [MintOpcode.MINT_CGE_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BGE_UN_I8_IMM_SP]: [MintOpcode.MINT_CGE_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BLE_I8_IMM_SP]: [MintOpcode.MINT_CLE_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BLE_I8_IMM_SP]: [MintOpcode.MINT_CLE_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BLE_UN_I8_IMM_SP]: [MintOpcode.MINT_CLE_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BEQ_R4_S]: MintOpcode.MINT_CEQ_R4, - [MintOpcode.MINT_BNE_UN_R4_S]: JiterpSpecialOpcode.CNE_UN_R4, - [MintOpcode.MINT_BGT_R4_S]: MintOpcode.MINT_CGT_R4, - [MintOpcode.MINT_BGT_UN_R4_S]: MintOpcode.MINT_CGT_UN_R4, - [MintOpcode.MINT_BLT_R4_S]: MintOpcode.MINT_CLT_R4, - [MintOpcode.MINT_BLT_UN_R4_S]: MintOpcode.MINT_CLT_UN_R4, - [MintOpcode.MINT_BGE_R4_S]: MintOpcode.MINT_CGE_R4, - [MintOpcode.MINT_BGE_UN_R4_S]: JiterpSpecialOpcode.CGE_UN_R4, - [MintOpcode.MINT_BLE_R4_S]: MintOpcode.MINT_CLE_R4, - [MintOpcode.MINT_BLE_UN_R4_S]: JiterpSpecialOpcode.CLE_UN_R4, - - [MintOpcode.MINT_BEQ_R8_S]: MintOpcode.MINT_CEQ_R8, - [MintOpcode.MINT_BNE_UN_R8_S]: JiterpSpecialOpcode.CNE_UN_R8, - [MintOpcode.MINT_BGT_R8_S]: MintOpcode.MINT_CGT_R8, - [MintOpcode.MINT_BGT_UN_R8_S]: MintOpcode.MINT_CGT_UN_R8, - [MintOpcode.MINT_BLT_R8_S]: MintOpcode.MINT_CLT_R8, - [MintOpcode.MINT_BLT_UN_R8_S]: MintOpcode.MINT_CLT_UN_R8, - [MintOpcode.MINT_BGE_R8_S]: MintOpcode.MINT_CGE_R8, - [MintOpcode.MINT_BGE_UN_R8_S]: JiterpSpecialOpcode.CGE_UN_R8, - [MintOpcode.MINT_BLE_R8_S]: MintOpcode.MINT_CLE_R8, - [MintOpcode.MINT_BLE_UN_R8_S]: JiterpSpecialOpcode.CLE_UN_R8, + [MintOpcode.MINT_BEQ_R4_S]: MintOpcode.MINT_CEQ_R4, + [MintOpcode.MINT_BNE_UN_R4_S]: JiterpSpecialOpcode.CNE_UN_R4, + [MintOpcode.MINT_BGT_R4_S]: MintOpcode.MINT_CGT_R4, + [MintOpcode.MINT_BGT_UN_R4_S]: MintOpcode.MINT_CGT_UN_R4, + [MintOpcode.MINT_BLT_R4_S]: MintOpcode.MINT_CLT_R4, + [MintOpcode.MINT_BLT_UN_R4_S]: MintOpcode.MINT_CLT_UN_R4, + [MintOpcode.MINT_BGE_R4_S]: MintOpcode.MINT_CGE_R4, + [MintOpcode.MINT_BGE_UN_R4_S]: JiterpSpecialOpcode.CGE_UN_R4, + [MintOpcode.MINT_BLE_R4_S]: MintOpcode.MINT_CLE_R4, + [MintOpcode.MINT_BLE_UN_R4_S]: JiterpSpecialOpcode.CLE_UN_R4, + + [MintOpcode.MINT_BEQ_R8_S]: MintOpcode.MINT_CEQ_R8, + [MintOpcode.MINT_BNE_UN_R8_S]: JiterpSpecialOpcode.CNE_UN_R8, + [MintOpcode.MINT_BGT_R8_S]: MintOpcode.MINT_CGT_R8, + [MintOpcode.MINT_BGT_UN_R8_S]: MintOpcode.MINT_CGT_UN_R8, + [MintOpcode.MINT_BLT_R8_S]: MintOpcode.MINT_CLT_R8, + [MintOpcode.MINT_BLT_UN_R8_S]: MintOpcode.MINT_CLT_UN_R8, + [MintOpcode.MINT_BGE_R8_S]: MintOpcode.MINT_CGE_R8, + [MintOpcode.MINT_BGE_UN_R8_S]: JiterpSpecialOpcode.CGE_UN_R8, + [MintOpcode.MINT_BLE_R8_S]: MintOpcode.MINT_CLE_R8, + [MintOpcode.MINT_BLE_UN_R8_S]: JiterpSpecialOpcode.CLE_UN_R8, }; -function emit_binop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean { +function emit_binop(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { // operands are popped right to left, which means you build the arg list left to right - let lhsLoadOp : WasmOpcode, rhsLoadOp : WasmOpcode, storeOp : WasmOpcode, + let lhsLoadOp: WasmOpcode, rhsLoadOp: WasmOpcode, storeOp: WasmOpcode, lhsVar = "math_lhs32", rhsVar = "math_rhs32", - info : OpRec3 | OpRec4 | undefined, + info: OpRec3 | OpRec4 | undefined, operandsCached = false; const intrinsicFpBinop = intrinsicFpBinops[opcode]; @@ -2379,7 +2381,7 @@ function emit_binop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode return true; } -function emit_unop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean { +function emit_unop(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { // operands are popped right to left, which means you build the arg list left to right const info = unopTable[opcode]; if (!info) @@ -2502,7 +2504,7 @@ function emit_unop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) return true; } -function append_call_handler_store_ret_ip ( +function append_call_handler_store_ret_ip( builder: WasmBuilder, ip: MintOpcodePtr, frame: NativePointer, opcode: MintOpcode ) { @@ -2522,10 +2524,10 @@ function append_call_handler_store_ret_ip ( builder.callHandlerReturnAddresses.push(retIp); } -function emit_branch ( +function emit_branch( builder: WasmBuilder, ip: MintOpcodePtr, frame: NativePointer, opcode: MintOpcode, displacement?: number -) : boolean { +): boolean { const info = OpcodeInfo[opcode]; const isSafepoint = (opcode >= MintOpcode.MINT_BRFALSE_I4_SP) && (opcode <= MintOpcode.MINT_BLT_UN_I8_IMM_SP); @@ -2687,10 +2689,10 @@ function emit_branch ( return true; } -function emit_relop_branch ( +function emit_relop_branch( builder: WasmBuilder, ip: MintOpcodePtr, frame: NativePointer, opcode: MintOpcode -) : boolean { +): boolean { const relopBranchInfo = relopbranchTable[opcode]; if (!relopBranchInfo) return false; @@ -2750,61 +2752,61 @@ function emit_relop_branch ( return emit_branch(builder, ip, frame, opcode, displacement); } -const mathIntrinsicTable : { [opcode: number] : [isUnary: boolean, isF32: boolean, opcodeOrFuncName: WasmOpcode | string] } = { - [MintOpcode.MINT_SQRT]: [true, false, WasmOpcode.f64_sqrt], - [MintOpcode.MINT_SQRTF]: [true, true, WasmOpcode.f32_sqrt], - [MintOpcode.MINT_CEILING]: [true, false, WasmOpcode.f64_ceil], - [MintOpcode.MINT_CEILINGF]: [true, true, WasmOpcode.f32_ceil], - [MintOpcode.MINT_FLOOR]: [true, false, WasmOpcode.f64_floor], - [MintOpcode.MINT_FLOORF]: [true, true, WasmOpcode.f32_floor], - [MintOpcode.MINT_ABS]: [true, false, WasmOpcode.f64_abs], - [MintOpcode.MINT_ABSF]: [true, true, WasmOpcode.f32_abs], - - [MintOpcode.MINT_ACOS]: [true, false, "acos"], - [MintOpcode.MINT_ACOSF]: [true, true, "acosf"], - [MintOpcode.MINT_ACOSH]: [true, false, "acosh"], - [MintOpcode.MINT_ACOSHF]: [true, true, "acoshf"], - [MintOpcode.MINT_COS]: [true, false, "cos"], - [MintOpcode.MINT_COSF]: [true, true, "cosf"], - [MintOpcode.MINT_ASIN]: [true, false, "asin"], - [MintOpcode.MINT_ASINF]: [true, true, "asinf"], - [MintOpcode.MINT_ASINH]: [true, false, "asinh"], - [MintOpcode.MINT_ASINHF]: [true, true, "asinhf"], - [MintOpcode.MINT_SIN]: [true, false, "sin"], - [MintOpcode.MINT_SINF]: [true, true, "sinf"], - [MintOpcode.MINT_ATAN]: [true, false, "atan"], - [MintOpcode.MINT_ATANF]: [true, true, "atanf"], - [MintOpcode.MINT_ATANH]: [true, false, "atanh"], - [MintOpcode.MINT_ATANHF]: [true, true, "atanhf"], - [MintOpcode.MINT_TAN]: [true, false, "tan"], - [MintOpcode.MINT_TANF]: [true, true, "tanf"], - [MintOpcode.MINT_CBRT]: [true, false, "cbrt"], - [MintOpcode.MINT_CBRTF]: [true, true, "cbrtf"], - [MintOpcode.MINT_EXP]: [true, false, "exp"], - [MintOpcode.MINT_EXPF]: [true, true, "expf"], - [MintOpcode.MINT_LOG]: [true, false, "log"], - [MintOpcode.MINT_LOGF]: [true, true, "logf"], - [MintOpcode.MINT_LOG2]: [true, false, "log2"], - [MintOpcode.MINT_LOG2F]: [true, true, "log2f"], - [MintOpcode.MINT_LOG10]: [true, false, "log10"], - [MintOpcode.MINT_LOG10F]: [true, true, "log10f"], - - [MintOpcode.MINT_MIN]: [false, false, WasmOpcode.f64_min], - [MintOpcode.MINT_MINF]: [false, true, WasmOpcode.f32_min], - [MintOpcode.MINT_MAX]: [false, false, WasmOpcode.f64_max], - [MintOpcode.MINT_MAXF]: [false, true, WasmOpcode.f32_max], - - [MintOpcode.MINT_ATAN2]: [false, false, "atan2"], - [MintOpcode.MINT_ATAN2F]: [false, true, "atan2f"], - [MintOpcode.MINT_POW]: [false, false, "pow"], - [MintOpcode.MINT_POWF]: [false, true, "powf"], - [MintOpcode.MINT_REM_R8]: [false, false, "fmod"], - [MintOpcode.MINT_REM_R4]: [false, true, "fmodf"], +const mathIntrinsicTable: { [opcode: number]: [isUnary: boolean, isF32: boolean, opcodeOrFuncName: WasmOpcode | string] } = { + [MintOpcode.MINT_SQRT]: [true, false, WasmOpcode.f64_sqrt], + [MintOpcode.MINT_SQRTF]: [true, true, WasmOpcode.f32_sqrt], + [MintOpcode.MINT_CEILING]: [true, false, WasmOpcode.f64_ceil], + [MintOpcode.MINT_CEILINGF]: [true, true, WasmOpcode.f32_ceil], + [MintOpcode.MINT_FLOOR]: [true, false, WasmOpcode.f64_floor], + [MintOpcode.MINT_FLOORF]: [true, true, WasmOpcode.f32_floor], + [MintOpcode.MINT_ABS]: [true, false, WasmOpcode.f64_abs], + [MintOpcode.MINT_ABSF]: [true, true, WasmOpcode.f32_abs], + + [MintOpcode.MINT_ACOS]: [true, false, "acos"], + [MintOpcode.MINT_ACOSF]: [true, true, "acosf"], + [MintOpcode.MINT_ACOSH]: [true, false, "acosh"], + [MintOpcode.MINT_ACOSHF]: [true, true, "acoshf"], + [MintOpcode.MINT_COS]: [true, false, "cos"], + [MintOpcode.MINT_COSF]: [true, true, "cosf"], + [MintOpcode.MINT_ASIN]: [true, false, "asin"], + [MintOpcode.MINT_ASINF]: [true, true, "asinf"], + [MintOpcode.MINT_ASINH]: [true, false, "asinh"], + [MintOpcode.MINT_ASINHF]: [true, true, "asinhf"], + [MintOpcode.MINT_SIN]: [true, false, "sin"], + [MintOpcode.MINT_SINF]: [true, true, "sinf"], + [MintOpcode.MINT_ATAN]: [true, false, "atan"], + [MintOpcode.MINT_ATANF]: [true, true, "atanf"], + [MintOpcode.MINT_ATANH]: [true, false, "atanh"], + [MintOpcode.MINT_ATANHF]: [true, true, "atanhf"], + [MintOpcode.MINT_TAN]: [true, false, "tan"], + [MintOpcode.MINT_TANF]: [true, true, "tanf"], + [MintOpcode.MINT_CBRT]: [true, false, "cbrt"], + [MintOpcode.MINT_CBRTF]: [true, true, "cbrtf"], + [MintOpcode.MINT_EXP]: [true, false, "exp"], + [MintOpcode.MINT_EXPF]: [true, true, "expf"], + [MintOpcode.MINT_LOG]: [true, false, "log"], + [MintOpcode.MINT_LOGF]: [true, true, "logf"], + [MintOpcode.MINT_LOG2]: [true, false, "log2"], + [MintOpcode.MINT_LOG2F]: [true, true, "log2f"], + [MintOpcode.MINT_LOG10]: [true, false, "log10"], + [MintOpcode.MINT_LOG10F]: [true, true, "log10f"], + + [MintOpcode.MINT_MIN]: [false, false, WasmOpcode.f64_min], + [MintOpcode.MINT_MINF]: [false, true, WasmOpcode.f32_min], + [MintOpcode.MINT_MAX]: [false, false, WasmOpcode.f64_max], + [MintOpcode.MINT_MAXF]: [false, true, WasmOpcode.f32_max], + + [MintOpcode.MINT_ATAN2]: [false, false, "atan2"], + [MintOpcode.MINT_ATAN2F]: [false, true, "atan2f"], + [MintOpcode.MINT_POW]: [false, false, "pow"], + [MintOpcode.MINT_POWF]: [false, true, "powf"], + [MintOpcode.MINT_REM_R8]: [false, false, "fmod"], + [MintOpcode.MINT_REM_R4]: [false, true, "fmodf"], }; -function emit_math_intrinsic (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean { - let isUnary : boolean, isF32 : boolean, name: string | undefined; - let wasmOp : WasmOpcode | undefined; +function emit_math_intrinsic(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { + let isUnary: boolean, isF32: boolean, name: string | undefined; + let wasmOp: WasmOpcode | undefined; const destOffset = getArgU16(ip, 1), srcOffset = getArgU16(ip, 2), rhsOffset = getArgU16(ip, 3); @@ -2850,7 +2852,7 @@ function emit_math_intrinsic (builder: WasmBuilder, ip: MintOpcodePtr, opcode: M } } -function emit_indirectop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode) : boolean { +function emit_indirectop(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { const isLoad = (opcode >= MintOpcode.MINT_LDIND_I1) && (opcode <= MintOpcode.MINT_LDIND_OFFSET_ADD_MUL_IMM_I8); const isAddMul = ( @@ -2860,17 +2862,19 @@ function emit_indirectop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintO const isOffset = ( (opcode >= MintOpcode.MINT_LDIND_OFFSET_I1) && (opcode <= MintOpcode.MINT_LDIND_OFFSET_IMM_I8) - ) || ( - (opcode >= MintOpcode.MINT_STIND_OFFSET_I1) && - (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) - ) || isAddMul; + ) || + ( + (opcode >= MintOpcode.MINT_STIND_OFFSET_I1) && + (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) + ) || isAddMul; const isImm = ( (opcode >= MintOpcode.MINT_LDIND_OFFSET_IMM_I1) && (opcode <= MintOpcode.MINT_LDIND_OFFSET_IMM_I8) - ) || ( - (opcode >= MintOpcode.MINT_STIND_OFFSET_IMM_I1) && - (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) - ) || isAddMul; + ) || + ( + (opcode >= MintOpcode.MINT_STIND_OFFSET_IMM_I1) && + (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) + ) || isAddMul; let valueVarIndex, addressVarIndex, offsetVarIndex = -1, constantOffset = 0, constantMultiplier = 1; @@ -2910,7 +2914,7 @@ function emit_indirectop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintO valueVarIndex = getArgU16(ip, 2); } - let getter : WasmOpcode, setter = WasmOpcode.i32_store; + let getter: WasmOpcode, setter = WasmOpcode.i32_store; switch (opcode) { case MintOpcode.MINT_LDIND_I1: case MintOpcode.MINT_LDIND_OFFSET_I1: @@ -3046,7 +3050,7 @@ function emit_indirectop (builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintO return true; } -function append_getelema1 ( +function append_getelema1( builder: WasmBuilder, ip: MintOpcodePtr, objectOffset: number, indexOffset: number, elementSize: number ) { @@ -3083,11 +3087,9 @@ function append_getelema1 ( // append_getelema1 leaves the address on the stack } -function emit_arrayop (builder: WasmBuilder, frame: NativePointer, ip: MintOpcodePtr, opcode: MintOpcode) : boolean { - const isLoad = ( - (opcode <= MintOpcode.MINT_LDELEMA_TC) && - (opcode >= MintOpcode.MINT_LDELEM_I1) - ) || (opcode === MintOpcode.MINT_LDLEN), +function emit_arrayop(builder: WasmBuilder, frame: NativePointer, ip: MintOpcodePtr, opcode: MintOpcode): boolean { + const isLoad = ((opcode <= MintOpcode.MINT_LDELEMA_TC) && (opcode >= MintOpcode.MINT_LDELEM_I1)) || + (opcode === MintOpcode.MINT_LDLEN), objectOffset = getArgU16(ip, isLoad ? 2 : 1), valueOffset = getArgU16(ip, isLoad ? 1 : 3), indexOffset = getArgU16(ip, isLoad ? 3 : 2); @@ -3237,7 +3239,7 @@ function emit_arrayop (builder: WasmBuilder, frame: NativePointer, ip: MintOpcod return true; } -function append_safepoint (builder: WasmBuilder, ip: MintOpcodePtr) { +function append_safepoint(builder: WasmBuilder, ip: MintOpcodePtr) { // Check whether a safepoint is required builder.ptr_const(cwraps.mono_jiterp_get_polling_required_address()); builder.appendU8(WasmOpcode.i32_load); diff --git a/src/mono/wasm/runtime/jiterpreter.ts b/src/mono/wasm/runtime/jiterpreter.ts index 1d355272ae85c3..776c562a94c58e 100644 --- a/src/mono/wasm/runtime/jiterpreter.ts +++ b/src/mono/wasm/runtime/jiterpreter.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { mono_assert, MonoMethod } from "./types"; +import { MonoMethod } from "./types/internal"; import { NativePointer } from "./types/emscripten"; import { Module, runtimeHelpers } from "./globals"; import { @@ -326,7 +326,7 @@ function wrap_trace_function( if (!_wrap_trace_function) { // If we used a regular closure, the js console would print the entirety of - // dotnet.js when printing an error stack trace, which is... not helpful + // dotnet.native.js when printing an error stack trace, which is... not helpful const js = `return function trace_enter (locals) { let threw = true; try { diff --git a/src/mono/wasm/runtime/loader/assets.ts b/src/mono/wasm/runtime/loader/assets.ts new file mode 100644 index 00000000000000..2a1bf7432a5449 --- /dev/null +++ b/src/mono/wasm/runtime/loader/assets.ts @@ -0,0 +1,416 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import type { AssetEntryInternal, PromiseAndController } from "../types/internal"; +import type { AssetBehaviours, AssetEntry, LoadingResource, ResourceRequest } from "../types"; +import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, loaderHelpers, runtimeHelpers } from "./globals"; +import { createPromiseController } from "./promise-controller"; + + +let throttlingPromise: PromiseAndController | undefined; +// in order to prevent net::ERR_INSUFFICIENT_RESOURCES if we start downloading too many files at same time +let parallel_count = 0; + +// don't `fetch` javaScript files +const skipDownloadsByAssetTypes: { + [k: string]: boolean +} = { + "js-module-threads": true, + "js-module-runtime": true, + "js-module-native": true, + "js-module-dotnet": true, + "dotnetwasm": true, +}; + +// `response.arrayBuffer()` can't be called twice. Some usecases are calling it on response in the instantiation. +const skipBufferByAssetTypes: { + [k: string]: boolean +} = { + "dotnetwasm": true, + "symbols": true, +}; + +const containedInSnapshotByAssetTypes: { + [k: string]: boolean +} = { + "resource": true, + "assembly": true, + "pdb": true, + "heap": true, + "icu": true, + "js-module-threads": true, + "js-module-runtime": true, + "js-module-native": true, + "js-module-dotnet": true, + "dotnetwasm": true, +}; + +// these assets are instantiated differently than the main flow +const skipInstantiateByAssetTypes: { + [k: string]: boolean +} = { + "js-module-threads": true, + "js-module-runtime": true, + "js-module-native": true, + "js-module-dotnet": true, + "dotnetwasm": true, + "symbols": true, +}; + +export function shouldLoadIcuAsset(asset: AssetEntryInternal): boolean { + return !(asset.behavior == "icu" && asset.name != loaderHelpers.preferredIcuAsset); +} + +export function resolve_asset_path(behavior: AssetBehaviours): AssetEntryInternal { + const asset: AssetEntryInternal | undefined = loaderHelpers.config.assets?.find(a => a.behavior == behavior); + mono_assert(asset, () => `Can't find asset for ${behavior}`); + if (!asset.resolvedUrl) { + asset.resolvedUrl = resolve_path(asset, ""); + } + return asset; +} +export async function mono_download_assets(): Promise { + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_download_assets"); + loaderHelpers.maxParallelDownloads = loaderHelpers.config.maxParallelDownloads || loaderHelpers.maxParallelDownloads; + loaderHelpers.enableDownloadRetry = loaderHelpers.config.enableDownloadRetry || loaderHelpers.enableDownloadRetry; + try { + const alwaysLoadedAssets: AssetEntryInternal[] = []; + const containedInSnapshotAssets: AssetEntryInternal[] = []; + const promises_of_assets: Promise[] = []; + + for (const a of loaderHelpers.config.assets!) { + const asset: AssetEntryInternal = a; + mono_assert(typeof asset === "object", "asset must be object"); + mono_assert(typeof asset.behavior === "string", "asset behavior must be known string"); + mono_assert(typeof asset.name === "string", "asset name must be string"); + mono_assert(!asset.resolvedUrl || typeof asset.resolvedUrl === "string", "asset resolvedUrl could be string"); + mono_assert(!asset.hash || typeof asset.hash === "string", "asset resolvedUrl could be string"); + mono_assert(!asset.pendingDownload || typeof asset.pendingDownload === "object", "asset pendingDownload could be object"); + if (containedInSnapshotByAssetTypes[asset.behavior]) { + containedInSnapshotAssets.push(asset); + } else { + alwaysLoadedAssets.push(asset); + } + } + + const countAndStartDownload = (asset: AssetEntryInternal) => { + if (!skipInstantiateByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { + loaderHelpers.expected_instantiated_assets_count++; + } + if (!skipDownloadsByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { + loaderHelpers.expected_downloaded_assets_count++; + promises_of_assets.push(start_asset_download(asset)); + } + }; + + // start fetching assets in parallel, only assets which are not part of memory snapshot + for (const asset of alwaysLoadedAssets) { + countAndStartDownload(asset); + } + + // continue after the dotnet.runtime.js was loaded + await loaderHelpers.runtimeModuleLoaded.promise; + + // continue after we know if memory snapshot is available or not + await runtimeHelpers.memorySnapshotSkippedOrDone.promise; + + // start fetching assets in parallel, only if memory snapshot is not available. + for (const asset of containedInSnapshotAssets) { + if (!runtimeHelpers.loadedMemorySnapshot) { + countAndStartDownload(asset); + } else { + // Otherwise cleanup in case we were given pending download. It would be even better if we could abort the download. + cleanupAsset(asset); + // tell the debugger it is loaded + if (asset.behavior == "resource" || asset.behavior == "assembly" || asset.behavior == "pdb") { + const url = resolve_path(asset, ""); + const virtualName: string = typeof (asset.virtualPath) === "string" + ? asset.virtualPath + : asset.name; + loaderHelpers._loaded_files.push({ url: url, file: virtualName }); + } + } + } + + loaderHelpers.allDownloadsQueued.promise_control.resolve(); + await loaderHelpers.runtimeModuleLoaded.promise; + + const promises_of_asset_instantiation: Promise[] = []; + for (const downloadPromise of promises_of_assets) { + promises_of_asset_instantiation.push((async () => { + const asset = await downloadPromise; + if (asset.buffer) { + if (!skipInstantiateByAssetTypes[asset.behavior]) { + const url = asset.pendingDownloadInternal!.url; + mono_assert(asset.buffer && typeof asset.buffer === "object", "asset buffer must be array or buffer like"); + const data = new Uint8Array(asset.buffer!); + cleanupAsset(asset); + + // wait till after onRuntimeInitialized and after memory snapshot is loaded or skipped + + await runtimeHelpers.beforeOnRuntimeInitialized.promise; + await runtimeHelpers.memorySnapshotSkippedOrDone.promise; + runtimeHelpers.instantiate_asset(asset, url, data); + } + if (asset.behavior === "symbols") { + await runtimeHelpers.instantiate_symbols_asset(asset); + cleanupAsset(asset); + } + } else { + const headersOnly = skipBufferByAssetTypes[asset.behavior]; + if (!headersOnly) { + mono_assert(asset.isOptional, "Expected asset to have the downloaded buffer"); + if (!skipDownloadsByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { + loaderHelpers.expected_downloaded_assets_count--; + } + if (!skipInstantiateByAssetTypes[asset.behavior] && shouldLoadIcuAsset(asset)) { + loaderHelpers.expected_instantiated_assets_count--; + } + } else { + if (skipBufferByAssetTypes[asset.behavior]) { + ++loaderHelpers.actual_downloaded_assets_count; + } + } + } + })()); + } + + // this await will get past the onRuntimeInitialized because we are not blocking via addRunDependency + // and we are not awating it here + Promise.all(promises_of_asset_instantiation).then(() => { + runtimeHelpers.allAssetsInMemory.promise_control.resolve(); + }).catch(e => { + loaderHelpers.err("MONO_WASM: Error in mono_download_assets: " + e); + loaderHelpers.abort_startup(e, true); + }); + // OPTIMIZATION explained: + // we do it this way so that we could allocate memory immediately after asset is downloaded (and after onRuntimeInitialized which happened already) + // spreading in time + // rather than to block all downloads after onRuntimeInitialized or block onRuntimeInitialized after all downloads are done. That would create allocation burst. + } catch (e: any) { + loaderHelpers.err("MONO_WASM: Error in mono_download_assets: " + e); + throw e; + } +} + +export function delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +// FIXME: Connection reset is probably the only good one for which we should retry +export async function start_asset_download(asset: AssetEntryInternal): Promise { + try { + return await start_asset_download_with_throttle(asset); + } catch (err: any) { + if (!loaderHelpers.enableDownloadRetry) { + // we will not re-try if disabled + throw err; + } + if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { + // we will not re-try on shell + throw err; + } + if (asset.pendingDownload && asset.pendingDownloadInternal == asset.pendingDownload) { + // we will not re-try with external source + throw err; + } + if (asset.resolvedUrl && asset.resolvedUrl.indexOf("file://") != -1) { + // we will not re-try with local file + throw err; + } + if (err && err.status == 404) { + // we will not re-try with 404 + throw err; + } + asset.pendingDownloadInternal = undefined; + // second attempt only after all first attempts are queued + await loaderHelpers.allDownloadsQueued.promise; + try { + return await start_asset_download_with_throttle(asset); + } catch (err) { + asset.pendingDownloadInternal = undefined; + // third attempt after small delay + await delay(100); + return await start_asset_download_with_throttle(asset); + } + } +} + +async function start_asset_download_with_throttle(asset: AssetEntryInternal): Promise { + // we don't addRunDependency to allow download in parallel with onRuntimeInitialized event! + while (throttlingPromise) { + await throttlingPromise.promise; + } + try { + ++parallel_count; + if (parallel_count == loaderHelpers.maxParallelDownloads) { + if (loaderHelpers.diagnosticTracing) + console.debug("MONO_WASM: Throttling further parallel downloads"); + throttlingPromise = createPromiseController(); + } + + const response = await start_asset_download_sources(asset); + if (!response) { + return asset; + } + const skipBuffer = skipBufferByAssetTypes[asset.behavior]; + if (skipBuffer) { + return asset; + } + asset.buffer = await response.arrayBuffer(); + ++loaderHelpers.actual_downloaded_assets_count; + return asset; + } + finally { + --parallel_count; + if (throttlingPromise && parallel_count == loaderHelpers.maxParallelDownloads - 1) { + if (loaderHelpers.diagnosticTracing) + console.debug("MONO_WASM: Resuming more parallel downloads"); + const old_throttling = throttlingPromise; + throttlingPromise = undefined; + old_throttling.promise_control.resolve(); + } + } +} + +async function start_asset_download_sources(asset: AssetEntryInternal): Promise { + // we don't addRunDependency to allow download in parallel with onRuntimeInitialized event! + if (asset.pendingDownload) { + asset.pendingDownloadInternal = asset.pendingDownload; + } + if (asset.pendingDownloadInternal && asset.pendingDownloadInternal.response) { + return asset.pendingDownloadInternal.response; + } + if (asset.buffer) { + const buffer = asset.buffer; + asset.buffer = null as any; // GC + asset.pendingDownloadInternal = { + url: "undefined://" + asset.name, + name: asset.name, + response: Promise.resolve({ + arrayBuffer: () => buffer, + headers: { + get: () => undefined, + } + }) as any + }; + return asset.pendingDownloadInternal.response; + } + + const sourcesList = asset.loadRemote && loaderHelpers.config.remoteSources ? loaderHelpers.config.remoteSources : [""]; + let response: Response | undefined = undefined; + for (let sourcePrefix of sourcesList) { + sourcePrefix = sourcePrefix.trim(); + // HACK: Special-case because MSBuild doesn't allow "" as an attribute + if (sourcePrefix === "./") + sourcePrefix = ""; + + const attemptUrl = resolve_path(asset, sourcePrefix); + if (asset.name === attemptUrl) { + if (loaderHelpers.diagnosticTracing) + console.debug(`MONO_WASM: Attempting to download '${attemptUrl}'`); + } else { + if (loaderHelpers.diagnosticTracing) + console.debug(`MONO_WASM: Attempting to download '${attemptUrl}' for ${asset.name}`); + } + try { + asset.resolvedUrl = attemptUrl; + const loadingResource = download_resource(asset); + asset.pendingDownloadInternal = loadingResource; + response = await loadingResource.response; + if (!response || !response.ok) { + continue;// next source + } + return response; + } + catch (err) { + if (!response) { + response = { + ok: false, + url: attemptUrl, + status: 0, + statusText: "" + err, + } as any; + } + continue; //next source + } + } + const isOkToFail = asset.isOptional || (asset.name.match(/\.pdb$/) && loaderHelpers.config.ignorePdbLoadErrors); + mono_assert(response, () => `Response undefined ${asset.name}`); + if (!isOkToFail) { + const err: any = new Error(`MONO_WASM: download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`); + err.status = response.status; + throw err; + } else { + loaderHelpers.out(`MONO_WASM: optional download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`); + return undefined; + } +} + +function resolve_path(asset: AssetEntry, sourcePrefix: string): string { + mono_assert(sourcePrefix !== null && sourcePrefix !== undefined, () => `sourcePrefix must be provided for ${asset.name}`); + let attemptUrl; + const assemblyRootFolder = loaderHelpers.config.assemblyRootFolder; + if (!asset.resolvedUrl) { + if (sourcePrefix === "") { + if (asset.behavior === "assembly" || asset.behavior === "pdb") { + attemptUrl = assemblyRootFolder + ? (assemblyRootFolder + "/" + asset.name) + : asset.name; + } + else if (asset.behavior === "resource") { + const path = asset.culture && asset.culture !== "" ? `${asset.culture}/${asset.name}` : asset.name; + attemptUrl = assemblyRootFolder + ? (assemblyRootFolder + "/" + path) + : path; + } + else { + attemptUrl = asset.name; + } + } else { + attemptUrl = sourcePrefix + asset.name; + } + attemptUrl = loaderHelpers.locateFile(attemptUrl); + } + else { + attemptUrl = asset.resolvedUrl; + } + mono_assert(attemptUrl && typeof attemptUrl == "string", "attemptUrl need to be path or url string"); + return attemptUrl; +} + +function download_resource(request: ResourceRequest): LoadingResource { + try { + if (typeof loaderHelpers.downloadResource === "function") { + const loading = loaderHelpers.downloadResource(request); + if (loading) return loading; + } + const options: any = {}; + if (request.hash) { + options.integrity = request.hash; + } + const response = loaderHelpers.fetch_like(request.resolvedUrl!, options); + return { + name: request.name, url: request.resolvedUrl!, response + }; + } catch (err) { + const response = { + ok: false, + url: request.resolvedUrl, + status: 500, + statusText: "ERR29: " + err, + arrayBuffer: () => { throw err; }, + json: () => { throw err; } + }; + return { + name: request.name, url: request.resolvedUrl!, response: Promise.resolve(response) + }; + } +} + +export function cleanupAsset(asset: AssetEntryInternal) { + // give GC chance to collect resources + asset.pendingDownloadInternal = null as any; // GC + asset.pendingDownload = null as any; // GC + asset.buffer = null as any; // GC +} \ No newline at end of file diff --git a/src/mono/wasm/runtime/blazor/BootConfig.ts b/src/mono/wasm/runtime/loader/blazor/BootConfig.ts similarity index 50% rename from src/mono/wasm/runtime/blazor/BootConfig.ts rename to src/mono/wasm/runtime/loader/blazor/BootConfig.ts index 48c033b7368b38..d136a18b7b99a8 100644 --- a/src/mono/wasm/runtime/blazor/BootConfig.ts +++ b/src/mono/wasm/runtime/loader/blazor/BootConfig.ts @@ -1,8 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { Module } from "../globals"; -import { WebAssemblyBootResourceType } from "../types-api"; +import type { BootJsonData } from "../../types/blazor"; +import type { WebAssemblyBootResourceType } from "../../types"; +import { loaderHelpers } from "../globals"; type LoadBootResourceCallback = (type: WebAssemblyBootResourceType, name: string, defaultUri: string, integrity: string) => string | Promise | null | undefined; @@ -25,7 +26,7 @@ export class BootConfigResult { bootConfigResponse = await loaderResponse; } - const applicationEnvironment = environment || (Module.getApplicationEnvironment && Module.getApplicationEnvironment(bootConfigResponse)) || "Production"; + const applicationEnvironment = environment || (loaderHelpers.getApplicationEnvironment && loaderHelpers.getApplicationEnvironment(bootConfigResponse)) || "Production"; const bootConfig: BootJsonData = await bootConfigResponse.json(); bootConfig.modifiableAssemblies = bootConfigResponse.headers.get("DOTNET-MODIFIABLE-ASSEMBLIES"); bootConfig.aspnetCoreBrowserTools = bootConfigResponse.headers.get("ASPNETCORE-BROWSER-TOOLS"); @@ -42,48 +43,3 @@ export class BootConfigResult { } } -// Keep in sync with Microsoft.NET.Sdk.WebAssembly.BootJsonData from the WasmSDK -export interface BootJsonData { - readonly entryAssembly: string; - readonly resources: ResourceGroups; - /** Gets a value that determines if this boot config was produced from a non-published build (i.e. dotnet build or dotnet run) */ - readonly debugBuild: boolean; - readonly linkerEnabled: boolean; - readonly cacheBootResources: boolean; - readonly config: string[]; - readonly icuDataMode: ICUDataMode; - readonly startupMemoryCache: boolean | undefined; - readonly runtimeOptions: string[] | undefined; - - // These properties are tacked on, and not found in the boot.json file - modifiableAssemblies: string | null; - aspnetCoreBrowserTools: string | null; -} - -export type BootJsonDataExtension = { [extensionName: string]: ResourceList }; - -export interface ResourceGroups { - readonly assembly: ResourceList; - readonly lazyAssembly: ResourceList; - readonly pdb?: ResourceList; - readonly runtime: ResourceList; - readonly satelliteResources?: { [cultureName: string]: ResourceList }; - readonly libraryInitializers?: ResourceList, - readonly extensions?: BootJsonDataExtension - readonly runtimeAssets: ExtendedResourceList; -} - -export type ResourceList = { [name: string]: string }; -export type ExtendedResourceList = { - [name: string]: { - hash: string, - behavior: string - } -}; - -export enum ICUDataMode { - Sharded, - All, - Invariant, - Custom -} diff --git a/src/mono/wasm/runtime/blazor/WebAssemblyResourceLoader.ts b/src/mono/wasm/runtime/loader/blazor/WebAssemblyResourceLoader.ts similarity index 98% rename from src/mono/wasm/runtime/blazor/WebAssemblyResourceLoader.ts rename to src/mono/wasm/runtime/loader/blazor/WebAssemblyResourceLoader.ts index c0840f6edb1ad9..8af4dba109e0d6 100644 --- a/src/mono/wasm/runtime/blazor/WebAssemblyResourceLoader.ts +++ b/src/mono/wasm/runtime/loader/blazor/WebAssemblyResourceLoader.ts @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { WebAssemblyBootResourceType, WebAssemblyStartOptions } from "../types-api"; +import type { WebAssemblyBootResourceType, WebAssemblyStartOptions } from "../../types"; +import type { BootJsonData, ResourceList } from "../../types/blazor"; import { toAbsoluteUri } from "./_Polyfill"; -import { BootJsonData, ResourceList } from "./BootConfig"; const networkFetchCacheMode = "no-cache"; export class WebAssemblyResourceLoader { diff --git a/src/mono/wasm/runtime/blazor/_Integration.ts b/src/mono/wasm/runtime/loader/blazor/_Integration.ts similarity index 75% rename from src/mono/wasm/runtime/blazor/_Integration.ts rename to src/mono/wasm/runtime/loader/blazor/_Integration.ts index 64896bfaa013c8..88203e1b2aa593 100644 --- a/src/mono/wasm/runtime/blazor/_Integration.ts +++ b/src/mono/wasm/runtime/loader/blazor/_Integration.ts @@ -1,29 +1,79 @@ -import { INTERNAL, Module } from "../globals"; -import { MonoConfigInternal } from "../types"; -import { AssetEntry, LoadingResource, WebAssemblyBootResourceType } from "../types-api"; -import { BootConfigResult, BootJsonData, ICUDataMode } from "./BootConfig"; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import type { DotnetModuleInternal, MonoConfigInternal } from "../../types/internal"; +import type { AssetBehaviours, AssetEntry, LoadingResource, WebAssemblyBootResourceType } from "../../types"; +import type { BootJsonData } from "../../types/blazor"; + +import { INTERNAL, loaderHelpers } from "../globals"; +import { BootConfigResult } from "./BootConfig"; import { WebAssemblyResourceLoader } from "./WebAssemblyResourceLoader"; import { hasDebuggingEnabled } from "./_Polyfill"; +import { ICUDataMode } from "../../types/blazor"; -export async function loadBootConfig(config: MonoConfigInternal,) { +let resourceLoader: WebAssemblyResourceLoader; + +export async function loadBootConfig(config: MonoConfigInternal, module: DotnetModuleInternal) { const candidateOptions = config.startupOptions ?? {}; const environment = candidateOptions.environment; const bootConfigPromise = BootConfigResult.initAsync(candidateOptions.loadBootResource, environment); - const bootConfigResult: BootConfigResult = await bootConfigPromise; - - const resourceLoader = await WebAssemblyResourceLoader.initAsync(bootConfigResult.bootConfig, candidateOptions || {}); - - INTERNAL.resourceLoader = resourceLoader; - - const newConfig = mapBootConfigToMonoConfig(Module.config as MonoConfigInternal, resourceLoader, bootConfigResult.applicationEnvironment); - Module.config = newConfig; + INTERNAL.resourceLoader = resourceLoader = await WebAssemblyResourceLoader.initAsync(bootConfigResult.bootConfig, candidateOptions || {}); + mapBootConfigToMonoConfig(loaderHelpers.config, bootConfigResult.applicationEnvironment); + setupModuleForBlazor(module); } let resourcesLoaded = 0; let totalResources = 0; -export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, resourceLoader: WebAssemblyResourceLoader, applicationEnvironment: string): MonoConfigInternal { +const behaviorByName = (name: string): AssetBehaviours | "other" => { + return name === "dotnet.timezones.blat" ? "vfs" + : name === "dotnet.native.wasm" ? "dotnetwasm" + : (name.startsWith("dotnet.native.worker") && name.endsWith(".js")) ? "js-module-threads" + : (name.startsWith("dotnet.native") && name.endsWith(".js")) ? "js-module-native" + : (name.startsWith("dotnet.runtime") && name.endsWith(".js")) ? "js-module-runtime" + : (name.startsWith("dotnet") && name.endsWith(".js")) ? "js-module-dotnet" + : name.startsWith("icudt") ? "icu" + : "other"; +}; + +const monoToBlazorAssetTypeMap: { [key: string]: WebAssemblyBootResourceType | undefined } = { + "assembly": "assembly", + "pdb": "pdb", + "icu": "globalization", + "vfs": "globalization", + "dotnetwasm": "dotnetwasm", +}; + +export function setupModuleForBlazor(module: DotnetModuleInternal) { + // it would not `loadResource` on types for which there is no typesMap mapping + const downloadResource = (asset: AssetEntry): LoadingResource | undefined => { + // GOTCHA: the mapping to blazor asset type may not cover all mono owned asset types in the future in which case: + // A) we may need to add such asset types to the mapping and to WebAssemblyBootResourceType + // B) or we could add generic "runtime" type to WebAssemblyBootResourceType as fallback + // C) or we could return `undefined` and let the runtime to load the asset. In which case the progress will not be reported on it and blazor will not be able to cache it. + const type = monoToBlazorAssetTypeMap[asset.behavior]; + if (type !== undefined) { + const res = resourceLoader.loadResource(asset.name, asset.resolvedUrl!, asset.hash!, type); + asset.pendingDownload = res; + + totalResources++; + res.response.then(() => { + resourcesLoaded++; + if (module.onDownloadResourceProgress) + module.onDownloadResourceProgress(resourcesLoaded, totalResources); + }); + + return res; + } + return undefined; + }; + + module.downloadResource = downloadResource; + module.disableDotnet6Compatibility = false; +} + +export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, applicationEnvironment: string) { const resources = resourceLoader.bootConfig.resources; const assets: AssetEntry[] = []; @@ -52,58 +102,12 @@ export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, reso moduleConfig.runtimeOptions = [...(moduleConfig.runtimeOptions || []), ...resourceLoader.bootConfig.runtimeOptions]; } - const monoToBlazorAssetTypeMap: { [key: string]: WebAssemblyBootResourceType | undefined } = { - "assembly": "assembly", - "pdb": "pdb", - "icu": "globalization", - "vfs": "globalization", - "dotnetwasm": "dotnetwasm", - }; - - const behaviorByName = (name: string) => { - return name === "dotnet.timezones.blat" ? "vfs" - : name === "dotnet.wasm" ? "dotnetwasm" - : (name.startsWith("dotnet.worker") && name.endsWith(".js")) ? "js-module-threads" - : (name.startsWith("dotnet") && name.endsWith(".js")) ? "js-module-dotnet" - : name.startsWith("icudt") ? "icu" - : "other"; - }; - - // it would not `loadResource` on types for which there is no typesMap mapping - const downloadResource = (asset: AssetEntry): LoadingResource | undefined => { - // GOTCHA: the mapping to blazor asset type may not cover all mono owned asset types in the future in which case: - // A) we may need to add such asset types to the mapping and to WebAssemblyBootResourceType - // B) or we could add generic "runtime" type to WebAssemblyBootResourceType as fallback - // C) or we could return `undefined` and let the runtime to load the asset. In which case the progress will not be reported on it and blazor will not be able to cache it. - const type = monoToBlazorAssetTypeMap[asset.behavior]; - if (type !== undefined) { - const res = resourceLoader.loadResource(asset.name, asset.resolvedUrl!, asset.hash!, type); - asset.pendingDownload = res; - - totalResources++; - res.response.then(() => { - resourcesLoaded++; - if (Module.onDownloadResourceProgress) - Module.onDownloadResourceProgress(resourcesLoaded, totalResources); - }); - - return res; - } - return undefined; - }; - - Module.downloadResource = downloadResource; - Module.disableDotnet6Compatibility = false; - // any runtime owned assets, with proper behavior already set for (const name in resources.runtimeAssets) { const asset = resources.runtimeAssets[name] as AssetEntry; asset.name = name; asset.resolvedUrl = `_framework/${name}`; assets.push(asset); - if (asset.behavior === "dotnetwasm") { - downloadResource(asset); - } } for (const name in resources.assembly) { const asset: AssetEntry = { @@ -113,7 +117,6 @@ export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, reso behavior: "assembly", }; assets.push(asset); - downloadResource(asset); } if (hasDebuggingEnabled(resourceLoader.bootConfig) && resources.pdb) { for (const name in resources.pdb) { @@ -124,7 +127,6 @@ export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, reso behavior: "pdb", }; assets.push(asset); - downloadResource(asset); } } const applicationCulture = resourceLoader.startOptions.applicationCulture || (navigator.languages && navigator.languages[0]); @@ -175,8 +177,6 @@ export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, reso if (resourceLoader.bootConfig.runtimeOptions) { moduleConfig.runtimeOptions = [...(moduleConfig.runtimeOptions || []), ...(resourceLoader.bootConfig.runtimeOptions || [])]; } - - return moduleConfig; } function getICUResourceName(bootConfig: BootJsonData, culture: string | undefined): string { @@ -217,4 +217,5 @@ function getICUResourceName(bootConfig: BootJsonData, culture: string | undefine return "icudt_CJK.dat"; } return "icudt_no_CJK.dat"; -} \ No newline at end of file +} + diff --git a/src/mono/wasm/runtime/blazor/_Polyfill.ts b/src/mono/wasm/runtime/loader/blazor/_Polyfill.ts similarity index 87% rename from src/mono/wasm/runtime/blazor/_Polyfill.ts rename to src/mono/wasm/runtime/loader/blazor/_Polyfill.ts index dc4aded75cc921..4eeefe2060dd91 100644 --- a/src/mono/wasm/runtime/blazor/_Polyfill.ts +++ b/src/mono/wasm/runtime/loader/blazor/_Polyfill.ts @@ -1,4 +1,7 @@ -import { BootJsonData } from "./BootConfig"; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import type { BootJsonData } from "../../types/blazor"; let testAnchor: HTMLAnchorElement; export function toAbsoluteUri(relativeUri: string): string { diff --git a/src/mono/wasm/runtime/loader/config.ts b/src/mono/wasm/runtime/loader/config.ts new file mode 100644 index 00000000000000..1c460f74ded091 --- /dev/null +++ b/src/mono/wasm/runtime/loader/config.ts @@ -0,0 +1,110 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import BuildConfiguration from "consts:configuration"; +import type { DotnetModuleInternal, MonoConfigInternal } from "../types/internal"; +import type { DotnetModuleConfig } from "../types"; +import { exportedRuntimeAPI, loaderHelpers, runtimeHelpers } from "./globals"; +import { loadBootConfig } from "./blazor/_Integration"; + +export function deep_merge_config(target: MonoConfigInternal, source: MonoConfigInternal): MonoConfigInternal { + const providedConfig: MonoConfigInternal = { ...source }; + if (providedConfig.assets) { + providedConfig.assets = [...(target.assets || []), ...(providedConfig.assets || [])]; + } + if (providedConfig.environmentVariables) { + providedConfig.environmentVariables = { ...(target.environmentVariables || {}), ...(providedConfig.environmentVariables || {}) }; + } + if (providedConfig.startupOptions) { + providedConfig.startupOptions = { ...(target.startupOptions || {}), ...(providedConfig.startupOptions || {}) }; + } + if (providedConfig.runtimeOptions) { + providedConfig.runtimeOptions = [...(target.runtimeOptions || []), ...(providedConfig.runtimeOptions || [])]; + } + return Object.assign(target, providedConfig); +} + +export function deep_merge_module(target: DotnetModuleInternal, source: DotnetModuleConfig): DotnetModuleInternal { + const providedConfig: DotnetModuleConfig = { ...source }; + if (providedConfig.config) { + if (!target.config) target.config = {}; + providedConfig.config = deep_merge_config(target.config, providedConfig.config); + } + return Object.assign(target, providedConfig); +} + +export function normalizeConfig() { + // normalize + const config = loaderHelpers.config; + + config.environmentVariables = config.environmentVariables || {}; + config.assets = config.assets || []; + config.runtimeOptions = config.runtimeOptions || []; + config.globalizationMode = config.globalizationMode || "auto"; + + if (config.debugLevel === undefined && BuildConfiguration === "Debug") { + config.debugLevel = -1; + } + if (config.diagnosticTracing === undefined && BuildConfiguration === "Debug") { + config.diagnosticTracing = true; + } + loaderHelpers.diagnosticTracing = !!config.diagnosticTracing; + runtimeHelpers.waitForDebugger = config.waitForDebugger; + config.startupMemoryCache = !!config.startupMemoryCache; + if (config.startupMemoryCache && runtimeHelpers.waitForDebugger) { + if (loaderHelpers.diagnosticTracing) console.info("MONO_WASM: Disabling startupMemoryCache because waitForDebugger is set"); + config.startupMemoryCache = false; + } + + runtimeHelpers.enablePerfMeasure = !!config.browserProfilerOptions + && globalThis.performance + && typeof globalThis.performance.measure === "function"; + +} + +let configLoaded = false; +export async function mono_wasm_load_config(module: DotnetModuleInternal): Promise { + const configFilePath = module.configSrc; + if (configLoaded) { + await loaderHelpers.afterConfigLoaded.promise; + return; + } + configLoaded = true; + if (!configFilePath) { + normalizeConfig(); + loaderHelpers.afterConfigLoaded.promise_control.resolve(loaderHelpers.config); + return; + } + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_load_config"); + try { + const resolveSrc = loaderHelpers.locateFile(configFilePath); + const configResponse = await loaderHelpers.fetch_like(resolveSrc); + const loadedConfig: MonoConfigInternal = (await configResponse.json()) || {}; + if (loaderHelpers.config.startupOptions) { + await loadBootConfig(loaderHelpers.config, module); + } else { + if (loadedConfig.environmentVariables && typeof (loadedConfig.environmentVariables) !== "object") + throw new Error("Expected config.environmentVariables to be unset or a dictionary-style object"); + deep_merge_config(loaderHelpers.config, loadedConfig); + } + + normalizeConfig(); + + if (module.onConfigLoaded) { + try { + await module.onConfigLoaded(loaderHelpers.config, exportedRuntimeAPI); + normalizeConfig(); + } + catch (err: any) { + console.error("MONO_WASM: onConfigLoaded() failed", err); + throw err; + } + } + loaderHelpers.afterConfigLoaded.promise_control.resolve(loaderHelpers.config); + } catch (err) { + const errMessage = `Failed to load config file ${configFilePath} ${err}`; + loaderHelpers.config = module.config = { message: errMessage, error: err, isError: true }; + loaderHelpers.abort_startup(errMessage, true); + throw err; + } +} \ No newline at end of file diff --git a/src/mono/wasm/runtime/loader/exit.ts b/src/mono/wasm/runtime/loader/exit.ts new file mode 100644 index 00000000000000..ff3b62b436a907 --- /dev/null +++ b/src/mono/wasm/runtime/loader/exit.ts @@ -0,0 +1,154 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, ENVIRONMENT_IS_WEB, INTERNAL, loaderHelpers, runtimeHelpers } from "./globals"; +import { consoleWebSocket } from "./logging"; + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export function abort_startup(reason: any, should_exit: boolean): void { + if (loaderHelpers.diagnosticTracing) console.trace("MONO_WASM: abort_startup"); + loaderHelpers.allDownloadsQueued.promise_control.reject(reason); + loaderHelpers.afterConfigLoaded.promise_control.reject(reason); + loaderHelpers.wasmDownloadPromise.promise_control.reject(reason); + loaderHelpers.runtimeModuleLoaded.promise_control.reject(reason); + if (runtimeHelpers.dotnetReady) { + runtimeHelpers.dotnetReady.promise_control.reject(reason); + runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.reject(reason); + runtimeHelpers.afterInstantiateWasm.promise_control.reject(reason); + runtimeHelpers.beforePreInit.promise_control.reject(reason); + runtimeHelpers.afterPreInit.promise_control.reject(reason); + runtimeHelpers.afterPreRun.promise_control.reject(reason); + runtimeHelpers.beforeOnRuntimeInitialized.promise_control.reject(reason); + runtimeHelpers.afterOnRuntimeInitialized.promise_control.reject(reason); + runtimeHelpers.afterPostRun.promise_control.reject(reason); + } + if (typeof reason !== "object" || reason.silent !== true) { + if (should_exit || ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { + mono_exit(1, reason); + } + throw reason; + } +} + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +export function mono_exit(exit_code: number, reason?: any): void { + if (loaderHelpers.config && loaderHelpers.config.asyncFlushOnExit && exit_code === 0) { + // this would NOT call Node's exit() immediately, it's a hanging promise + (async () => { + try { + await flush_node_streams(); + } + finally { + set_exit_code_and_quit_now(exit_code, reason); + } + })(); + // we need to throw, rather than let the caller continue the normal execution + // in the middle of some code, which expects this to stop the process + throw runtimeHelpers.ExitStatus + ? new runtimeHelpers.ExitStatus(exit_code) + : reason + ? reason + : new Error("Stop with exit code " + exit_code); + } else { + set_exit_code_and_quit_now(exit_code, reason); + } +} + +async function flush_node_streams() { + try { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore: + const process = await import(/* webpackIgnore: true */"process"); + const flushStream = (stream: any) => { + return new Promise((resolve, reject) => { + stream.on("error", (error: any) => reject(error)); + stream.write("", function () { resolve(); }); + }); + }; + const stderrFlushed = flushStream(process.stderr); + const stdoutFlushed = flushStream(process.stdout); + await Promise.all([stdoutFlushed, stderrFlushed]); + } catch (err) { + console.error(`flushing std* streams failed: ${err}`); + } +} + +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types +function set_exit_code_and_quit_now(exit_code: number, reason?: any): void { + if (runtimeHelpers.ExitStatus) { + if (reason && !(reason instanceof runtimeHelpers.ExitStatus)) { + if (!loaderHelpers.config.logExitCode) { + if (reason instanceof Error && runtimeHelpers.stringify_as_error_with_stack) + loaderHelpers.err(runtimeHelpers.stringify_as_error_with_stack(reason)); + else if (typeof reason == "string") + loaderHelpers.err(reason); + else + loaderHelpers.err(JSON.stringify(reason)); + } + } + else if (!reason) { + reason = new runtimeHelpers.ExitStatus(exit_code); + } else if (typeof reason.status === "number") { + exit_code = reason.status; + } + } + logErrorOnExit(exit_code, reason); + try { + if (runtimeHelpers.jiterpreter_dump_stats) runtimeHelpers.jiterpreter_dump_stats(false); + } catch { + // eslint-disable-next-line @typescript-eslint/no-extra-semi + ; + } + + appendElementOnExit(exit_code); + if (exit_code !== 0 || !ENVIRONMENT_IS_WEB) { + if (ENVIRONMENT_IS_NODE && INTERNAL.process) { + INTERNAL.process.exit(exit_code); + throw reason; + } + else if (runtimeHelpers.quit) { + runtimeHelpers.quit(exit_code, reason); + } else { + throw reason; + } + } +} + +function appendElementOnExit(exit_code: number) { + if (ENVIRONMENT_IS_WEB && loaderHelpers.config && loaderHelpers.config.appendElementOnExit) { + //Tell xharness WasmBrowserTestRunner what was the exit code + const tests_done_elem = document.createElement("label"); + tests_done_elem.id = "tests_done"; + if (exit_code) tests_done_elem.style.background = "red"; + tests_done_elem.innerHTML = exit_code.toString(); + document.body.appendChild(tests_done_elem); + } +} + +function logErrorOnExit(exit_code: number, reason?: any) { + if (loaderHelpers.config && loaderHelpers.config.logExitCode) { + if (exit_code != 0 && reason) { + if (reason instanceof Error && runtimeHelpers.stringify_as_error_with_stack) + console.error(runtimeHelpers.stringify_as_error_with_stack(reason)); + else if (typeof reason == "string") + console.error(reason); + else + console.error(JSON.stringify(reason)); + } + if (consoleWebSocket) { + const stop_when_ws_buffer_empty = () => { + if (consoleWebSocket.bufferedAmount == 0) { + // tell xharness WasmTestMessagesProcessor we are done. + // note this sends last few bytes into the same WS + console.log("WASM EXIT " + exit_code); + } + else { + setTimeout(stop_when_ws_buffer_empty, 100); + } + }; + stop_when_ws_buffer_empty(); + } else { + console.log("WASM EXIT " + exit_code); + } + } +} diff --git a/src/mono/wasm/runtime/loader/globals.ts b/src/mono/wasm/runtime/loader/globals.ts new file mode 100644 index 00000000000000..f4f34cbf1140ed --- /dev/null +++ b/src/mono/wasm/runtime/loader/globals.ts @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import type { AssetEntryInternal, GlobalObjects, LoaderHelpers, RuntimeHelpers } from "../types/internal"; +import type { MonoConfig, RuntimeAPI } from "../types"; +import { abort_startup, mono_exit } from "./exit"; +import { assertIsControllablePromise, createPromiseController, getPromiseController } from "./promise-controller"; +import { mono_download_assets, resolve_asset_path } from "./assets"; +import { setup_proxy_console } from "./logging"; + +export const ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string"; +export const ENVIRONMENT_IS_WEB = typeof window == "object"; +export const ENVIRONMENT_IS_WORKER = typeof importScripts == "function"; +export const ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; + +export let runtimeHelpers: RuntimeHelpers = null as any; +export let loaderHelpers: LoaderHelpers = null as any; +export let exportedRuntimeAPI: RuntimeAPI = null as any; +export let INTERNAL: any; + +export function setGlobalObjects( + globalObjects: GlobalObjects, +) { + runtimeHelpers = globalObjects.runtimeHelpers; + loaderHelpers = globalObjects.loaderHelpers; + exportedRuntimeAPI = globalObjects.api; + INTERNAL = globalObjects.internal; + + Object.assign(globalObjects.module, { + disableDotnet6Compatibility: true, + config: { environmentVariables: {} } + }); + Object.assign(loaderHelpers, { + config: globalObjects.module.config, + diagnosticTracing: false, + + maxParallelDownloads: 16, + enableDownloadRetry: true, + + _loaded_files: [], + loadedFiles: [], + actual_downloaded_assets_count: 0, + actual_instantiated_assets_count: 0, + expected_downloaded_assets_count: 0, + expected_instantiated_assets_count: 0, + + afterConfigLoaded: createPromiseController(), + allDownloadsQueued: createPromiseController(), + wasmDownloadPromise: createPromiseController(), + runtimeModuleLoaded: createPromiseController(), + + abort_startup, + mono_exit, + createPromiseController, + getPromiseController, + assertIsControllablePromise, + mono_download_assets, + resolve_asset_path, + setup_proxy_console, + + } as Partial); +} diff --git a/src/mono/wasm/runtime/loader/icu.ts b/src/mono/wasm/runtime/loader/icu.ts new file mode 100644 index 00000000000000..39e2bccd14b297 --- /dev/null +++ b/src/mono/wasm/runtime/loader/icu.ts @@ -0,0 +1,71 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import { ENVIRONMENT_IS_WEB, loaderHelpers } from "./globals"; + +export function init_globalization() { + loaderHelpers.invariantMode = loaderHelpers.config.globalizationMode === "invariant"; + loaderHelpers.preferredIcuAsset = get_preferred_icu_asset(); + + if (!loaderHelpers.invariantMode) { + if (loaderHelpers.preferredIcuAsset) { + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: ICU data archive(s) available, disabling invariant mode"); + } else if (loaderHelpers.config.globalizationMode !== "icu") { + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: ICU data archive(s) not available, using invariant globalization mode"); + loaderHelpers.invariantMode = true; + loaderHelpers.preferredIcuAsset = null; + } else { + const msg = "invariant globalization mode is inactive and no ICU data archives are available"; + loaderHelpers.err(`MONO_WASM: ERROR: ${msg}`); + throw new Error(msg); + } + } + + const invariantEnv = "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT"; + const hybridEnv = "DOTNET_SYSTEM_GLOBALIZATION_HYBRID"; + const env_variables = loaderHelpers.config.environmentVariables!; + if (env_variables[hybridEnv] === undefined && loaderHelpers.config.globalizationMode === "hybrid") { + env_variables[hybridEnv] = "1"; + } + else if (env_variables[invariantEnv] === undefined && loaderHelpers.invariantMode) { + env_variables[invariantEnv] = "1"; + } + if (env_variables["TZ"] === undefined) { + try { + // this call is relatively expensive, so we call it during download of other assets + const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || null; + if (timezone) { + env_variables!["TZ"] = timezone; + } + } catch { + console.info("MONO_WASM: failed to detect timezone, will fallback to UTC"); + } + } +} + +export function get_preferred_icu_asset(): string | null { + if (!loaderHelpers.config.assets || loaderHelpers.invariantMode) + return null; + + // By setting user can define what ICU source file they want to load. + // There is no need to check application's culture when is set. + // If it was not set, then we have 3 "icu" assets in config and we should choose + // only one for loading, the one that matches the application's locale. + const icuAssets = loaderHelpers.config.assets.filter(a => a["behavior"] == "icu"); + if (icuAssets.length === 1) + return icuAssets[0].name; + + // reads the browsers locale / the OS's locale + const preferredCulture = ENVIRONMENT_IS_WEB ? navigator.language : Intl.DateTimeFormat().resolvedOptions().locale; + const prefix = preferredCulture.split("-")[0]; + const CJK = "icudt_CJK.dat"; + const EFIGS = "icudt_EFIGS.dat"; + const OTHERS = "icudt_no_CJK.dat"; + + // not all "fr-*", "it-*", "de-*", "es-*" are in EFIGS, only the one that is mostly used + if (prefix == "en" || ["fr", "fr-FR", "it", "it-IT", "de", "de-DE", "es", "es-ES"].includes(preferredCulture)) + return EFIGS; + if (["zh", "ko", "ja"].includes(prefix)) + return CJK; + return OTHERS; +} diff --git a/src/mono/wasm/runtime/loader/index.ts b/src/mono/wasm/runtime/loader/index.ts new file mode 100644 index 00000000000000..9c2f0d00f181c1 --- /dev/null +++ b/src/mono/wasm/runtime/loader/index.ts @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import type { DotnetHostBuilder } from "../types"; +import { mono_exit } from "./exit"; +import { HostBuilder, createEmscripten } from "./run"; + +// export external API +const dotnet: DotnetHostBuilder = new HostBuilder(); +const exit = mono_exit; +const legacyEntrypoint = createEmscripten; + +export { dotnet, exit }; +export default legacyEntrypoint; diff --git a/src/mono/wasm/runtime/loader/logging.ts b/src/mono/wasm/runtime/loader/logging.ts new file mode 100644 index 00000000000000..7be1ec67bd0223 --- /dev/null +++ b/src/mono/wasm/runtime/loader/logging.ts @@ -0,0 +1,88 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +export let consoleWebSocket: WebSocket; + +export function setup_proxy_console(id: string, console: Console, origin: string): void { + // this need to be copy, in order to keep reference to original methods + const originalConsole = { + log: console.log, + error: console.error + }; + const anyConsole = console as any; + + function proxyConsoleMethod(prefix: string, func: any, asJson: boolean) { + return function (...args: any[]) { + try { + let payload = args[0]; + if (payload === undefined) payload = "undefined"; + else if (payload === null) payload = "null"; + else if (typeof payload === "function") payload = payload.toString(); + else if (typeof payload !== "string") { + try { + payload = JSON.stringify(payload); + } catch (e) { + payload = payload.toString(); + } + } + + if (typeof payload === "string") { + if (payload[0] == "[") { + const now = new Date().toISOString(); + if (id !== "main") { + payload = `[${id}][${now}] ${payload}`; + } else { + payload = `[${now}] ${payload}`; + } + } else if (id !== "main") { + payload = `[${id}] ${payload}`; + } + } + + if (asJson) { + func(JSON.stringify({ + method: prefix, + payload: payload, + arguments: args + })); + } else { + func([prefix + payload, ...args.slice(1)]); + } + } catch (err) { + originalConsole.error(`proxyConsole failed: ${err}`); + } + }; + } + + const methods = ["debug", "trace", "warn", "info", "error"]; + for (const m of methods) { + if (typeof (anyConsole[m]) !== "function") { + anyConsole[m] = proxyConsoleMethod(`console.${m}: `, console.log, false); + } + } + + const consoleUrl = `${origin}/console`.replace("https://", "wss://").replace("http://", "ws://"); + + consoleWebSocket = new WebSocket(consoleUrl); + consoleWebSocket.addEventListener("open", () => { + originalConsole.log(`browser: [${id}] Console websocket connected.`); + }); + consoleWebSocket.addEventListener("error", (event) => { + originalConsole.error(`[${id}] websocket error: ${event}`, event); + }); + consoleWebSocket.addEventListener("close", (event) => { + originalConsole.error(`[${id}] websocket closed: ${event}`, event); + }); + + const send = (msg: string) => { + if (consoleWebSocket.readyState === WebSocket.OPEN) { + consoleWebSocket.send(msg); + } + else { + originalConsole.log(msg); + } + }; + + for (const m of ["log", ...methods]) + anyConsole[m] = proxyConsoleMethod(`console.${m}`, send, true); +} diff --git a/src/mono/wasm/runtime/loader/polyfills.ts b/src/mono/wasm/runtime/loader/polyfills.ts new file mode 100644 index 00000000000000..e1436c57fee5cf --- /dev/null +++ b/src/mono/wasm/runtime/loader/polyfills.ts @@ -0,0 +1,128 @@ + +import type { DotnetModuleInternal } from "../types/internal"; +import { INTERNAL, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, loaderHelpers } from "./globals"; + +let node_fs: any | undefined = undefined; +let node_url: any | undefined = undefined; + +export async function init_polyfills(module: DotnetModuleInternal): Promise { + + loaderHelpers.scriptDirectory = detectScriptDirectory(); + loaderHelpers.locateFile = (path) => { + if (isPathAbsolute(path)) return path; + return loaderHelpers.scriptDirectory + path; + }; + loaderHelpers.downloadResource = module.downloadResource; + loaderHelpers.fetch_like = fetch_like; + loaderHelpers.out = console.log; + loaderHelpers.err = console.error; + loaderHelpers.getApplicationEnvironment = module.getApplicationEnvironment; + + if (ENVIRONMENT_IS_NODE) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore: + INTERNAL.require = await import(/* webpackIgnore: true */"module").then(mod => mod.createRequire(import.meta.url)); + } else { + INTERNAL.require = Promise.resolve(() => { throw new Error("require not supported"); }); + } + + if (typeof globalThis.URL === "undefined") { + globalThis.URL = class URL { + private url; + constructor(url: string) { + this.url = url; + } + toString() { + return this.url; + } + } as any; + } +} + +const hasFetch = typeof (globalThis.fetch) === "function"; +export async function fetch_like(url: string, init?: RequestInit): Promise { + try { + if (ENVIRONMENT_IS_NODE) { + const isFileUrl = url.startsWith("file://"); + if (!isFileUrl && hasFetch) { + return globalThis.fetch(url, init || { credentials: "same-origin" }); + } + if (!node_fs) { + node_url = INTERNAL.require("url"); + node_fs = INTERNAL.require("fs"); + } + if (isFileUrl) { + url = node_url.fileURLToPath(url); + } + + const arrayBuffer = await node_fs.promises.readFile(url); + return { + ok: true, + headers: [], + url, + arrayBuffer: () => arrayBuffer, + json: () => JSON.parse(arrayBuffer) + }; + } + else if (hasFetch) { + return globalThis.fetch(url, init || { credentials: "same-origin" }); + } + else if (typeof (read) === "function") { + // note that it can't open files with unicode names, like Strae.xml + // https://bugs.chromium.org/p/v8/issues/detail?id=12541 + return { + ok: true, + url, + arrayBuffer: () => { + return new Uint8Array(read(url, "binary")); + }, + json: () => { + return JSON.parse(read(url, "utf8")); + } + }; + } + } + catch (e: any) { + return { + ok: false, + url, + status: 500, + statusText: "ERR28: " + e, + arrayBuffer: () => { throw e; }, + json: () => { throw e; } + }; + } + throw new Error("No fetch implementation available"); +} + +function normalizeFileUrl(filename: string) { + // unix vs windows + // remove query string + return filename.replace(/\\/g, "/").replace(/[?#].*/, ""); +} + +function normalizeDirectoryUrl(dir: string) { + return dir.slice(0, dir.lastIndexOf("/")) + "/"; +} + +export function detectScriptDirectory(): string { + loaderHelpers.scriptUrl = normalizeFileUrl(import.meta.url); + return normalizeDirectoryUrl(loaderHelpers.scriptUrl); +} + +const protocolRx = /^[a-zA-Z][a-zA-Z\d+\-.]*?:\/\//; +const windowsAbsoluteRx = /[a-zA-Z]:[\\/]/; +function isPathAbsolute(path: string): boolean { + if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { + // unix /x.json + // windows \x.json + // windows C:\x.json + // windows C:/x.json + return path.startsWith("/") || path.startsWith("\\") || path.indexOf("///") !== -1 || windowsAbsoluteRx.test(path); + } + + // anything with protocol is always absolute + // windows file:///C:/x.json + // windows http://C:/x.json + return protocolRx.test(path); +} diff --git a/src/mono/wasm/runtime/promise-controller.ts b/src/mono/wasm/runtime/loader/promise-controller.ts similarity index 69% rename from src/mono/wasm/runtime/promise-controller.ts rename to src/mono/wasm/runtime/loader/promise-controller.ts index f31c199143f2b7..d46719c8b041fa 100644 --- a/src/mono/wasm/runtime/promise-controller.ts +++ b/src/mono/wasm/runtime/loader/promise-controller.ts @@ -1,32 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { - mono_assert -} from "./types"; + +import type { ControllablePromise, PromiseAndController, PromiseController } from "../types/internal"; /// a unique symbol used to mark a promise as controllable export const promise_control_symbol = Symbol.for("wasm promise_control"); -/// A PromiseController encapsulates a Promise together with easy access to its resolve and reject functions. -/// It's a bit like a TaskCompletionSource in .NET -export interface PromiseController { - isDone: boolean; - readonly promise: Promise; - resolve: (value: T | PromiseLike) => void; - reject: (reason?: any) => void; -} - -/// A Promise with a controller attached -export interface ControllablePromise extends Promise { - [promise_control_symbol]: PromiseController; -} - -/// Just a pair of a promise and its controller -export interface PromiseAndController { - promise: ControllablePromise; - promise_control: PromiseController; -} - /// Creates a new promise together with a controller that can be used to resolve or reject that promise. /// Optionally takes callbacks to be called immediately after a promise is resolved or rejected. export function createPromiseController(afterResolve?: () => void, afterReject?: () => void): PromiseAndController { @@ -57,17 +36,17 @@ export function createPromiseController(afterResolve?: () => void, afterRejec }); (promise_control).promise = promise; const controllablePromise = promise as ControllablePromise; - controllablePromise[promise_control_symbol] = promise_control; + (controllablePromise as any)[promise_control_symbol] = promise_control; return { promise: controllablePromise, promise_control: promise_control }; } export function getPromiseController(promise: ControllablePromise): PromiseController; export function getPromiseController(promise: Promise): PromiseController | undefined { - return (promise as ControllablePromise)[promise_control_symbol]; + return (promise as any)[promise_control_symbol]; } export function isControllablePromise(promise: Promise): promise is ControllablePromise { - return (promise as ControllablePromise)[promise_control_symbol] !== undefined; + return (promise as any)[promise_control_symbol] !== undefined; } export function assertIsControllablePromise(promise: Promise): asserts promise is ControllablePromise { diff --git a/src/mono/wasm/runtime/run-outer.ts b/src/mono/wasm/runtime/loader/run.ts similarity index 78% rename from src/mono/wasm/runtime/run-outer.ts rename to src/mono/wasm/runtime/loader/run.ts index 0321cd8e574100..f0c37eaefec8c4 100644 --- a/src/mono/wasm/runtime/run-outer.ts +++ b/src/mono/wasm/runtime/loader/run.ts @@ -1,24 +1,26 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// WARNING: code in this file is executed before any of the emscripten code, so there is very little initialized already +import type { MonoConfig, DotnetHostBuilder, DotnetModuleConfig, RuntimeAPI, WebAssemblyStartOptions } from "../types"; +import type { MonoConfigInternal, GlobalObjects, EmscriptenModuleInternal, initializeExportsType, initializeReplacementsType, configureEmscriptenStartupType, configureWorkerStartupType, setGlobalObjectsType, passEmscriptenInternalsType, } from "../types/internal"; -import type { MonoConfig, DotnetHostBuilder, DotnetModuleConfig, RuntimeAPI, WebAssemblyStartOptions } from "./types-api"; -import type { MonoConfigInternal, GlobalObjects, EmscriptenModuleInternal } from "./types"; - -import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WEB, setGlobalObjects } from "./globals"; -import { mono_exit } from "./run"; -import { mono_assert } from "./types"; +import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WEB, exportedRuntimeAPI, setGlobalObjects } from "./globals"; +import { deep_merge_config, deep_merge_module, mono_wasm_load_config } from "./config"; +import { mono_exit } from "./exit"; import { setup_proxy_console } from "./logging"; -import { deep_merge_config, deep_merge_module } from "./config"; -import { initializeExports } from "./exports"; +import { resolve_asset_path, start_asset_download } from "./assets"; +import { init_polyfills } from "./polyfills"; +import { runtimeHelpers, loaderHelpers } from "./globals"; +import { init_globalization } from "./icu"; + export const globalObjectsRoot: GlobalObjects = { mono: {}, binding: {}, internal: {}, module: {}, - helpers: {}, + loaderHelpers: {}, + runtimeHelpers: {}, api: {} } as any; @@ -347,9 +349,8 @@ export class HostBuilder implements DotnetHostBuilder { } } -export function unifyModuleConfig(originalModule: EmscriptenModuleInternal, moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)): DotnetModuleConfig { - initializeExports(); - Object.assign(module, { ready: originalModule.ready }); +export async function createEmscripten(moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)): Promise { + // extract ModuleConfig if (typeof moduleFactory === "function") { const extension = moduleFactory(globalObjectsRoot.api) as any; if (extension.ready) { @@ -365,5 +366,59 @@ export function unifyModuleConfig(originalModule: EmscriptenModuleInternal, modu throw new Error("MONO_WASM: Can't use moduleFactory callback of createDotnetRuntime function."); } - return module; + if (!module.configSrc && (!module.config || Object.keys(module.config).length === 0 || !module.config.assets)) { + // if config file location nor assets are provided + module.configSrc = "./mono-config.json"; + } + + await init_polyfills(module); + + // download config + await mono_wasm_load_config(module); + + const promises = [ + // keep js module names dynamic by using config, in the future we can use feature detection to load different flavors + import(resolve_asset_path("js-module-runtime").resolvedUrl!), + import(resolve_asset_path("js-module-native").resolvedUrl!), + ]; + + start_asset_download(resolve_asset_path("dotnetwasm")).then(asset => { + loaderHelpers.wasmDownloadPromise.promise_control.resolve(asset); + }); + + init_globalization(); + + // TODO call mono_download_assets(); here in parallel ? + + const es6Modules = await Promise.all(promises); + const { initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setGlobalObjects, passEmscriptenInternals } = es6Modules[0] as { + setGlobalObjects: setGlobalObjectsType, + initializeExports: initializeExportsType, + initializeReplacements: initializeReplacementsType, + configureEmscriptenStartup: configureEmscriptenStartupType, + configureWorkerStartup: configureWorkerStartupType, + passEmscriptenInternals: passEmscriptenInternalsType, + }; + const { default: emscriptenFactory } = es6Modules[1] as { + default: (unificator: Function) => EmscriptenModuleInternal + }; + + setGlobalObjects(globalObjectsRoot); + initializeExports(globalObjectsRoot); + loaderHelpers.runtimeModuleLoaded.promise_control.resolve(); + + emscriptenFactory((originalModule: EmscriptenModuleInternal) => { + Object.assign(module, { + ready: originalModule.ready, + __dotnet_runtime: { + initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, passEmscriptenInternals + } + }); + + return module; + }); + + await runtimeHelpers.dotnetReady.promise; + + return exportedRuntimeAPI; } diff --git a/src/mono/wasm/runtime/logging.ts b/src/mono/wasm/runtime/logging.ts index 5f3910e30499f1..390286b24da923 100644 --- a/src/mono/wasm/runtime/logging.ts +++ b/src/mono/wasm/runtime/logging.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { INTERNAL, Module, runtimeHelpers } from "./globals"; +import { INTERNAL, Module, loaderHelpers } from "./globals"; import { CharPtr, VoidPtr } from "./types/emscripten"; export const wasm_func_map = new Map(); @@ -106,91 +106,6 @@ export function mono_wasm_trace_logger(log_domain_ptr: CharPtr, log_level_ptr: C } } -export let consoleWebSocket: WebSocket; - -export function setup_proxy_console(id: string, console: Console, origin: string): void { - // this need to be copy, in order to keep reference to original methods - const originalConsole = { - log: console.log, - error: console.error - }; - const anyConsole = console as any; - - function proxyConsoleMethod(prefix: string, func: any, asJson: boolean) { - return function (...args: any[]) { - try { - let payload = args[0]; - if (payload === undefined) payload = "undefined"; - else if (payload === null) payload = "null"; - else if (typeof payload === "function") payload = payload.toString(); - else if (typeof payload !== "string") { - try { - payload = JSON.stringify(payload); - } catch (e) { - payload = payload.toString(); - } - } - - if (typeof payload === "string") { - if (payload[0] == "[") { - const now = new Date().toISOString(); - if (id !== "main") { - payload = `[${id}][${now}] ${payload}`; - } else { - payload = `[${now}] ${payload}`; - } - } else if (id !== "main") { - payload = `[${id}] ${payload}`; - } - } - - if (asJson) { - func(JSON.stringify({ - method: prefix, - payload: payload, - arguments: args - })); - } else { - func([prefix + payload, ...args.slice(1)]); - } - } catch (err) { - originalConsole.error(`proxyConsole failed: ${err}`); - } - }; - } - - const methods = ["debug", "trace", "warn", "info", "error"]; - for (const m of methods) { - if (typeof (anyConsole[m]) !== "function") { - anyConsole[m] = proxyConsoleMethod(`console.${m}: `, console.log, false); - } - } - - const consoleUrl = `${origin}/console`.replace("https://", "wss://").replace("http://", "ws://"); - - consoleWebSocket = new WebSocket(consoleUrl); - consoleWebSocket.addEventListener("open", () => { - originalConsole.log(`browser: [${id}] Console websocket connected.`); - }); - consoleWebSocket.addEventListener("error", (event) => { - originalConsole.error(`[${id}] websocket error: ${event}`, event); - }); - consoleWebSocket.addEventListener("close", (event) => { - originalConsole.error(`[${id}] websocket closed: ${event}`, event); - }); - - const send = (msg: string) => { - if (consoleWebSocket.readyState === WebSocket.OPEN) { - consoleWebSocket.send(msg); - } - else { - originalConsole.log(msg); - } - }; - - for (const m of ["log", ...methods]) - anyConsole[m] = proxyConsoleMethod(`console.${m}`, send, true); -} export function parseSymbolMapFile(text: string) { text.split(/[\r\n]/).forEach((line: string) => { @@ -202,5 +117,5 @@ export function parseSymbolMapFile(text: string) { wasm_func_map.set(Number(parts[0]), parts[1]); }); - if (runtimeHelpers.diagnosticTracing) console.debug(`MONO_WASM: Loaded ${wasm_func_map.size} symbols`); + if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: Loaded ${wasm_func_map.size} symbols`); } \ No newline at end of file diff --git a/src/mono/wasm/runtime/managed-exports.ts b/src/mono/wasm/runtime/managed-exports.ts index 4892052af57202..bc54e51b85bddc 100644 --- a/src/mono/wasm/runtime/managed-exports.ts +++ b/src/mono/wasm/runtime/managed-exports.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { GCHandle, MarshalerToCs, MarshalerToJs, MarshalerType, MonoMethod, mono_assert } from "./types"; +import { GCHandle, MarshalerToCs, MarshalerToJs, MarshalerType, MonoMethod } from "./types/internal"; import cwraps from "./cwraps"; import { runtimeHelpers, ENVIRONMENT_IS_PTHREAD, Module } from "./globals"; import { alloc_stack_frame, get_arg, get_arg_gc_handle, set_arg_type, set_gc_handle } from "./marshal"; diff --git a/src/mono/wasm/runtime/marshal-to-cs.ts b/src/mono/wasm/runtime/marshal-to-cs.ts index cc596738cd07f2..fbdd3629b68140 100644 --- a/src/mono/wasm/runtime/marshal-to-cs.ts +++ b/src/mono/wasm/runtime/marshal-to-cs.ts @@ -17,7 +17,7 @@ import { import { get_marshaler_to_js_by_type } from "./marshal-to-js"; import { _zero_region } from "./memory"; import { js_string_to_mono_string_root } from "./strings"; -import { mono_assert, GCHandle, GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToCs, MarshalerType } from "./types"; +import { GCHandle, GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToCs, MarshalerType } from "./types/internal"; import { TypedArray } from "./types/emscripten"; import { addUnsettledPromise, settleUnsettledPromise } from "./pthreads/shared/eventloop"; diff --git a/src/mono/wasm/runtime/marshal-to-js.ts b/src/mono/wasm/runtime/marshal-to-js.ts index 6590bacd12cefe..1cbf461e6a7f0d 100644 --- a/src/mono/wasm/runtime/marshal-to-js.ts +++ b/src/mono/wasm/runtime/marshal-to-js.ts @@ -1,10 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { createPromiseController, assertIsControllablePromise, getPromiseController } from "./promise-controller"; import cwraps from "./cwraps"; import { _lookup_js_owned_object, mono_wasm_get_jsobj_from_js_handle, mono_wasm_get_js_handle, setup_managed_proxy } from "./gc-handles"; -import { Module, runtimeHelpers } from "./globals"; +import { Module, createPromiseController, loaderHelpers, runtimeHelpers } from "./globals"; import { ManagedObject, ManagedError, get_arg_gc_handle, get_arg_js_handle, get_arg_type, get_arg_i32, get_arg_f64, get_arg_i52, get_arg_i16, get_arg_u8, get_arg_f32, @@ -14,7 +13,7 @@ import { ArraySegment, Span, MemoryViewType, get_signature_arg3_type, get_arg_i64_big, get_arg_intptr, get_arg_element_type, JavaScriptMarshalerArgSize } from "./marshal"; import { conv_string_root } from "./strings"; -import { mono_assert, JSHandleNull, GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToJs, MarshalerType } from "./types"; +import { JSHandleNull, GCHandleNull, JSMarshalerArgument, JSMarshalerArguments, JSMarshalerType, MarshalerToCs, MarshalerToJs, BoundMarshalerToJs, MarshalerType } from "./types/internal"; import { TypedArray } from "./types/emscripten"; import { get_marshaler_to_cs_by_type } from "./marshal-to-cs"; @@ -225,8 +224,8 @@ export function marshal_task_to_js(arg: JSMarshalerArgument, _?: MarshalerType, } const promise = mono_wasm_get_jsobj_from_js_handle(js_handle); mono_assert(!!promise, () => `ERR28: promise not found for js_handle: ${js_handle} `); - assertIsControllablePromise(promise); - const promise_control = getPromiseController(promise); + loaderHelpers.assertIsControllablePromise(promise); + const promise_control = loaderHelpers.getPromiseController(promise); const orig_resolve = promise_control.resolve; promise_control.resolve = (argInner: JSMarshalerArgument) => { @@ -281,8 +280,8 @@ export function mono_wasm_marshal_promise(args: JSMarshalerArguments): void { // resolve existing promise const promise = mono_wasm_get_jsobj_from_js_handle(js_handle); mono_assert(!!promise, () => `ERR25: promise not found for js_handle: ${js_handle} `); - assertIsControllablePromise(promise); - const promise_control = getPromiseController(promise); + loaderHelpers.assertIsControllablePromise(promise); + const promise_control = loaderHelpers.getPromiseController(promise); if (exc_type !== MarshalerType.None) { const reason = marshal_exception_to_js(exc); diff --git a/src/mono/wasm/runtime/marshal.ts b/src/mono/wasm/runtime/marshal.ts index 5cc7a9eab5cad7..9fc17c720bbe86 100644 --- a/src/mono/wasm/runtime/marshal.ts +++ b/src/mono/wasm/runtime/marshal.ts @@ -5,7 +5,7 @@ import { js_owned_gc_handle_symbol, teardown_managed_proxy } from "./gc-handles" import { Module, runtimeHelpers } from "./globals"; import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8 } from "./memory"; import { mono_wasm_new_external_root } from "./roots"; -import { mono_assert, GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot, MarshalerType } from "./types"; +import { GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot, MarshalerType } from "./types/internal"; import { CharPtr, TypedArray, VoidPtr } from "./types/emscripten"; export const cs_to_js_marshalers = new Map(); diff --git a/src/mono/wasm/runtime/memory.ts b/src/mono/wasm/runtime/memory.ts index 5ab35b8a12b763..83e94171a53274 100644 --- a/src/mono/wasm/runtime/memory.ts +++ b/src/mono/wasm/runtime/memory.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import monoWasmThreads from "consts:monoWasmThreads"; -import { mono_assert, MemOffset, NumberOrPointer } from "./types"; +import { MemOffset, NumberOrPointer } from "./types/internal"; import { VoidPtr, CharPtr } from "./types/emscripten"; import cwraps, { I52Error } from "./cwraps"; import { Module, runtimeHelpers } from "./globals"; diff --git a/src/mono/wasm/runtime/modularize-dotnet.md b/src/mono/wasm/runtime/modularize-dotnet.md index 63f4122f4e7fa0..4b23e3790af357 100644 --- a/src/mono/wasm/runtime/modularize-dotnet.md +++ b/src/mono/wasm/runtime/modularize-dotnet.md @@ -1,5 +1,5 @@ # Linked javascript files -They are emcc way how to extend the dotnet.js script during linking, by appending the scripts. +They are emcc way how to extend the dotnet.native.js script during linking, by appending the scripts. See https://emscripten.org/docs/tools_reference/emcc.html#emcc-pre-js There are `-extern-pre-js`,`-pre-js`, `-post-js`, `-extern-post-js`. diff --git a/src/mono/wasm/runtime/net6-legacy/buffers.ts b/src/mono/wasm/runtime/net6-legacy/buffers.ts index 0a33b6991b0bdc..533a161cd24b6e 100644 --- a/src/mono/wasm/runtime/net6-legacy/buffers.ts +++ b/src/mono/wasm/runtime/net6-legacy/buffers.ts @@ -4,7 +4,7 @@ import { Module } from "../globals"; import { wrap_error_root, wrap_no_error_root } from "../invoke-js"; import { mono_wasm_new_external_root } from "../roots"; -import { MonoArray, MonoObjectRef, MonoObject } from "../types"; +import { MonoArray, MonoObjectRef, MonoObject } from "../types/internal"; import { Int32Ptr, TypedArray } from "../types/emscripten"; import { js_to_mono_obj_root } from "./js-to-cs"; diff --git a/src/mono/wasm/runtime/net6-legacy/corebindings.ts b/src/mono/wasm/runtime/net6-legacy/corebindings.ts index 489df81ece89af..fd4d85aa021304 100644 --- a/src/mono/wasm/runtime/net6-legacy/corebindings.ts +++ b/src/mono/wasm/runtime/net6-legacy/corebindings.ts @@ -1,12 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { JSHandle, GCHandle, MonoObjectRef, MonoMethod, MonoObject, WasmRoot } from "../types"; +import { JSHandle, GCHandle, MonoObjectRef, MonoMethod, MonoObject, WasmRoot, PromiseController } from "../types/internal"; import { mono_bind_method, _create_primitive_converters } from "./method-binding"; import { mono_wasm_new_root } from "../roots"; import { Module, runtimeHelpers } from "../globals"; import cwraps from "../cwraps"; -import { PromiseController } from "../promise-controller"; import { legacyHelpers, wasm_type_symbol } from "./globals"; import { find_corlib_class } from "../class-loader"; type SigLine = [lazy: boolean, jsname: string, csname: string, signature: string/*ArgsMarshalString*/]; diff --git a/src/mono/wasm/runtime/net6-legacy/cs-to-js.ts b/src/mono/wasm/runtime/net6-legacy/cs-to-js.ts index 2aefab4afb7a72..0585daae7b2a4f 100644 --- a/src/mono/wasm/runtime/net6-legacy/cs-to-js.ts +++ b/src/mono/wasm/runtime/net6-legacy/cs-to-js.ts @@ -1,21 +1,21 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +import { Int32Ptr, VoidPtr } from "../types/emscripten"; +import { MarshalType, MonoType, MarshalError, MonoTypeNull, MonoArray, MonoArrayNull, MonoObject, MonoObjectNull, GCHandle, MonoStringRef, MonoObjectRef, MonoString, JSHandleDisposed, is_nullish, WasmRoot } from "../types/internal"; import { _are_promises_supported } from "../cancelable-promise"; import { legacy_c_functions as cwraps } from "../cwraps"; import { mono_wasm_get_jsobj_from_js_handle, _lookup_js_owned_object, setup_managed_proxy, mono_wasm_get_js_handle, teardown_managed_proxy, assert_not_disposed } from "../gc-handles"; import { wrap_error_root, wrap_no_error_root } from "../invoke-js"; import { ManagedObject } from "../marshal"; import { getU32, getI32, getF32, getF64, setI32_unchecked } from "../memory"; -import { createPromiseController } from "../promise-controller"; import { mono_wasm_new_root, mono_wasm_new_external_root } from "../roots"; import { conv_string_root } from "../strings"; -import { MarshalType, MonoType, MarshalError, MonoTypeNull, MonoArray, MonoArrayNull, MonoObject, MonoObjectNull, GCHandle, MonoStringRef, MonoObjectRef, MonoString, JSHandleDisposed, is_nullish, WasmRoot } from "../types"; -import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { legacyManagedExports } from "./corebindings"; import { legacyHelpers } from "./globals"; import { js_to_mono_obj_root } from "./js-to-cs"; import { mono_bind_method, mono_method_get_call_signature_ref } from "./method-binding"; +import { createPromiseController } from "../globals"; const delegate_invoke_symbol = Symbol.for("wasm delegate_invoke"); diff --git a/src/mono/wasm/runtime/net6-legacy/export-types.ts b/src/mono/wasm/runtime/net6-legacy/export-types.ts index 921689525e34a7..78d695de27c962 100644 --- a/src/mono/wasm/runtime/net6-legacy/export-types.ts +++ b/src/mono/wasm/runtime/net6-legacy/export-types.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import type { MemOffset, MonoArray, MonoObject, MonoObjectRef, MonoString, NumberOrPointer, WasmRoot, WasmRootBuffer } from "../types"; +import type { MemOffset, MonoArray, MonoObject, MonoObjectRef, MonoString, NumberOrPointer, WasmRoot, WasmRootBuffer } from "../types/internal"; import type { VoidPtr } from "../types/emscripten"; /** diff --git a/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts b/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts index 0c45c2749357ab..4c61e88fca9a5d 100644 --- a/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts +++ b/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts @@ -4,11 +4,10 @@ import { legacy_c_functions as cwraps } from "../cwraps"; import { mono_wasm_runtime_ready } from "../debug"; import { mono_wasm_load_icu_data } from "../icu"; -import { runtimeHelpers } from "../globals"; import { mono_wasm_load_bytes_into_heap, setB32, setI8, setI16, setI32, setI52, setU52, setI64Big, setU8, setU16, setU32, setF32, setF64, getB32, getI8, getI16, getI32, getI52, getU52, getI64Big, getU8, getU16, getU32, getF32, getF64 } from "../memory"; import { mono_wasm_new_root_buffer, mono_wasm_new_root, mono_wasm_new_external_root, mono_wasm_release_roots } from "../roots"; import { mono_run_main, mono_run_main_and_exit } from "../run"; -import { mono_wasm_setenv, mono_wasm_load_config } from "../startup"; +import { mono_wasm_setenv } from "../startup"; import { js_string_to_mono_string, conv_string, js_string_to_mono_string_root, conv_string_root } from "../strings"; import { mono_array_to_js_array, unbox_mono_obj, unbox_mono_obj_root, mono_array_root_to_js_array } from "./cs-to-js"; import { js_typed_array_to_array, js_to_mono_obj, js_typed_array_to_array_root, js_to_mono_obj_root } from "./js-to-cs"; @@ -17,6 +16,7 @@ import { mono_wasm_load_runtime } from "../startup"; import { BINDINGType, MONOType } from "./export-types"; import { mono_wasm_load_data_archive } from "../assets"; import { mono_method_resolve } from "./method-binding"; +import { loaderHelpers } from "../globals"; export function export_mono_api(): MONOType { return { @@ -26,7 +26,7 @@ export function export_mono_api(): MONOType { mono_wasm_load_icu_data, mono_wasm_runtime_ready, mono_wasm_load_data_archive, - mono_wasm_load_config, + mono_wasm_load_config: null as any,//TODO ZAMO mono_wasm_new_root_buffer, mono_wasm_new_root, mono_wasm_new_external_root, @@ -38,7 +38,7 @@ export function export_mono_api(): MONOType { mono_wasm_add_assembly: null, mono_wasm_load_runtime, - config: runtimeHelpers.config, + config: loaderHelpers.config, loaded_files: [], // memory accessors diff --git a/src/mono/wasm/runtime/net6-legacy/globals.ts b/src/mono/wasm/runtime/net6-legacy/globals.ts index cf69addeaee4ac..3aabbe0830f380 100644 --- a/src/mono/wasm/runtime/net6-legacy/globals.ts +++ b/src/mono/wasm/runtime/net6-legacy/globals.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import type { GlobalObjects, MonoClass } from "../types"; +import type { GlobalObjects, MonoClass } from "../types/internal"; import type { VoidPtr } from "../types/emscripten"; import type { BINDINGType, MONOType } from "./export-types"; diff --git a/src/mono/wasm/runtime/net6-legacy/js-to-cs.ts b/src/mono/wasm/runtime/net6-legacy/js-to-cs.ts index f4f81ef5615d7e..21558c86248416 100644 --- a/src/mono/wasm/runtime/net6-legacy/js-to-cs.ts +++ b/src/mono/wasm/runtime/net6-legacy/js-to-cs.ts @@ -9,7 +9,7 @@ import { wrap_error_root, wrap_no_error_root } from "../invoke-js"; import { setI32_unchecked, setU32_unchecked, setF64, setB32 } from "../memory"; import { mono_wasm_new_root, mono_wasm_release_roots, mono_wasm_new_external_root } from "../roots"; import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root } from "../strings"; -import { MonoObject, is_nullish, MonoClass, MonoArray, MonoMethod, MonoObjectNull, JSHandle, MonoObjectRef, JSHandleNull, JSHandleDisposed, WasmRoot } from "../types"; +import { MonoObject, is_nullish, MonoClass, MonoArray, MonoMethod, MonoObjectNull, JSHandle, MonoObjectRef, JSHandleNull, JSHandleDisposed, WasmRoot } from "../types/internal"; import { TypedArray, Int32Ptr } from "../types/emscripten"; import { has_backing_array_buffer } from "./buffers"; import { legacyManagedExports } from "./corebindings"; diff --git a/src/mono/wasm/runtime/net6-legacy/method-binding.ts b/src/mono/wasm/runtime/net6-legacy/method-binding.ts index 780301959061f6..4cab645fb18255 100644 --- a/src/mono/wasm/runtime/net6-legacy/method-binding.ts +++ b/src/mono/wasm/runtime/net6-legacy/method-binding.ts @@ -8,7 +8,7 @@ import { parseFQN } from "../invoke-cs"; import { setI32, setU32, setF32, setF64, setU52, setI52, setB32, setI32_unchecked, setU32_unchecked, _zero_region, _create_temp_frame, getB32, getI32, getU32, getF32, getF64 } from "../memory"; import { mono_wasm_new_external_root, mono_wasm_new_root } from "../roots"; import { js_string_to_mono_string_root, js_string_to_mono_string_interned_root, conv_string_root } from "../strings"; -import { MonoMethod, MonoObject, MonoType, MonoClass, mono_assert, VoidPtrNull, MarshalType, MonoString, MonoObjectNull, WasmRootBuffer, WasmRoot } from "../types"; +import { MonoMethod, MonoObject, MonoType, MonoClass, VoidPtrNull, MarshalType, MonoString, MonoObjectNull, WasmRootBuffer, WasmRoot } from "../types/internal"; import { VoidPtr } from "../types/emscripten"; import { legacyManagedExports } from "./corebindings"; import { get_js_owned_object_by_gc_handle_ref, _unbox_mono_obj_root_with_known_nonprimitive_type } from "./cs-to-js"; diff --git a/src/mono/wasm/runtime/net6-legacy/method-calls.ts b/src/mono/wasm/runtime/net6-legacy/method-calls.ts index cf9fee9430ebd1..330e7c0c44b024 100644 --- a/src/mono/wasm/runtime/net6-legacy/method-calls.ts +++ b/src/mono/wasm/runtime/net6-legacy/method-calls.ts @@ -9,7 +9,7 @@ import { _release_temp_frame } from "../memory"; import { mono_wasm_new_external_root, mono_wasm_new_root } from "../roots"; import { find_entry_point } from "../run"; import { conv_string_root, js_string_to_mono_string_root } from "../strings"; -import { JSHandle, MonoStringRef, MonoObjectRef, MonoArray, MonoString, MonoObject, is_nullish, mono_assert, WasmRoot } from "../types"; +import { JSHandle, MonoStringRef, MonoObjectRef, MonoArray, MonoString, MonoObject, is_nullish, WasmRoot } from "../types/internal"; import { Int32Ptr, VoidPtr } from "../types/emscripten"; import { mono_array_root_to_js_array, unbox_mono_obj_root } from "./cs-to-js"; import { js_array_to_mono_array, js_to_mono_obj_root } from "./js-to-cs"; diff --git a/src/mono/wasm/runtime/polyfills.ts b/src/mono/wasm/runtime/polyfills.ts index 4edfffe60f4675..639bd3209d3f94 100644 --- a/src/mono/wasm/runtime/polyfills.ts +++ b/src/mono/wasm/runtime/polyfills.ts @@ -3,31 +3,57 @@ import BuildConfiguration from "consts:configuration"; import MonoWasmThreads from "consts:monoWasmThreads"; -import type { DotnetModuleConfigImports, EmscriptenReplacements } from "./types"; +import type { EmscriptenReplacements } from "./types/internal"; import type { TypedArray } from "./types/emscripten"; -import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, ENVIRONMENT_IS_WORKER, ENVIRONMENT_IS_WEB, INTERNAL, Module, runtimeHelpers } from "./globals"; +import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WEB, INTERNAL, Module, loaderHelpers, runtimeHelpers } from "./globals"; import { replaceEmscriptenPThreadLibrary } from "./pthreads/shared/emscripten-replacements"; -let node_fs: any | undefined = undefined; -let node_url: any | undefined = undefined; - -export function init_polyfills(): void { +const dummyPerformance = { + now: function () { + return Date.now(); + } +}; +export function initializeReplacements(replacements: EmscriptenReplacements): void { // performance.now() is used by emscripten and doesn't work in JSC if (typeof globalThis.performance === "undefined") { globalThis.performance = dummyPerformance as any; } - if (typeof globalThis.URL === "undefined") { - globalThis.URL = class URL { - private url; - constructor(url: string) { - this.url = url; - } - toString() { - return this.url; - } - } as any; + replacements.require = INTERNAL.require; + + // script location + replacements.scriptDirectory = loaderHelpers.scriptDirectory; + Module.mainScriptUrlOrBlob = replacements.scriptUrl;// this is needed by worker threads + if (Module.locateFile === Module.__locateFile) { + Module.locateFile = loaderHelpers.locateFile; } + + if (BuildConfiguration === "Debug") { + console.debug(`MONO_WASM: starting script ${loaderHelpers.scriptUrl}`); + console.debug(`MONO_WASM: starting in ${loaderHelpers.scriptDirectory}`); + } + + // prefer fetch_like over global fetch for assets + replacements.fetch = loaderHelpers.fetch_like; + + // misc + replacements.noExitRuntime = ENVIRONMENT_IS_WEB; + + // threads + if (MonoWasmThreads) { + if (replacements.pthreadReplacements) { + replaceEmscriptenPThreadLibrary(replacements.pthreadReplacements); + } + } + + // memory + const originalUpdateMemoryViews = replacements.updateMemoryViews; + runtimeHelpers.updateMemoryViews = replacements.updateMemoryViews = () => { + originalUpdateMemoryViews(); + }; +} + +export async function init_polyfills_async(): Promise { // v8 shell doesn't have Event and EventTarget if (MonoWasmThreads && typeof globalThis.Event === "undefined") { globalThis.Event = class Event { @@ -119,73 +145,8 @@ export function init_polyfills(): void { } }; } -} - -export function initializeReplacements(replacements: EmscriptenReplacements): void { - // require replacement - const imports = Module.imports = (Module.imports || {}) as DotnetModuleConfigImports; - const requireWrapper = (wrappedRequire: Function) => (name: string) => { - const resolved = (Module.imports)[name]; - if (resolved) { - return resolved; - } - return wrappedRequire(name); - }; - if (imports.require) { - runtimeHelpers.requirePromise = replacements.requirePromise = Promise.resolve(requireWrapper(imports.require)); - } - else if (replacements.require) { - runtimeHelpers.requirePromise = replacements.requirePromise = Promise.resolve(requireWrapper(replacements.require)); - } else if (replacements.requirePromise) { - runtimeHelpers.requirePromise = replacements.requirePromise.then(require => requireWrapper(require)); - } else { - runtimeHelpers.requirePromise = replacements.requirePromise = Promise.resolve(requireWrapper((name: string) => { - throw new Error(`Please provide Module.imports.${name} or Module.imports.require`); - })); - } - - // script location - runtimeHelpers.scriptDirectory = replacements.scriptDirectory = detectScriptDirectory(replacements); - Module.mainScriptUrlOrBlob = replacements.scriptUrl;// this is needed by worker threads - if (BuildConfiguration === "Debug") { - console.debug(`MONO_WASM: starting script ${replacements.scriptUrl}`); - console.debug(`MONO_WASM: starting in ${runtimeHelpers.scriptDirectory}`); - } - if (Module.__locateFile === Module.locateFile) { - // above it's our early version, we could replace it with better - Module.locateFile = runtimeHelpers.locateFile = (path) => { - if (isPathAbsolute(path)) return path; - return runtimeHelpers.scriptDirectory + path; - }; - } else { - // we use what was given to us - runtimeHelpers.locateFile = Module.locateFile!; - } - - // prefer fetch_like over global fetch for assets - replacements.fetch = runtimeHelpers.fetch_like = imports.fetch || fetch_like; - - // misc - replacements.noExitRuntime = ENVIRONMENT_IS_WEB; - - // threads - if (MonoWasmThreads) { - if (replacements.pthreadReplacements) { - replaceEmscriptenPThreadLibrary(replacements.pthreadReplacements); - } - } - - // memory - const originalUpdateMemoryViews = replacements.updateMemoryViews; - runtimeHelpers.updateMemoryViews = replacements.updateMemoryViews = () => { - originalUpdateMemoryViews(); - }; -} - -export async function init_polyfills_async(): Promise { if (ENVIRONMENT_IS_NODE) { // wait for locateFile setup on NodeJs - INTERNAL.require = await runtimeHelpers.requirePromise; if (globalThis.performance === dummyPerformance) { const { performance } = INTERNAL.require("perf_hooks"); globalThis.performance = performance; @@ -223,106 +184,4 @@ export async function init_polyfills_async(): Promise { runtimeHelpers.subtle = globalThis.crypto?.subtle; } -const dummyPerformance = { - now: function () { - return Date.now(); - } -}; - -export async function fetch_like(url: string, init?: RequestInit): Promise { - const imports = Module.imports as DotnetModuleConfigImports; - const hasFetch = typeof (globalThis.fetch) === "function"; - try { - if (typeof (imports.fetch) === "function") { - return imports.fetch(url, init || { credentials: "same-origin" }); - } - else if (ENVIRONMENT_IS_NODE) { - const isFileUrl = url.startsWith("file://"); - if (!isFileUrl && hasFetch) { - return globalThis.fetch(url, init || { credentials: "same-origin" }); - } - if (!node_fs) { - const node_require = await runtimeHelpers.requirePromise; - node_url = node_require("url"); - node_fs = node_require("fs"); - } - if (isFileUrl) { - url = node_url.fileURLToPath(url); - } - - const arrayBuffer = await node_fs.promises.readFile(url); - return { - ok: true, - headers: [], - url, - arrayBuffer: () => arrayBuffer, - json: () => JSON.parse(arrayBuffer) - }; - } - else if (hasFetch) { - return globalThis.fetch(url, init || { credentials: "same-origin" }); - } - else if (typeof (read) === "function") { - // note that it can't open files with unicode names, like Strae.xml - // https://bugs.chromium.org/p/v8/issues/detail?id=12541 - const arrayBuffer = new Uint8Array(read(url, "binary")); - return { - ok: true, - url, - arrayBuffer: () => arrayBuffer, - json: () => JSON.parse(Module.UTF8ArrayToString(arrayBuffer, 0, arrayBuffer.length)) - }; - } - } - catch (e: any) { - return { - ok: false, - url, - status: 500, - statusText: "ERR28: " + e, - arrayBuffer: () => { throw e; }, - json: () => { throw e; } - }; - } - throw new Error("No fetch implementation available"); -} - -function normalizeFileUrl(filename: string) { - // unix vs windows - // remove query string - return filename.replace(/\\/g, "/").replace(/[?#].*/, ""); -} - -function normalizeDirectoryUrl(dir: string) { - return dir.slice(0, dir.lastIndexOf("/")) + "/"; -} - -export function detectScriptDirectory(replacements: EmscriptenReplacements): string { - if (ENVIRONMENT_IS_WORKER) { - // Check worker, not web, since window could be polyfilled - replacements.scriptUrl = self.location.href; - } - if (!replacements.scriptUrl) { - // probably V8 shell in non ES6 - replacements.scriptUrl = "./dotnet.js"; - } - replacements.scriptUrl = normalizeFileUrl(replacements.scriptUrl); - return normalizeDirectoryUrl(replacements.scriptUrl); -} -const protocolRx = /^[a-zA-Z][a-zA-Z\d+\-.]*?:\/\//; -const windowsAbsoluteRx = /[a-zA-Z]:[\\/]/; -function isPathAbsolute(path: string): boolean { - if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) { - // unix /x.json - // windows \x.json - // windows C:\x.json - // windows C:/x.json - return path.startsWith("/") || path.startsWith("\\") || path.indexOf("///") !== -1 || windowsAbsoluteRx.test(path); - } - - // anything with protocol is always absolute - // windows file:///C:/x.json - // windows http://C:/x.json - return protocolRx.test(path); -} diff --git a/src/mono/wasm/runtime/profiler.ts b/src/mono/wasm/runtime/profiler.ts index fbaa646d903bb7..021273c2f82b97 100644 --- a/src/mono/wasm/runtime/profiler.ts +++ b/src/mono/wasm/runtime/profiler.ts @@ -2,9 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. import { ENVIRONMENT_IS_WEB, Module, runtimeHelpers } from "./globals"; -import { AOTProfilerOptions, BrowserProfilerOptions } from "./types"; +import { MonoMethod, AOTProfilerOptions, BrowserProfilerOptions } from "./types/internal"; import cwraps from "./cwraps"; -import { MonoMethod } from "./types"; // Initialize the AOT profiler with OPTIONS. // Requires the AOT profiler to be linked into the app. diff --git a/src/mono/wasm/runtime/promise-utils.ts b/src/mono/wasm/runtime/promise-utils.ts deleted file mode 100644 index 6b1e57ee737383..00000000000000 --- a/src/mono/wasm/runtime/promise-utils.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/// Make a promise that resolves after a given number of milliseconds. -export function delay(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); -} - diff --git a/src/mono/wasm/runtime/pthreads/browser/index.ts b/src/mono/wasm/runtime/pthreads/browser/index.ts index 9910fcea2daea4..46bb22a5b443f2 100644 --- a/src/mono/wasm/runtime/pthreads/browser/index.ts +++ b/src/mono/wasm/runtime/pthreads/browser/index.ts @@ -4,11 +4,10 @@ import { isMonoWorkerMessageChannelCreated, monoSymbol, makeMonoThreadMessageApplyMonoConfig, isMonoWorkerMessagePreload, MonoWorkerMessage } from "../shared"; import { pthread_ptr } from "../shared/types"; import { MonoThreadMessage } from "../shared"; -import { PromiseController, createPromiseController } from "../../promise-controller"; -import { mono_assert } from "../../types"; import Internals from "../shared/emscripten-internals"; -import { runtimeHelpers } from "../../globals"; -import { MonoConfig } from "../../types-api"; +import { createPromiseController, loaderHelpers } from "../../globals"; +import { PromiseController } from "../../types/internal"; +import { MonoConfig } from "../../types"; const threads: Map = new Map(); @@ -91,7 +90,7 @@ function monoWorkerMessageHandler(worker: Worker, ev: MessageEvent import MonoWasmThreads from "consts:monoWasmThreads"; -import { Module, ENVIRONMENT_IS_PTHREAD, runtimeHelpers, ENVIRONMENT_IS_WEB } from "../../globals"; +import { Module, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_WEB, loaderHelpers } from "../../globals"; import { makeChannelCreatedMonoMessage, makePreloadMonoMessage } from "../shared"; import type { pthread_ptr } from "../shared/types"; -import { is_nullish, MonoConfigInternal, mono_assert } from "../../types"; +import { is_nullish, MonoConfigInternal } from "../../types/internal"; import type { MonoThreadMessage } from "../shared"; import { PThreadSelf, @@ -16,9 +16,8 @@ import { dotnetPthreadAttached, WorkerThreadEventTarget } from "./events"; -import { setup_proxy_console } from "../../logging"; -import { afterConfigLoaded, preRunWorker } from "../../startup"; -import { MonoConfig } from "../../types-api"; +import { preRunWorker } from "../../startup"; +import { MonoConfig } from "../../types"; // re-export some of the events types export { @@ -100,13 +99,13 @@ function onMonoConfigReceived(config: MonoConfigInternal): void { } console.debug("MONO_WASM: mono config received"); - config = runtimeHelpers.config = Module.config = Object.assign(Module.config || {} as any, config); + config = loaderHelpers.config = Module.config = Object.assign(Module.config || {} as any, config); workerMonoConfigReceived = true; - afterConfigLoaded.promise_control.resolve(config); + loaderHelpers.afterConfigLoaded.promise_control.resolve(config); if (ENVIRONMENT_IS_WEB && config.forwardConsoleLogsToWS && typeof globalThis.WebSocket != "undefined") { - setup_proxy_console("pthread-worker", console, self.location.href); + loaderHelpers.setup_proxy_console("pthread-worker", console, self.location.href); } } @@ -115,7 +114,7 @@ function onMonoConfigReceived(config: MonoConfigInternal): void { export function mono_wasm_pthread_on_pthread_attached(pthread_id: pthread_ptr): void { const self = pthread_self; mono_assert(self !== null && self.pthread_id == pthread_id, "expected pthread_self to be set already when attaching"); - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: attaching pthread to runtime 0x" + pthread_id.toString(16)); preRunWorker(); currentWorkerThreadEvents.dispatchEvent(makeWorkerThreadEvent(dotnetPthreadAttached, self)); @@ -129,7 +128,7 @@ export function afterThreadInitTLS(): void { if (ENVIRONMENT_IS_PTHREAD) { const pthread_ptr = (Module)["_pthread_self"](); mono_assert(!is_nullish(pthread_ptr), "pthread_self() returned null"); - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: after thread init, pthread ptr 0x" + pthread_ptr.toString(16)); const self = setupChannelToMainThread(pthread_ptr); currentWorkerThreadEvents.dispatchEvent(makeWorkerThreadEvent(dotnetPthreadCreated, self)); diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index a666eebd725f9c..aa3f1a4a10d82c 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -31,16 +31,11 @@ const terserConfig = { keep_fnames: /(mono_wasm_runtime_ready|mono_wasm_fire_debugger_agent_message_with_data|mono_wasm_fire_debugger_agent_message_with_data_to_pause|mono_wasm_set_timeout_exec)/, keep_classnames: /(ManagedObject|ManagedError|Span|ArraySegment|WasmRootBuffer|SessionOptionsBuilder)/, }, - format: { - wrap_iife: true - } }; const plugins = isDebug ? [writeOnChangePlugin()] : [terser(terserConfig), writeOnChangePlugin()]; const banner = "//! Licensed to the .NET Foundation under one or more agreements.\n//! The .NET Foundation licenses this file to you under the MIT license.\n"; const banner_dts = banner + "//!\n//! This is generated file, see src/mono/wasm/runtime/rollup.config.js\n\n//! This is not considered public API with backward compatibility guarantees. \n"; // emcc doesn't know how to load ES6 module, that's why we need the whole rollup.js -const format = "iife"; -const name = "__dotnet_runtime"; const inlineAssert = [ { pattern: /mono_assert\(([^,]*), *"([^"]*)"\);/gm, @@ -86,19 +81,16 @@ const typescriptConfigOptions = { }; const outputCodePlugins = [regexReplace(inlineAssert), consts({ productVersion, configuration, monoWasmThreads, monoDiagnosticsMock, gitHash, WasmEnableLegacyJsInterop }), typescript(typescriptConfigOptions)]; +const externalDependencies = ["module"]; -const externalDependencies = [ -]; - -const iffeConfig = { +const loaderConfig = { treeshake: !isDebug, - input: "exports.ts", + input: "./loader/index.ts", output: [ { - file: nativeBinDir + "/src/es6/runtime.es6.iffe.js", - name, + format: "es", + file: nativeBinDir + "/dotnet.js", banner, - format, plugins, } ], @@ -107,7 +99,7 @@ const iffeConfig = { onwarn: onwarn }; const typesConfig = { - input: "./export-types.ts", + input: "./types/export-types.ts", output: [ { format: "es", @@ -119,6 +111,21 @@ const typesConfig = { external: externalDependencies, plugins: [dts()], }; +const runtimeConfig = { + treeshake: !isDebug, + input: "exports.ts", + output: [ + { + format: "es", + file: nativeBinDir + "/dotnet.runtime.js", + banner, + plugins, + } + ], + external: externalDependencies, + plugins: outputCodePlugins, + onwarn: onwarn +}; const legacyConfig = { input: "./net6-legacy/export-types.ts", output: [ @@ -189,7 +196,8 @@ function makeWorkerConfig(workerName, workerInputSourcePath) { const workerConfigs = findWebWorkerInputs("./workers").map((workerInput) => makeWorkerConfig(workerInput.workerName, workerInput.path)); const allConfigs = [ - iffeConfig, + loaderConfig, + runtimeConfig, typesConfig, legacyConfig, ].concat(workerConfigs) diff --git a/src/mono/wasm/runtime/roots.ts b/src/mono/wasm/runtime/roots.ts index 05b49a0b81df0e..30d0bdc0554c5e 100644 --- a/src/mono/wasm/runtime/roots.ts +++ b/src/mono/wasm/runtime/roots.ts @@ -4,7 +4,7 @@ import cwraps from "./cwraps"; import { Module } from "./globals"; import { VoidPtr, ManagedPointer, NativePointer } from "./types/emscripten"; -import { MonoObjectRef, MonoObjectRefNull, MonoObject, is_nullish, WasmRoot, WasmRootBuffer } from "./types"; +import { MonoObjectRef, MonoObjectRefNull, MonoObject, is_nullish, WasmRoot, WasmRootBuffer } from "./types/internal"; import { _zero_region } from "./memory"; const maxScratchRoots = 8192; diff --git a/src/mono/wasm/runtime/run.ts b/src/mono/wasm/runtime/run.ts index 9b92f33555e65d..bdbb2f8e7bfa82 100644 --- a/src/mono/wasm/runtime/run.ts +++ b/src/mono/wasm/runtime/run.ts @@ -1,14 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WEB, INTERNAL, Module, runtimeHelpers } from "./globals"; +import { loaderHelpers, runtimeHelpers } from "./globals"; import { mono_wasm_wait_for_debugger } from "./debug"; -import { abort_startup, mono_wasm_set_main_args } from "./startup"; +import { mono_wasm_set_main_args } from "./startup"; import cwraps from "./cwraps"; import { assembly_load } from "./class-loader"; -import { mono_assert } from "./types"; -import { consoleWebSocket, mono_wasm_stringify_as_error_with_stack } from "./logging"; -import { jiterpreter_dump_stats } from "./jiterpreter"; /** * Possible signatures are described here https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/main-command-line @@ -16,13 +13,13 @@ import { jiterpreter_dump_stats } from "./jiterpreter"; export async function mono_run_main_and_exit(main_assembly_name: string, args: string[]): Promise { try { const result = await mono_run_main(main_assembly_name, args); - mono_exit(result); + loaderHelpers.mono_exit(result); return result; } catch (error) { if (error instanceof runtimeHelpers.ExitStatus) { return error.status; } - mono_exit(1, error); + loaderHelpers.mono_exit(1, error); return 1; } } @@ -56,131 +53,3 @@ export function find_entry_point(assembly: string) { return method; } -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export function mono_on_abort(error: any): void { - abort_startup(error, false); - mono_exit(1, error); -} - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export function mono_exit(exit_code: number, reason?: any): void { - if (runtimeHelpers.config && runtimeHelpers.config.asyncFlushOnExit && exit_code === 0) { - // this would NOT call Node's exit() immediately, it's a hanging promise - (async () => { - try { - await flush_node_streams(); - } - finally { - set_exit_code_and_quit_now(exit_code, reason); - } - })(); - // we need to throw, rather than let the caller continue the normal execution - // in the middle of some code, which expects this to stop the process - throw runtimeHelpers.ExitStatus - ? new runtimeHelpers.ExitStatus(exit_code) - : reason - ? reason - : new Error("Stop with exit code " + exit_code); - } else { - set_exit_code_and_quit_now(exit_code, reason); - } -} - -async function flush_node_streams() { - try { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: - const process = await import(/* webpackIgnore: true */"process"); - const flushStream = (stream: any) => { - return new Promise((resolve, reject) => { - stream.on("error", (error: any) => reject(error)); - stream.write("", function () { resolve(); }); - }); - }; - const stderrFlushed = flushStream(process.stderr); - const stdoutFlushed = flushStream(process.stdout); - await Promise.all([stdoutFlushed, stderrFlushed]); - } catch (err) { - console.error(`flushing std* streams failed: ${err}`); - } -} - -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function set_exit_code_and_quit_now(exit_code: number, reason?: any): void { - if (runtimeHelpers.ExitStatus) { - if (reason && !(reason instanceof runtimeHelpers.ExitStatus)) { - if (!runtimeHelpers.config.logExitCode) { - if (reason instanceof Error) - Module.err(mono_wasm_stringify_as_error_with_stack(reason)); - else if (typeof reason == "string") - Module.err(reason); - else - Module.err(JSON.stringify(reason)); - } - } - else if (!reason) { - reason = new runtimeHelpers.ExitStatus(exit_code); - } else if (typeof reason.status === "number") { - exit_code = reason.status; - } - } - logErrorOnExit(exit_code, reason); - appendElementOnExit(exit_code); - if (exit_code !== 0 || !ENVIRONMENT_IS_WEB) { - if (ENVIRONMENT_IS_NODE && INTERNAL.process) { - INTERNAL.process.exit(exit_code); - throw reason; - } - else if (runtimeHelpers.quit) { - runtimeHelpers.quit(exit_code, reason); - } else { - throw reason; - } - } -} - -function appendElementOnExit(exit_code: number) { - if (ENVIRONMENT_IS_WEB && runtimeHelpers.config && runtimeHelpers.config.appendElementOnExit) { - //Tell xharness WasmBrowserTestRunner what was the exit code - const tests_done_elem = document.createElement("label"); - tests_done_elem.id = "tests_done"; - if (exit_code) tests_done_elem.style.background = "red"; - tests_done_elem.innerHTML = exit_code.toString(); - document.body.appendChild(tests_done_elem); - } -} - -function logErrorOnExit(exit_code: number, reason?: any) { - if (runtimeHelpers.config && runtimeHelpers.config.logExitCode) { - if (exit_code != 0 && reason) { - if (reason instanceof Error) - console.error(mono_wasm_stringify_as_error_with_stack(reason)); - else if (typeof reason == "string") - console.error(reason); - else - console.error(JSON.stringify(reason)); - } - if (consoleWebSocket) { - const stop_when_ws_buffer_empty = () => { - if (consoleWebSocket.bufferedAmount == 0) { - // tell xharness WasmTestMessagesProcessor we are done. - // note this sends last few bytes into the same WS - console.log("WASM EXIT " + exit_code); - } - else { - setTimeout(stop_when_ws_buffer_empty, 100); - } - }; - stop_when_ws_buffer_empty(); - } else { - console.log("WASM EXIT " + exit_code); - } - } - - try { - jiterpreter_dump_stats(false); - } catch { - // eslint-disable-next-line @typescript-eslint/no-extra-semi - ; - } -} diff --git a/src/mono/wasm/runtime/snapshot.ts b/src/mono/wasm/runtime/snapshot.ts index cf225916edeeab..5c1d109342e916 100644 --- a/src/mono/wasm/runtime/snapshot.ts +++ b/src/mono/wasm/runtime/snapshot.ts @@ -4,7 +4,7 @@ import ProductVersion from "consts:productVersion"; import GitHash from "consts:gitHash"; import MonoWasmThreads from "consts:monoWasmThreads"; -import { ENVIRONMENT_IS_WEB, runtimeHelpers } from "./globals"; +import { ENVIRONMENT_IS_WEB, loaderHelpers, runtimeHelpers } from "./globals"; const memoryPrefix = "https://dotnet.generated.invalid/wasm-memory"; @@ -140,7 +140,7 @@ async function getCacheKey(): Promise { if (!runtimeHelpers.subtle) { return null; } - const inputs = Object.assign({}, runtimeHelpers.config) as any; + const inputs = Object.assign({}, loaderHelpers.config) as any; // above already has env variables, runtime options, etc if (!inputs.assetsHash) { @@ -159,7 +159,7 @@ async function getCacheKey(): Promise { // Now we remove assets collection from the hash. delete inputs.assets; // some things are calculated at runtime, so we need to add them to the hash - inputs.preferredIcuAsset = runtimeHelpers.preferredIcuAsset; + inputs.preferredIcuAsset = loaderHelpers.preferredIcuAsset; // timezone is part of env variables, so it is already in the hash // some things are not relevant for memory snapshot diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index 1ae473cf243389..c298a79a24898f 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -1,54 +1,35 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import BuildConfiguration from "consts:configuration"; import MonoWasmThreads from "consts:monoWasmThreads"; import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop"; -import type { MonoConfig } from "./types-api"; -import type { MonoConfigInternal, DotnetModuleInternal } from "./types"; -import { mono_assert, CharPtrNull } from "./types"; -import { disableLegacyJsInterop, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, exportedRuntimeAPI, INTERNAL, Module, runtimeHelpers } from "./globals"; +import { DotnetModuleInternal, CharPtrNull } from "./types/internal"; +import { disableLegacyJsInterop, exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers } from "./globals"; import cwraps, { init_c_exports } from "./cwraps"; import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug"; import { toBase64StringImpl } from "./base64"; import { mono_wasm_init_aot_profiler, mono_wasm_init_browser_profiler } from "./profiler"; -import { mono_on_abort, mono_exit } from "./run"; import { initialize_marshalers_to_cs } from "./marshal-to-cs"; import { initialize_marshalers_to_js } from "./marshal-to-js"; import { init_polyfills_async } from "./polyfills"; import * as pthreads_worker from "./pthreads/worker"; -import { createPromiseController } from "./promise-controller"; import { string_decoder } from "./strings"; import { init_managed_exports } from "./managed-exports"; import { cwraps_internal } from "./exports-internal"; import { CharPtr, InstantiateWasmCallBack, InstantiateWasmSuccessCallback } from "./types/emscripten"; -import { instantiate_wasm_asset, mono_download_assets, resolve_asset_path, start_asset_download, wait_for_all_assets } from "./assets"; +import { instantiate_wasm_asset, wait_for_all_assets } from "./assets"; import { mono_wasm_init_diagnostics } from "./diagnostics"; import { preAllocatePThreadWorkerPool, instantiateWasmPThreadWorkerPool } from "./pthreads/browser"; import { export_linker } from "./exports-linker"; import { endMeasure, MeasuredBlock, startMeasure } from "./profiler"; import { getMemorySnapshot, storeMemorySnapshot, getMemorySnapshotSize } from "./snapshot"; -import { loadBootConfig } from "./blazor/_Integration"; // legacy import { init_legacy_exports } from "./net6-legacy/corebindings"; import { cwraps_binding_api, cwraps_mono_api } from "./net6-legacy/exports-legacy"; import { BINDING, MONO } from "./net6-legacy/globals"; -import { init_globalization } from "./icu"; - -let config: MonoConfigInternal = undefined as any; -let configLoaded = false; -export const dotnetReady = createPromiseController(); -export const afterConfigLoaded = createPromiseController(); -export const memorySnapshotSkippedOrDone = createPromiseController(); -export const afterInstantiateWasm = createPromiseController(); -export const beforePreInit = createPromiseController(); -export const afterPreInit = createPromiseController(); -export const afterPreRun = createPromiseController(); -export const beforeOnRuntimeInitialized = createPromiseController(); -export const afterOnRuntimeInitialized = createPromiseController(); -export const afterPostRun = createPromiseController(); + // default size if MonoConfig.pthreadPoolSize is undefined const MONO_PTHREAD_POOL_SIZE = 4; @@ -58,14 +39,9 @@ const MONO_PTHREAD_POOL_SIZE = 4; export function configureEmscriptenStartup(module: DotnetModuleInternal): void { const mark = startMeasure(); - if (!module.configSrc && (!module.config || Object.keys(module.config).length === 0 || !module.config.assets)) { - // if config file location nor assets are provided - module.configSrc = "./mono-config.json"; - } - - if (!module["locateFile"]) { + if (!module.locateFile) { // this is dummy plug so that wasmBinaryFile doesn't try to use URL class - module["locateFile"] = module["__locateFile"] = (path) => runtimeHelpers.scriptDirectory + path; + module.locateFile = module.__locateFile = (path) => loaderHelpers.scriptDirectory + path; } if (!module.out) { @@ -75,6 +51,8 @@ export function configureEmscriptenStartup(module: DotnetModuleInternal): void { if (!module.err) { module.err = console.error.bind(console); } + loaderHelpers.out = module.out; + loaderHelpers.err = module.err; // these all could be overridden on DotnetModuleConfig, we are chaing them to async below, as opposed to emscripten // when user set configSrc or config, we are running our default startup sequence. @@ -86,7 +64,7 @@ export function configureEmscriptenStartup(module: DotnetModuleInternal): void { const userOnRuntimeInitialized: () => void = module.onRuntimeInitialized ? module.onRuntimeInitialized : () => { }; // execution order == [0] == - // - default or user Module.instantiateWasm (will start downloading dotnet.wasm) + // - default or user Module.instantiateWasm (will start downloading dotnet.native.wasm) module.instantiateWasm = (imports, callback) => instantiateWasm(imports, callback, userInstantiateWasm); // execution order == [1] == module.preInit = [() => preInit(userPreInit)]; @@ -100,20 +78,23 @@ export function configureEmscriptenStartup(module: DotnetModuleInternal): void { module.ready.then(async () => { // wait for previous stage - await afterPostRun.promise; + await runtimeHelpers.afterPostRun.promise; // startup end endMeasure(mark, MeasuredBlock.emscriptenStartup); // - here we resolve the promise returned by createDotnetRuntime export // - any code after createDotnetRuntime is executed now - dotnetReady.promise_control.resolve(exportedRuntimeAPI); + runtimeHelpers.dotnetReady.promise_control.resolve(exportedRuntimeAPI); runtimeHelpers.runtimeReady = true; }).catch(err => { - dotnetReady.promise_control.reject(err); + runtimeHelpers.dotnetReady.promise_control.reject(err); }); - module.ready = dotnetReady.promise; + module.ready = runtimeHelpers.dotnetReady.promise; // execution order == [*] == if (!module.onAbort) { - module.onAbort = () => mono_on_abort; + module.onAbort = (error) => { + loaderHelpers.abort_startup(error, false); + loaderHelpers.mono_exit(1, error); + }; } } @@ -123,19 +104,13 @@ function instantiateWasm( userInstantiateWasm?: InstantiateWasmCallBack): any[] { // this is called so early that even Module exports like addRunDependency don't exist yet - if (!Module.configSrc && !Module.config && !userInstantiateWasm) { - Module.out("MONO_WASM: configSrc nor config was specified"); - } - normalizeConfig(); - const mark = startMeasure(); if (userInstantiateWasm) { - init_globalization(); // user wasm instantiation doesn't support memory snapshots - memorySnapshotSkippedOrDone.promise_control.resolve(); + runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); const exports = userInstantiateWasm(imports, (instance: WebAssembly.Instance, module: WebAssembly.Module | undefined) => { endMeasure(mark, MeasuredBlock.instantiateWasm); - afterInstantiateWasm.promise_control.resolve(); + runtimeHelpers.afterInstantiateWasm.promise_control.resolve(); successCallback(instance, module); }); return exports; @@ -150,9 +125,8 @@ async function instantiateWasmWorker( successCallback: InstantiateWasmSuccessCallback ): Promise { // wait for the config to arrive by message from the main thread - await afterConfigLoaded.promise; + await loaderHelpers.afterConfigLoaded.promise; - normalizeConfig(); replace_linker_placeholders(imports, export_linker()); // Instantiate from the module posted from the main thread. @@ -167,13 +141,13 @@ function preInit(userPreInit: (() => void)[]) { const mark = startMeasure(); try { mono_wasm_pre_init_essential(false); - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: preInit"); - beforePreInit.promise_control.resolve(); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: preInit"); + runtimeHelpers.beforePreInit.promise_control.resolve(); // all user Module.preInit callbacks userPreInit.forEach(fn => fn()); } catch (err) { _print_error("MONO_WASM: user preInint() failed", err); - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } // this will start immediately but return on first await. @@ -190,11 +164,11 @@ function preInit(userPreInit: (() => void)[]) { endMeasure(mark, MeasuredBlock.preInit); } catch (err) { - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } // signal next stage - afterPreInit.promise_control.resolve(); + runtimeHelpers.afterPreInit.promise_control.resolve(); Module.removeRunDependency("mono_pre_init"); })(); } @@ -203,15 +177,15 @@ async function preInitWorkerAsync() { console.debug("MONO_WASM: worker initializing essential C exports and APIs"); const mark = startMeasure(); try { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: preInitWorker"); - beforePreInit.promise_control.resolve(); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: preInitWorker"); + runtimeHelpers.beforePreInit.promise_control.resolve(); mono_wasm_pre_init_essential(true); await init_polyfills_async(); - afterPreInit.promise_control.resolve(); + runtimeHelpers.afterPreInit.promise_control.resolve(); endMeasure(mark, MeasuredBlock.preInitWorker); } catch (err) { _print_error("MONO_WASM: user preInitWorker() failed", err); - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } } @@ -222,66 +196,66 @@ export function preRunWorker() { bindings_init(); endMeasure(mark, MeasuredBlock.preRunWorker); } catch (err) { - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } // signal next stage - afterPreRun.promise_control.resolve(); + runtimeHelpers.afterPreRun.promise_control.resolve(); } async function preRunAsync(userPreRun: (() => void)[]) { Module.addRunDependency("mono_pre_run_async"); // wait for previous stages try { - await afterInstantiateWasm.promise; - await afterPreInit.promise; - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: preRunAsync"); + await runtimeHelpers.afterInstantiateWasm.promise; + await runtimeHelpers.afterPreInit.promise; + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: preRunAsync"); const mark = startMeasure(); // all user Module.preRun callbacks userPreRun.map(fn => fn()); endMeasure(mark, MeasuredBlock.preRun); } catch (err) { _print_error("MONO_WASM: user callback preRun() failed", err); - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } // signal next stage - afterPreRun.promise_control.resolve(); + runtimeHelpers.afterPreRun.promise_control.resolve(); Module.removeRunDependency("mono_pre_run_async"); } async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { try { // wait for previous stage - await afterPreRun.promise; - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: onRuntimeInitialized"); + await runtimeHelpers.afterPreRun.promise; + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: onRuntimeInitialized"); const mark = startMeasure(); // signal this stage, this will allow pending assets to allocate memory - beforeOnRuntimeInitialized.promise_control.resolve(); + runtimeHelpers.beforeOnRuntimeInitialized.promise_control.resolve(); await wait_for_all_assets(); // Diagnostics early are not supported with memory snapshot. See below how we enable them later. // Please disable startupMemoryCache in order to be able to diagnose or pause runtime startup. - if (MonoWasmThreads && !config.startupMemoryCache) { + if (MonoWasmThreads && !loaderHelpers.config.startupMemoryCache) { await mono_wasm_init_diagnostics(); } // load runtime and apply environment settings (if necessary) await mono_wasm_before_memory_snapshot(); - if (config.exitAfterSnapshot) { + if (loaderHelpers.config.exitAfterSnapshot) { const reason = runtimeHelpers.ExitStatus ? new runtimeHelpers.ExitStatus(0) : new Error("Snapshot taken, exiting because exitAfterSnapshot was set."); reason.silent = true; - abort_startup(reason, false); + loaderHelpers.abort_startup(reason, false); return; } if (MonoWasmThreads) { - if (config.startupMemoryCache) { + if (loaderHelpers.config.startupMemoryCache) { // we could enable diagnostics after the snapshot is taken await mono_wasm_init_diagnostics(); } @@ -296,7 +270,7 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { string_decoder.init_fields(); }); - if (config.startupOptions && INTERNAL.resourceLoader) { + if (loaderHelpers.config.startupOptions && INTERNAL.resourceLoader) { if (INTERNAL.resourceLoader.bootConfig.debugBuild && INTERNAL.resourceLoader.bootConfig.cacheBootResources) { INTERNAL.resourceLoader.logToConsole(); } @@ -316,18 +290,18 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { endMeasure(mark, MeasuredBlock.onRuntimeInitialized); } catch (err) { _print_error("MONO_WASM: onRuntimeInitializedAsync() failed", err); - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } // signal next stage - afterOnRuntimeInitialized.promise_control.resolve(); + runtimeHelpers.afterOnRuntimeInitialized.promise_control.resolve(); } async function postRunAsync(userpostRun: (() => void)[]) { // wait for previous stage try { - await afterOnRuntimeInitialized.promise; - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: postRunAsync"); + await runtimeHelpers.afterOnRuntimeInitialized.promise; + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: postRunAsync"); const mark = startMeasure(); // create /usr/share folder which is SpecialFolder.CommonApplicationData @@ -339,42 +313,19 @@ async function postRunAsync(userpostRun: (() => void)[]) { endMeasure(mark, MeasuredBlock.postRun); } catch (err) { _print_error("MONO_WASM: user callback posRun() failed", err); - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } // signal next stage - afterPostRun.promise_control.resolve(); + runtimeHelpers.afterPostRun.promise_control.resolve(); } -// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export function abort_startup(reason: any, should_exit: boolean): void { - if (runtimeHelpers.diagnosticTracing) console.trace("MONO_WASM: abort_startup"); - dotnetReady.promise_control.reject(reason); - memorySnapshotSkippedOrDone.promise_control.reject(reason); - afterInstantiateWasm.promise_control.reject(reason); - beforePreInit.promise_control.reject(reason); - afterPreInit.promise_control.reject(reason); - afterPreRun.promise_control.reject(reason); - beforeOnRuntimeInitialized.promise_control.reject(reason); - afterOnRuntimeInitialized.promise_control.reject(reason); - afterPostRun.promise_control.reject(reason); - if (typeof reason !== "object" || reason.silent !== true) { - if (should_exit) { - mono_exit(1, reason); - } - else if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { - const wasm_exit = cwraps.mono_wasm_exit; - wasm_exit(1); - } - throw reason; - } -} function mono_wasm_pre_init_essential(isWorker: boolean): void { if (!isWorker) Module.addRunDependency("mono_wasm_pre_init_essential"); - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential"); init_c_exports(); cwraps_internal(INTERNAL); @@ -384,7 +335,7 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void { } // removeRunDependency triggers the dependenciesFulfilled callback (runCaller) in // emscripten - on a worker since we don't have any other dependencies that causes run() to get - // called too soon; and then it will get called a second time when dotnet.js calls it directly. + // called too soon; and then it will get called a second time when dotnet.native.js calls it directly. // on a worker run() short-cirtcuits and just calls readyPromiseResolve, initRuntime and postMessage. // sending postMessage twice will break instantiateWasmPThreadWorkerPool on the main thread. if (!isWorker) @@ -392,30 +343,29 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void { } async function mono_wasm_pre_init_essential_async(): Promise { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential_async"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential_async"); Module.addRunDependency("mono_wasm_pre_init_essential_async"); await init_polyfills_async(); - await mono_wasm_load_config(Module.configSrc); if (MonoWasmThreads) { - preAllocatePThreadWorkerPool(MONO_PTHREAD_POOL_SIZE, config); + preAllocatePThreadWorkerPool(MONO_PTHREAD_POOL_SIZE, loaderHelpers.config); } Module.removeRunDependency("mono_wasm_pre_init_essential_async"); } async function mono_wasm_pre_init_full(): Promise { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_full"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_full"); Module.addRunDependency("mono_wasm_pre_init_full"); - await mono_download_assets(); + await loaderHelpers.mono_download_assets(); Module.removeRunDependency("mono_wasm_pre_init_full"); } async function mono_wasm_after_user_runtime_initialized(): Promise { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_after_user_runtime_initialized"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_after_user_runtime_initialized"); try { if (!Module.disableDotnet6Compatibility && Module.exports) { // Export emscripten defined in module through EXPORTED_RUNTIME_METHODS @@ -435,7 +385,7 @@ async function mono_wasm_after_user_runtime_initialized(): Promise { } } - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: Initializing mono runtime"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: Initializing mono runtime"); if (Module.onDotnetReady) { try { @@ -509,36 +459,30 @@ async function instantiate_wasm_module( // this is called so early that even Module exports like addRunDependency don't exist yet try { let memorySize: number | undefined = undefined; - await mono_wasm_load_config(Module.configSrc); - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module"); - const assetToLoad = resolve_asset_path("dotnetwasm"); - // FIXME: this would not apply re-try (on connection reset during download) for dotnet.wasm because we could not download the buffer before we pass it to instantiate_wasm_asset - const wasmDownloadPromise = start_asset_download(assetToLoad); - - // this is right time as we have free CPU time to do this - init_globalization(); + await loaderHelpers.afterConfigLoaded; + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module"); - if (config.startupMemoryCache) { + if (loaderHelpers.config.startupMemoryCache) { memorySize = await getMemorySnapshotSize(); runtimeHelpers.loadedMemorySnapshot = !!memorySize; runtimeHelpers.storeMemorySnapshotPending = !runtimeHelpers.loadedMemorySnapshot; } if (!runtimeHelpers.loadedMemorySnapshot) { // we should start downloading DLLs etc as they are not in the snapshot - memorySnapshotSkippedOrDone.promise_control.resolve(); + runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); } - await wasmDownloadPromise; - await beforePreInit.promise; + await runtimeHelpers.beforePreInit.promise; Module.addRunDependency("instantiate_wasm_module"); replace_linker_placeholders(imports, export_linker()); + const assetToLoad = await loaderHelpers.wasmDownloadPromise.promise; await instantiate_wasm_asset(assetToLoad, imports, successCallback); assetToLoad.pendingDownloadInternal = null as any; // GC assetToLoad.pendingDownload = null as any; // GC assetToLoad.buffer = null as any; // GC - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module done"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module done"); if (runtimeHelpers.loadedMemorySnapshot) { try { @@ -552,12 +496,12 @@ async function instantiate_wasm_module( runtimeHelpers.loadedMemorySnapshot = false; } // now we know if the loading of memory succeeded or not, we can start loading the rest of the assets - memorySnapshotSkippedOrDone.promise_control.resolve(); + runtimeHelpers.memorySnapshotSkippedOrDone.promise_control.resolve(); } - afterInstantiateWasm.promise_control.resolve(); + runtimeHelpers.afterInstantiateWasm.promise_control.resolve(); } catch (err) { _print_error("MONO_WASM: instantiate_wasm_module() failed", err); - abort_startup(err, true); + loaderHelpers.abort_startup(err, true); throw err; } Module.removeRunDependency("instantiate_wasm_module"); @@ -570,36 +514,36 @@ async function mono_wasm_before_memory_snapshot() { const memoryBytes = await getMemorySnapshot(); mono_assert(memoryBytes!.byteLength === Module.HEAP8.byteLength, "MONO_WASM: Loaded memory is not the expected size"); Module.HEAP8.set(new Int8Array(memoryBytes!), 0); - if (runtimeHelpers.diagnosticTracing) console.info("MONO_WASM: Loaded WASM linear memory from browser cache"); + if (loaderHelpers.diagnosticTracing) console.info("MONO_WASM: Loaded WASM linear memory from browser cache"); // all things below are loaded from the snapshot return; } - for (const k in config.environmentVariables) { - const v = config.environmentVariables![k]; + for (const k in loaderHelpers.config.environmentVariables) { + const v = loaderHelpers.config.environmentVariables![k]; if (typeof (v) === "string") mono_wasm_setenv(k, v); else throw new Error(`Expected environment variable '${k}' to be a string but it was ${typeof v}: '${v}'`); } - if (config.startupMemoryCache) { + if (loaderHelpers.config.startupMemoryCache) { // disable the trampoline for now, we will re-enable it after we stored the snapshot cwraps.mono_jiterp_update_jit_call_dispatcher(0); } - if (config.runtimeOptions) - mono_wasm_set_runtime_options(config.runtimeOptions); + if (loaderHelpers.config.runtimeOptions) + mono_wasm_set_runtime_options(loaderHelpers.config.runtimeOptions); - if (config.aotProfilerOptions) - mono_wasm_init_aot_profiler(config.aotProfilerOptions); + if (loaderHelpers.config.aotProfilerOptions) + mono_wasm_init_aot_profiler(loaderHelpers.config.aotProfilerOptions); - if (config.browserProfilerOptions) - mono_wasm_init_browser_profiler(config.browserProfilerOptions); + if (loaderHelpers.config.browserProfilerOptions) + mono_wasm_init_browser_profiler(loaderHelpers.config.browserProfilerOptions); - mono_wasm_load_runtime("unused", config.debugLevel); + mono_wasm_load_runtime("unused", loaderHelpers.config.debugLevel); // we didn't have snapshot yet and the feature is enabled. Take snapshot now. - if (config.startupMemoryCache) { + if (loaderHelpers.config.startupMemoryCache) { // this would install the mono_jiterp_do_jit_call_indirect cwraps.mono_jiterp_update_jit_call_dispatcher(-1); await storeMemorySnapshot(Module.HEAP8.buffer); @@ -610,12 +554,12 @@ async function mono_wasm_before_memory_snapshot() { } export function mono_wasm_load_runtime(unused?: string, debugLevel?: number): void { - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_load_runtime"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_load_runtime"); try { const mark = startMeasure(); if (debugLevel == undefined) { debugLevel = 0; - if (config && config.debugLevel) { + if (loaderHelpers.config.debugLevel) { debugLevel = 0 + debugLevel; } } @@ -624,7 +568,7 @@ export function mono_wasm_load_runtime(unused?: string, debugLevel?: number): vo } catch (err: any) { _print_error("MONO_WASM: mono_wasm_load_runtime () failed", err); - abort_startup(err, false); + loaderHelpers.abort_startup(err, false); } } @@ -632,7 +576,7 @@ export function bindings_init(): void { if (runtimeHelpers.mono_wasm_bindings_is_ready) { return; } - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: bindings_init"); + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: bindings_init"); runtimeHelpers.mono_wasm_bindings_is_ready = true; try { const mark = startMeasure(); @@ -650,91 +594,6 @@ export function bindings_init(): void { } } -/** - * Loads the mono config file (typically called mono-config.json) asynchroniously - * Note: the run dependencies are so emsdk actually awaits it in order. - * - * @param {string} configFilePath - relative path to the config file - * @throws Will throw an error if the config file loading fails - */ -export async function mono_wasm_load_config(configFilePath?: string): Promise { - if (configLoaded) { - await afterConfigLoaded.promise; - return; - } - configLoaded = true; - if (!configFilePath) { - normalizeConfig(); - afterConfigLoaded.promise_control.resolve(config); - return; - } - if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_load_config"); - try { - if (config.startupOptions) { - await loadBootConfig(config); - } else { - const resolveSrc = runtimeHelpers.locateFile(configFilePath); - const configResponse = await runtimeHelpers.fetch_like(resolveSrc); - const loadedConfig: MonoConfigInternal = (await configResponse.json()) || {}; - if (loadedConfig.environmentVariables && typeof (loadedConfig.environmentVariables) !== "object") - throw new Error("Expected config.environmentVariables to be unset or a dictionary-style object"); - - // merge - loadedConfig.assets = [...(loadedConfig.assets || []), ...(config.assets || [])]; - loadedConfig.environmentVariables = { ...(loadedConfig.environmentVariables || {}), ...(config.environmentVariables || {}) }; - loadedConfig.runtimeOptions = [...(loadedConfig.runtimeOptions || []), ...(config.runtimeOptions || [])]; - config = runtimeHelpers.config = Module.config = Object.assign(Module.config as any, loadedConfig); - } - - normalizeConfig(); - - if (Module.onConfigLoaded) { - try { - await Module.onConfigLoaded(config, exportedRuntimeAPI); - normalizeConfig(); - } - catch (err: any) { - _print_error("MONO_WASM: onConfigLoaded() failed", err); - throw err; - } - } - afterConfigLoaded.promise_control.resolve(config); - } catch (err) { - const errMessage = `Failed to load config file ${configFilePath} ${err}`; - config = runtimeHelpers.config = Module.config = { message: errMessage, error: err, isError: true }; - abort_startup(errMessage, true); - throw err; - } -} - -function normalizeConfig() { - // normalize - Module.config = config = runtimeHelpers.config = Object.assign(runtimeHelpers.config, Module.config || {}); - - config.environmentVariables = config.environmentVariables || {}; - config.assets = config.assets || []; - config.runtimeOptions = config.runtimeOptions || []; - config.globalizationMode = config.globalizationMode || "auto"; - - if (config.debugLevel === undefined && BuildConfiguration === "Debug") { - config.debugLevel = -1; - } - if (config.diagnosticTracing === undefined && BuildConfiguration === "Debug") { - config.diagnosticTracing = true; - } - runtimeHelpers.diagnosticTracing = !!config.diagnosticTracing; - runtimeHelpers.waitForDebugger = config.waitForDebugger; - config.startupMemoryCache = !!config.startupMemoryCache; - if (config.startupMemoryCache && runtimeHelpers.waitForDebugger) { - if (runtimeHelpers.diagnosticTracing) console.info("MONO_WASM: Disabling startupMemoryCache because waitForDebugger is set"); - config.startupMemoryCache = false; - } - - runtimeHelpers.enablePerfMeasure = !!config.browserProfilerOptions - && globalThis.performance - && typeof globalThis.performance.measure === "function"; - -} export function mono_wasm_asm_loaded(assembly_name: CharPtr, assembly_ptr: number, assembly_len: number, pdb_ptr: number, pdb_len: number): void { // Only trigger this codepath for assemblies loaded after app is ready @@ -783,12 +642,12 @@ export async function configureWorkerStartup(module: DotnetModuleInternal): Prom pthreads_worker.setupPreloadChannelToMainThread(); // This is a good place for subsystems to attach listeners for pthreads_worker.currentWorkerThreadEvents pthreads_worker.currentWorkerThreadEvents.addEventListener(pthreads_worker.dotnetPthreadCreated, (ev) => { - if (runtimeHelpers.diagnosticTracing) + if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: pthread created 0x" + ev.pthread_self.pthread_id.toString(16)); }); // these are the only events which are called on worker module.preInit = [() => preInitWorkerAsync()]; module.instantiateWasm = instantiateWasmWorker; - await afterPreInit.promise; + await runtimeHelpers.afterPreInit.promise; } diff --git a/src/mono/wasm/runtime/strings.ts b/src/mono/wasm/runtime/strings.ts index 9ec559ff219997..52f6c8dbbe3732 100644 --- a/src/mono/wasm/runtime/strings.ts +++ b/src/mono/wasm/runtime/strings.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import { mono_wasm_new_root_buffer } from "./roots"; -import { MonoString, MonoStringNull, is_nullish, WasmRoot, WasmRootBuffer } from "./types"; +import { MonoString, MonoStringNull, is_nullish, WasmRoot, WasmRootBuffer } from "./types/internal"; import { Module } from "./globals"; import cwraps from "./cwraps"; import { mono_wasm_new_root } from "./roots"; diff --git a/src/mono/wasm/runtime/types/blazor.ts b/src/mono/wasm/runtime/types/blazor.ts new file mode 100644 index 00000000000000..95f88fd1017754 --- /dev/null +++ b/src/mono/wasm/runtime/types/blazor.ts @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Keep in sync with Microsoft.NET.Sdk.WebAssembly.BootJsonData from the WasmSDK +export interface BootJsonData { + readonly entryAssembly: string; + readonly resources: ResourceGroups; + /** Gets a value that determines if this boot config was produced from a non-published build (i.e. dotnet build or dotnet run) */ + readonly debugBuild: boolean; + readonly linkerEnabled: boolean; + readonly cacheBootResources: boolean; + readonly config: string[]; + readonly icuDataMode: ICUDataMode; + readonly startupMemoryCache: boolean | undefined; + readonly runtimeOptions: string[] | undefined; + + // These properties are tacked on, and not found in the boot.json file + modifiableAssemblies: string | null; + aspnetCoreBrowserTools: string | null; +} + +export type BootJsonDataExtension = { [extensionName: string]: ResourceList }; + +export interface ResourceGroups { + readonly assembly: ResourceList; + readonly lazyAssembly: ResourceList; + readonly pdb?: ResourceList; + readonly runtime: ResourceList; + readonly satelliteResources?: { [cultureName: string]: ResourceList }; + readonly libraryInitializers?: ResourceList, + readonly extensions?: BootJsonDataExtension + readonly runtimeAssets: ExtendedResourceList; +} + +export type ResourceList = { [name: string]: string }; +export type ExtendedResourceList = { + [name: string]: { + hash: string, + behavior: string + } +}; + +export enum ICUDataMode { + Sharded = 0, + All = 1, + Invariant = 2, + Custom = 3 +} diff --git a/src/mono/wasm/runtime/types/consts.d.ts b/src/mono/wasm/runtime/types/consts.d.ts index 11a7e5439e3110..a86668b13fa8af 100644 --- a/src/mono/wasm/runtime/types/consts.d.ts +++ b/src/mono/wasm/runtime/types/consts.d.ts @@ -18,4 +18,6 @@ declare module "consts:monoDiagnosticsMock" { export default constant; } -declare function createEmscripten(module: any): Promise; +// see src\mono\wasm\runtime\rollup.config.js +// inline this, because the lambda could allocate closure on hot path otherwise +declare function mono_assert(condition: unknown, messageFactory: string | (() => string)): asserts condition; diff --git a/src/mono/wasm/runtime/export-types.ts b/src/mono/wasm/runtime/types/export-types.ts similarity index 80% rename from src/mono/wasm/runtime/export-types.ts rename to src/mono/wasm/runtime/types/export-types.ts index f81661e365e1f7..379b817aa95852 100644 --- a/src/mono/wasm/runtime/export-types.ts +++ b/src/mono/wasm/runtime/types/export-types.ts @@ -1,11 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import type { BootJsonData, ICUDataMode } from "./blazor/BootConfig"; -import type { IMemoryView } from "./marshal"; -import type { CreateDotnetRuntimeType, DotnetModuleConfig, RuntimeAPI, MonoConfig, ModuleAPI, AssetEntry, ResourceRequest } from "./types-api"; -import type { EmscriptenModule } from "./types/emscripten"; -import type { dotnet, exit } from "./exports"; +import type { IMemoryView } from "../marshal"; +import type { CreateDotnetRuntimeType, DotnetModuleConfig, RuntimeAPI, MonoConfig, ModuleAPI, AssetEntry, ResourceRequest } from "."; +import type { EmscriptenModule } from "./emscripten"; +import type { dotnet, exit } from "../loader/index"; +import type { BootJsonData, ICUDataMode } from "./blazor"; // ----------------------------------------------------------- // this files has all public exports from the dotnet.js module diff --git a/src/mono/wasm/runtime/types-api.ts b/src/mono/wasm/runtime/types/index.ts similarity index 96% rename from src/mono/wasm/runtime/types-api.ts rename to src/mono/wasm/runtime/types/index.ts index 3fd1c327e0c1d7..de166381096d11 100644 --- a/src/mono/wasm/runtime/types-api.ts +++ b/src/mono/wasm/runtime/types/index.ts @@ -1,4 +1,7 @@ -import type { EmscriptenModule, NativePointer } from "./types/emscripten"; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +import type { EmscriptenModule, NativePointer } from "./emscripten"; export interface DotnetHostBuilder { withConfig(config: MonoConfig): DotnetHostBuilder @@ -134,6 +137,9 @@ export type AssetBehaviours = | "vfs" // load asset into the virtual filesystem (for fopen, File.Open, etc) | "dotnetwasm" // the binary of the dotnet runtime | "js-module-threads" // the javascript module for threads + | "js-module-runtime" // the javascript module for threads + | "js-module-dotnet" // the javascript module for threads + | "js-module-native" // the javascript module for threads | "symbols" // the javascript module for threads export type GlobalizationMode = diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types/internal.ts similarity index 77% rename from src/mono/wasm/runtime/types.ts rename to src/mono/wasm/runtime/types/internal.ts index 3f1c811dceccb0..a77c577f645d85 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types/internal.ts @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { AssetEntry, DotnetModuleConfig, LoadingResource, MonoConfig, RuntimeAPI, WebAssemblyStartOptions } from "./types-api"; -import { CharPtr, EmscriptenModule, ManagedPointer, NativePointer, VoidPtr, Int32Ptr } from "./types/emscripten"; +import type { AssetBehaviours, AssetEntry, DotnetModuleConfig, LoadingResource, MonoConfig, ResourceRequest, RuntimeAPI, WebAssemblyStartOptions } from "."; +import type { CharPtr, EmscriptenModule, ManagedPointer, NativePointer, VoidPtr, Int32Ptr } from "./emscripten"; export type GCHandle = { __brand: "GCHandle" @@ -92,17 +92,45 @@ export interface AssetEntryInternal extends AssetEntry { pendingDownloadInternal?: LoadingResource } -export type AssetBehaviours = - "resource" // load asset as a managed resource assembly - | "assembly" // load asset as a managed assembly - | "pdb" // load asset as a managed debugging information - | "heap" // store asset into the native heap - | "icu" // load asset as an ICU data archive - | "vfs" // load asset into the virtual filesystem (for fopen, File.Open, etc) - | "dotnetwasm" // the binary of the dotnet runtime - | "js-module-threads" // the javascript module for threads - | "symbols" // the symbols for the wasm native code +export type LoaderHelpers = { + config: MonoConfigInternal; + diagnosticTracing: boolean; + + maxParallelDownloads: number; + enableDownloadRetry: boolean; + + loadedFiles: string[], + _loaded_files: { url: string, file: string }[]; + scriptDirectory: string + scriptUrl: string + preferredIcuAsset: string | null, + invariantMode: boolean, + actual_downloaded_assets_count: number, + actual_instantiated_assets_count: number, + expected_downloaded_assets_count: number, + expected_instantiated_assets_count: number, + + afterConfigLoaded: PromiseAndController, + allDownloadsQueued: PromiseAndController, + wasmDownloadPromise: PromiseAndController, + runtimeModuleLoaded: PromiseAndController, + + abort_startup: (reason: any, should_exit: boolean) => void, + mono_exit: (exit_code: number, reason?: any) => void, + createPromiseController: (afterResolve?: () => void, afterReject?: () => void) => PromiseAndController, + getPromiseController: (promise: ControllablePromise) => PromiseController, + assertIsControllablePromise: (promise: Promise) => asserts promise is ControllablePromise, + mono_download_assets: () => Promise, + resolve_asset_path: (behavior: AssetBehaviours) => AssetEntryInternal, + setup_proxy_console: (id: string, console: Console, origin: string) => void + fetch_like: (url: string, init?: RequestInit) => Promise; + locateFile: (path: string, prefix?: string) => string, + downloadResource?: (request: ResourceRequest) => LoadingResource | undefined + out(message: string): void; + err(message: string): void; + getApplicationEnvironment?: (bootConfigResponse: Response) => string | null; +} export type RuntimeHelpers = { runtime_interop_module: MonoAssembly; runtime_interop_namespace: string; @@ -113,29 +141,34 @@ export type RuntimeHelpers = { mono_wasm_runtime_is_ready: boolean; mono_wasm_bindings_is_ready: boolean; - loaded_files: string[]; - maxParallelDownloads: number; - enableDownloadRetry: boolean; - config: MonoConfigInternal; - diagnosticTracing: boolean; + loadedMemorySnapshot: boolean, enablePerfMeasure: boolean; waitForDebugger?: number; - fetch_like: (url: string, init?: RequestInit) => Promise; - scriptDirectory: string - requirePromise: Promise ExitStatus: ExitStatusError; quit: Function, - locateFile: (path: string, prefix?: string) => string, javaScriptExports: JavaScriptExports, - loadedFiles: string[], - loadedMemorySnapshot: boolean, storeMemorySnapshotPending: boolean, memorySnapshotCacheKey: string, subtle: SubtleCrypto | null, - preferredIcuAsset: string | null, - invariantMode: boolean, updateMemoryViews: () => void runtimeReady: boolean, + + allAssetsInMemory: PromiseAndController, + dotnetReady: PromiseAndController, + memorySnapshotSkippedOrDone: PromiseAndController, + afterInstantiateWasm: PromiseAndController, + beforePreInit: PromiseAndController, + afterPreInit: PromiseAndController, + afterPreRun: PromiseAndController, + beforeOnRuntimeInitialized: PromiseAndController, + afterOnRuntimeInitialized: PromiseAndController, + afterPostRun: PromiseAndController, + + //core + stringify_as_error_with_stack?: (error: any) => string, + instantiate_asset: (asset: AssetEntry, url: string, bytes: Uint8Array) => void, + instantiate_symbols_asset: (pendingAsset: AssetEntryInternal) => Promise, + jiterpreter_dump_stats?: (x: boolean) => string, } export type AOTProfilerOptions = { @@ -150,38 +183,6 @@ export type BrowserProfilerOptions = { export type DotnetModule = EmscriptenModule & DotnetModuleConfig; export type DotnetModuleInternal = EmscriptenModule & DotnetModuleConfig & EmscriptenModuleInternal; - -export type DotnetModuleConfigImports = { - require?: (name: string) => any; - fetch?: (url: string, options: any | undefined) => Promise; - fs?: { - promises?: { - readFile?: (path: string) => Promise, - } - readFileSync?: (path: string, options: any | undefined) => string, - }; - crypto?: { - randomBytes?: (size: number) => Buffer - }; - ws?: WebSocket & { Server: any }; - path?: { - normalize?: (path: string) => string, - dirname?: (path: string) => string, - }; - url?: any; -} - -// see src\mono\wasm\runtime\rollup.config.js -// inline this, because the lambda could allocate closure on hot path otherwise -export function mono_assert(condition: unknown, messageFactory: string | (() => string)): asserts condition { - if (!condition) { - const message = typeof messageFactory === "string" - ? messageFactory - : messageFactory(); - throw new Error(`Assert failed: ${message}`); - } -} - // see src/mono/wasm/driver.c MARSHAL_TYPE_xxx and Runtime.cs MarshalType export const enum MarshalType { NULL = 0, @@ -233,26 +234,23 @@ export function is_nullish(value: T | null | undefined): value is null | unde } export type EmscriptenInternals = { - isWorker: boolean, - isShell: boolean, isPThread: boolean, disableLegacyJsInterop: boolean, quit_: Function, ExitStatus: ExitStatusError, - requirePromise: Promise }; export type GlobalObjects = { mono: any, binding: any, internal: any, module: DotnetModuleInternal, - helpers: RuntimeHelpers, + loaderHelpers: LoaderHelpers, + runtimeHelpers: RuntimeHelpers, api: RuntimeAPI, }; export type EmscriptenReplacements = { fetch: any, require: any, - requirePromise: Promise, updateMemoryViews: Function, pthreadReplacements: PThreadReplacements | undefined | null scriptDirectory: string; @@ -410,3 +408,32 @@ export declare interface EmscriptenModuleInternal { addRunDependency(id: string): void; onConfigLoaded?: (config: MonoConfig, api: RuntimeAPI) => void | Promise; } + +/// A PromiseController encapsulates a Promise together with easy access to its resolve and reject functions. +/// It's a bit like a TaskCompletionSource in .NET +export interface PromiseController { + isDone: boolean; + readonly promise: Promise; + resolve: (value: T | PromiseLike) => void; + reject: (reason?: any) => void; +} + + +/// A Promise with a controller attached +export interface ControllablePromise extends Promise { + __brand: "ControllablePromise" +} + +/// Just a pair of a promise and its controller +export interface PromiseAndController { + promise: ControllablePromise; + promise_control: PromiseController; +} + +export type passEmscriptenInternalsType = (internals: EmscriptenInternals) => void; +export type setGlobalObjectsType = (globalObjects: GlobalObjects) => void; +export type initializeExportsType = (globalObjects: GlobalObjects) => RuntimeAPI; +export type initializeReplacementsType = (replacements: EmscriptenReplacements) => void; +export type configureEmscriptenStartupType = (module: DotnetModuleInternal) => void; +export type configureWorkerStartupType = (module: DotnetModuleInternal) => Promise + diff --git a/src/mono/wasm/runtime/web-socket.ts b/src/mono/wasm/runtime/web-socket.ts index 9b2e1042cb4c00..e28477b6efe96c 100644 --- a/src/mono/wasm/runtime/web-socket.ts +++ b/src/mono/wasm/runtime/web-socket.ts @@ -3,11 +3,10 @@ import { prevent_timer_throttling } from "./scheduling"; import { Queue } from "./queue"; -import { PromiseController, createPromiseController } from "./promise-controller"; -import { mono_assert } from "./types"; -import { Module } from "./globals"; +import { Module, createPromiseController } from "./globals"; import { setI32 } from "./memory"; import { VoidPtr } from "./types/emscripten"; +import { PromiseController } from "./types/internal"; const wasm_ws_pending_send_buffer = Symbol.for("wasm ws_pending_send_buffer"); const wasm_ws_pending_send_buffer_offset = Symbol.for("wasm ws_pending_send_buffer_offset"); diff --git a/src/mono/wasm/runtime/workers/README.md b/src/mono/wasm/runtime/workers/README.md index b6347fe1d33c38..0939b05204d3c0 100644 --- a/src/mono/wasm/runtime/workers/README.md +++ b/src/mono/wasm/runtime/workers/README.md @@ -13,7 +13,7 @@ To add a new web worker, add a definition here and modify the ## Caveats: a note about pthreads -The workers in this directory are completely standalone from the Emscripten pthreads! they do not have access to the shared instance memory, and do not load the Emscripten `dotnet.js`. As a result, the workers in this directory cannot use any of pthread APIs or otherwise interact with the runtime in any way, except through message passing, or by having something in the runtime set up their own shared array buffer (which would be inaccessible from wasm). +The workers in this directory are completely standalone from the Emscripten pthreads! they do not have access to the shared instance memory, and do not load the Emscripten `dotnet.native.js`. As a result, the workers in this directory cannot use any of pthread APIs or otherwise interact with the runtime in any way, except through message passing, or by having something in the runtime set up their own shared array buffer (which would be inaccessible from wasm). On the other hand, the workers in this directory also do not depend on a .NET runtime compiled with `-s USE_PTHREADS` and are thus usable on sufficiently new browser using the single-threaded builds of .NET for WebAssembly. diff --git a/src/mono/wasm/symbolicator/Program.cs b/src/mono/wasm/symbolicator/Program.cs index ee293863187f29..668f1ed06593db 100644 --- a/src/mono/wasm/symbolicator/Program.cs +++ b/src/mono/wasm/symbolicator/Program.cs @@ -72,4 +72,4 @@ return 0; -static void ShowUsage() => Console.WriteLine($"Usage: symbolicator [] [-|]"); +static void ShowUsage() => Console.WriteLine($"Usage: symbolicator [] [-|]"); diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index cb76cb0d19e025..85f3ad4ac36492 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -459,19 +459,21 @@ - - diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs index 0eddaf4d4aed96..4bbb6422260832 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -235,7 +235,7 @@ private List ProcessNativeAssets( if (isDotNetWasm) { - var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.wasm"); + var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.native.wasm"); ITaskItem newDotNetWasm = null; if (aotDotNetWasm != null) { @@ -252,7 +252,7 @@ private List ProcessNativeAssets( ApplyPublishProperties(newDotNetWasm); nativeStaticWebAssets.Add(newDotNetWasm); - if (resolvedNativeAssetToPublish.TryGetValue("dotnet.wasm", out var resolved)) + if (resolvedNativeAssetToPublish.TryGetValue("dotnet.native.wasm", out var resolved)) { filesToRemove.Add(resolved); } @@ -280,7 +280,7 @@ static bool IsDotNetWorkerJs(string key) return fileName.StartsWith("dotnet.worker.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal); } - static bool IsDotNetWasm(string key) => string.Equals("dotnet.wasm", Path.GetFileName(key), StringComparison.Ordinal); + static bool IsDotNetWasm(string key) => string.Equals("dotnet.native.wasm", Path.GetFileName(key), StringComparison.Ordinal); } private List ProcessSymbolAssets( diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index 439ebf64e7ed58..52c91909a3e711 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -78,6 +78,21 @@ private sealed class WasmEntry : AssetEntry public WasmEntry(string name, string hash) : base(name, hash, "dotnetwasm") { } } + private sealed class LoaderJsEntry : AssetEntry + { + public LoaderJsEntry(string name, string hash) : base(name, hash, "js-module-dotnet") { } + } + + private sealed class NativeJsEntry : AssetEntry + { + public NativeJsEntry(string name, string hash) : base(name, hash, "js-module-native") { } + } + + private sealed class RuntimeJsEntry : AssetEntry + { + public RuntimeJsEntry(string name, string hash) : base(name, hash, "js-module-runtime") { } + } + private sealed class ThreadsWorkerEntry : AssetEntry { public ThreadsWorkerEntry(string name, string hash) : base(name, hash, "js-module-threads") { } @@ -198,15 +213,27 @@ protected override bool ExecuteInternal() var dest = Path.Combine(AppDir!, name); if (!FileCopyChecked(item.ItemSpec, dest, "NativeAssets")) return false; - if (name == "dotnet.wasm") + if (name == "dotnet.js") + { + config.Assets.Add(new LoaderJsEntry (name, Utils.ComputeIntegrity(item.ItemSpec)) ); + } + else if (name == "dotnet.native.wasm") { config.Assets.Add(new WasmEntry (name, Utils.ComputeIntegrity(item.ItemSpec)) ); } + else if (name == "dotnet.native.js") + { + config.Assets.Add(new NativeJsEntry (name, Utils.ComputeIntegrity(item.ItemSpec)) ); + } + else if (name == "dotnet.runtime.js") + { + config.Assets.Add(new RuntimeJsEntry (name, Utils.ComputeIntegrity(item.ItemSpec)) ); + } else if (IncludeThreadsWorker && name == "dotnet.worker.js") { config.Assets.Add(new ThreadsWorkerEntry (name, Utils.ComputeIntegrity(item.ItemSpec))); } - else if(name == "dotnet.js.symbols") + else if(name == "dotnet.native.js.symbols") { config.Assets.Add(new SymbolsData(name, Utils.ComputeIntegrity(item.ItemSpec))); } diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs b/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs index a552adfbb19272..b5a6539e2cb87b 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilderBaseTask.cs @@ -22,7 +22,7 @@ public abstract class WasmAppBuilderBaseTask : Task [Required] public string[] Assemblies { get; set; } = Array.Empty(); - // files like dotnet.wasm, icudt.dat etc + // files like dotnet.native.wasm, icudt.dat etc [NotNull] [Required] public ITaskItem[] NativeAssets { get; set; } = Array.Empty(); From 12515598ee4aa22a5daa973b3fa53870093d452a Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 4 May 2023 15:16:46 +0200 Subject: [PATCH 02/25] wip --- src/mono/wasm/runtime/exports.ts | 4 +- src/mono/wasm/runtime/globals.ts | 3 +- src/mono/wasm/runtime/loader/globals.ts | 3 +- src/mono/wasm/runtime/loader/run.ts | 10 ++-- src/mono/wasm/runtime/rollup.config.js | 79 ++++++++++++++++++------- 5 files changed, 70 insertions(+), 29 deletions(-) diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index c82a1a38962612..407c14c8b3cf1a 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -7,7 +7,7 @@ import BuildConfiguration from "consts:configuration"; import WasmEnableLegacyJsInterop from "consts:WasmEnableLegacyJsInterop"; import type { RuntimeAPI } from "./types"; -import { Module, disableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setGlobalObjects, } from "./globals"; +import { Module, disableLegacyJsInterop, exportedRuntimeAPI, passEmscriptenInternals, runtimeHelpers, setRuntimeGlobals, } from "./globals"; import { GlobalObjects, is_nullish } from "./types/internal"; import { configureEmscriptenStartup, configureWorkerStartup } from "./startup"; @@ -142,5 +142,5 @@ class RuntimeList { // export external API export { - passEmscriptenInternals, initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setGlobalObjects + passEmscriptenInternals, initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals }; \ No newline at end of file diff --git a/src/mono/wasm/runtime/globals.ts b/src/mono/wasm/runtime/globals.ts index b2fa7bdf80bf44..1e978cec338f9d 100644 --- a/src/mono/wasm/runtime/globals.ts +++ b/src/mono/wasm/runtime/globals.ts @@ -23,6 +23,7 @@ export let runtimeHelpers: RuntimeHelpers = null as any; export let loaderHelpers: LoaderHelpers = null as any; // this is when we link with workload tools. The consts:WasmEnableLegacyJsInterop is when we compile with rollup. export let disableLegacyJsInterop = false; +export const thisIsRuntimeModuleRollupGuard = true;// this will be removed by rollup, please keep it in place export function passEmscriptenInternals(internals: EmscriptenInternals): void { ENVIRONMENT_IS_PTHREAD = internals.isPThread; @@ -31,7 +32,7 @@ export function passEmscriptenInternals(internals: EmscriptenInternals): void { runtimeHelpers.ExitStatus = internals.ExitStatus; } -export function setGlobalObjects(globalObjects: GlobalObjects) { +export function setRuntimeGlobals(globalObjects: GlobalObjects) { Module = globalObjects.module; INTERNAL = globalObjects.internal; runtimeHelpers = globalObjects.runtimeHelpers; diff --git a/src/mono/wasm/runtime/loader/globals.ts b/src/mono/wasm/runtime/loader/globals.ts index f4f34cbf1140ed..4fe2ebaf6ff3d9 100644 --- a/src/mono/wasm/runtime/loader/globals.ts +++ b/src/mono/wasm/runtime/loader/globals.ts @@ -17,8 +17,9 @@ export let runtimeHelpers: RuntimeHelpers = null as any; export let loaderHelpers: LoaderHelpers = null as any; export let exportedRuntimeAPI: RuntimeAPI = null as any; export let INTERNAL: any; +export const thisIsLoaderModuleRollupGuard = true;// this will be removed by rollup, please keep it in place -export function setGlobalObjects( +export function setLoaderGlobals( globalObjects: GlobalObjects, ) { runtimeHelpers = globalObjects.runtimeHelpers; diff --git a/src/mono/wasm/runtime/loader/run.ts b/src/mono/wasm/runtime/loader/run.ts index f0c37eaefec8c4..29cca240524818 100644 --- a/src/mono/wasm/runtime/loader/run.ts +++ b/src/mono/wasm/runtime/loader/run.ts @@ -4,7 +4,7 @@ import type { MonoConfig, DotnetHostBuilder, DotnetModuleConfig, RuntimeAPI, WebAssemblyStartOptions } from "../types"; import type { MonoConfigInternal, GlobalObjects, EmscriptenModuleInternal, initializeExportsType, initializeReplacementsType, configureEmscriptenStartupType, configureWorkerStartupType, setGlobalObjectsType, passEmscriptenInternalsType, } from "../types/internal"; -import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WEB, exportedRuntimeAPI, setGlobalObjects } from "./globals"; +import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WEB, exportedRuntimeAPI, setLoaderGlobals } from "./globals"; import { deep_merge_config, deep_merge_module, mono_wasm_load_config } from "./config"; import { mono_exit } from "./exit"; import { setup_proxy_console } from "./logging"; @@ -24,7 +24,7 @@ export const globalObjectsRoot: GlobalObjects = { api: {} } as any; -setGlobalObjects(globalObjectsRoot); +setLoaderGlobals(globalObjectsRoot); const module = globalObjectsRoot.module; const monoConfig = module.config as MonoConfigInternal; @@ -391,8 +391,8 @@ export async function createEmscripten(moduleFactory: DotnetModuleConfig | ((api // TODO call mono_download_assets(); here in parallel ? const es6Modules = await Promise.all(promises); - const { initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setGlobalObjects, passEmscriptenInternals } = es6Modules[0] as { - setGlobalObjects: setGlobalObjectsType, + const { initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals, passEmscriptenInternals } = es6Modules[0] as { + setRuntimeGlobals: setGlobalObjectsType, initializeExports: initializeExportsType, initializeReplacements: initializeReplacementsType, configureEmscriptenStartup: configureEmscriptenStartupType, @@ -403,7 +403,7 @@ export async function createEmscripten(moduleFactory: DotnetModuleConfig | ((api default: (unificator: Function) => EmscriptenModuleInternal }; - setGlobalObjects(globalObjectsRoot); + setRuntimeGlobals(globalObjectsRoot); initializeExports(globalObjectsRoot); loaderHelpers.runtimeModuleLoaded.promise_control.resolve(); diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index aa3f1a4a10d82c..8bcfe63b16f9ff 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -45,10 +45,24 @@ const inlineAssert = [ { pattern: /mono_assert\(([^,]*), \(\) => *`([^`]*)`\);/gm, replacement: "if (!($1)) throw new Error(`Assert failed: $2`); // inlined mono_assert" - }, { - pattern: /^\s*mono_assert/gm, - failure: "previous regexp didn't inline all mono_assert statements" - }]; + } +]; +const checkAssert = +{ + pattern: /^\s*mono_assert/gm, + failure: "previous regexp didn't inline all mono_assert statements" +}; +const checkNoLoader = +{ + pattern: /thisIsLoaderModuleRollupGuard/gm, + failure: "module should not contain thisIsLoaderModuleRollupGuard member. This is probably duplicated code in the output caused by a dependency outside on the loader module." +}; +const checkNoRuntime = +{ + pattern: /thisIsRuntimeModuleRollupGuard/gm, + failure: "module should not contain thisIsRuntimeModuleRollupGuard member. This is probably duplicated code in the output caused by a dependency on the runtime module." +}; + let gitHash; try { @@ -80,7 +94,7 @@ const typescriptConfigOptions = { include: ["**/*.ts", "../../../../artifacts/bin/native/generated/**/*.ts"] }; -const outputCodePlugins = [regexReplace(inlineAssert), consts({ productVersion, configuration, monoWasmThreads, monoDiagnosticsMock, gitHash, WasmEnableLegacyJsInterop }), typescript(typescriptConfigOptions)]; +const outputCodePlugins = [consts({ productVersion, configuration, monoWasmThreads, monoDiagnosticsMock, gitHash, WasmEnableLegacyJsInterop }), typescript(typescriptConfigOptions)]; const externalDependencies = ["module"]; const loaderConfig = { @@ -95,7 +109,7 @@ const loaderConfig = { } ], external: externalDependencies, - plugins: outputCodePlugins, + plugins: [regexReplace(inlineAssert), regexCheck([checkAssert, checkNoRuntime]), ...outputCodePlugins], onwarn: onwarn }; const typesConfig = { @@ -123,7 +137,7 @@ const runtimeConfig = { } ], external: externalDependencies, - plugins: outputCodePlugins, + plugins: [regexReplace(inlineAssert), regexCheck([checkAssert, checkNoLoader]), ...outputCodePlugins], onwarn: onwarn }; const legacyConfig = { @@ -262,11 +276,45 @@ function checkFileExists(file) { .catch(() => false); } +function regexCheck(checks = []) { + const filter = createFilter("**/*.ts"); + + return { + name: "regexCheck", + + renderChunk(code, chunk) { + const id = chunk.fileName; + if (!filter(id)) return null; + return executeCheck(this, code, id); + }, + + transform(code, id) { + if (!filter(id)) return null; + return executeCheck(this, code, id); + } + }; + + function executeCheck(self, code, id) { + // self.warn("executeCheck" + id); + for (const rep of checks) { + const { pattern, failure } = rep; + const match = pattern.test(code); + if (match) { + self.error(failure + " " + id); + return null; + } + } + + return null; + } +} + + function regexReplace(replacements = []) { const filter = createFilter("**/*.ts"); return { - name: "replace", + name: "regexReplace", renderChunk(code, chunk) { const id = chunk.fileName; @@ -280,21 +328,12 @@ function regexReplace(replacements = []) { } }; - function executeReplacement(self, code, id) { + function executeReplacement(_, code) { // TODO use MagicString for sourcemap support let fixed = code; for (const rep of replacements) { - const { pattern, replacement, failure } = rep; - if (failure) { - const match = pattern.test(fixed); - if (match) { - self.error(failure + " " + id, pattern.lastIndex); - return null; - } - } - else { - fixed = fixed.replace(pattern, replacement); - } + const { pattern, replacement } = rep; + fixed = fixed.replace(pattern, replacement); } if (fixed == code) { From 31abd81b740e918331040dc5e606f8efa64bfc4b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 4 May 2023 15:23:09 +0200 Subject: [PATCH 03/25] wip --- eng/liveBuilds.targets | 2 +- src/mono/sample/wasm/Directory.Build.targets | 1 + src/mono/wasm/build/WasmApp.targets | 6 ++---- .../ComputeWasmPublishAssets.cs | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 18453b2ae119dc..f0a62d03a9d703 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -233,7 +233,7 @@ diff --git a/src/mono/sample/wasm/Directory.Build.targets b/src/mono/sample/wasm/Directory.Build.targets index 448b2e65c0893f..88aceecfaed964 100644 --- a/src/mono/sample/wasm/Directory.Build.targets +++ b/src/mono/sample/wasm/Directory.Build.targets @@ -32,6 +32,7 @@ " Outputs=" bin/$(Configuration)/AppBundle/dotnet.native.wasm; + bin/$(Configuration)/AppBundle/dotnet.native.js; bin/$(Configuration)/AppBundle/$(_WasmMainJSFileName); "> diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index 50ab15441f4266..de7b759dfb4fce 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -331,9 +331,7 @@ <_HasDotnetWasm Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.wasm'">true <_HasDotnetJsWorker Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.worker.js'">true <_HasDotnetJsSymbols Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.js.symbols'">true - <_HasDotnetJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js'">true <_HasDotnetNativeJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.js'">true - <_HasDotnetRuntimeJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.runtime.js'">true <_WasmIcuDataFileName Condition="'$(WasmIcuDataFileName)' != '' and Exists('$(WasmIcuDataFileName)')">$(WasmIcuDataFileName) <_WasmIcuDataFileName Condition="'$(WasmIcuDataFileName)' != '' and !Exists('$(WasmIcuDataFileName)')">$(MicrosoftNetCoreAppRuntimePackRidNativeDir)$(WasmIcuDataFileName) @@ -345,8 +343,8 @@ - - + + diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs index 4bbb6422260832..2ccb0eee90e86e 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -271,13 +271,13 @@ private List ProcessNativeAssets( static bool IsDotNetJs(string key) { var fileName = Path.GetFileName(key); - return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker"); + return fileName.StartsWith("dotnet.native.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker"); } static bool IsDotNetWorkerJs(string key) { var fileName = Path.GetFileName(key); - return fileName.StartsWith("dotnet.worker.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal); + return fileName.StartsWith("dotnet.native.worker.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal); } static bool IsDotNetWasm(string key) => string.Equals("dotnet.native.wasm", Path.GetFileName(key), StringComparison.Ordinal); From 5543761b3d459992ac06afa53390b1c10664a87d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 4 May 2023 15:34:59 +0200 Subject: [PATCH 04/25] wip --- src/mono/wasm/runtime/es6/dotnet.es6.extpost.js | 2 +- src/mono/wasm/runtime/es6/dotnet.es6.pre.js | 2 ++ src/mono/wasm/runtime/globals.ts | 6 +++++- src/mono/wasm/runtime/loader/globals.ts | 6 +++++- src/mono/wasm/runtime/rollup.config.js | 8 ++++---- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js b/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js index 7fdd5d0ef8023d..510b2bef4efd4f 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.extpost.js @@ -1,2 +1,2 @@ -var fetch = fetch || undefined; var require = require || undefined; var __dirname = __dirname || ''; +var fetch = fetch || undefined; var require = require || undefined; var __dirname = __dirname || ''; var _nativeModuleLoaded = false; diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js index 8c2a0e6472917a..9eb9b1c6b99e7d 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.pre.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.pre.js @@ -1 +1,3 @@ +if (_nativeModuleLoaded) throw new Error("Native module already loaded"); +_nativeModuleLoaded = true; createDotnetRuntime = Module = createDotnetRuntime(Module); \ No newline at end of file diff --git a/src/mono/wasm/runtime/globals.ts b/src/mono/wasm/runtime/globals.ts index 1e978cec338f9d..c3523c1b36915a 100644 --- a/src/mono/wasm/runtime/globals.ts +++ b/src/mono/wasm/runtime/globals.ts @@ -23,7 +23,7 @@ export let runtimeHelpers: RuntimeHelpers = null as any; export let loaderHelpers: LoaderHelpers = null as any; // this is when we link with workload tools. The consts:WasmEnableLegacyJsInterop is when we compile with rollup. export let disableLegacyJsInterop = false; -export const thisIsRuntimeModuleRollupGuard = true;// this will be removed by rollup, please keep it in place +export let _runtimeModuleLoaded = false; // please keep it in place also as rollup guard export function passEmscriptenInternals(internals: EmscriptenInternals): void { ENVIRONMENT_IS_PTHREAD = internals.isPThread; @@ -33,6 +33,10 @@ export function passEmscriptenInternals(internals: EmscriptenInternals): void { } export function setRuntimeGlobals(globalObjects: GlobalObjects) { + if (_runtimeModuleLoaded) { + throw new Error("Runtime module already loaded"); + } + _runtimeModuleLoaded = true; Module = globalObjects.module; INTERNAL = globalObjects.internal; runtimeHelpers = globalObjects.runtimeHelpers; diff --git a/src/mono/wasm/runtime/loader/globals.ts b/src/mono/wasm/runtime/loader/globals.ts index 4fe2ebaf6ff3d9..49f8d1e903126e 100644 --- a/src/mono/wasm/runtime/loader/globals.ts +++ b/src/mono/wasm/runtime/loader/globals.ts @@ -17,11 +17,15 @@ export let runtimeHelpers: RuntimeHelpers = null as any; export let loaderHelpers: LoaderHelpers = null as any; export let exportedRuntimeAPI: RuntimeAPI = null as any; export let INTERNAL: any; -export const thisIsLoaderModuleRollupGuard = true;// this will be removed by rollup, please keep it in place +export let _loaderModuleLoaded = false; // please keep it in place also as rollup guard export function setLoaderGlobals( globalObjects: GlobalObjects, ) { + if (_loaderModuleLoaded) { + throw new Error("Loader module already loaded"); + } + _loaderModuleLoaded = true; runtimeHelpers = globalObjects.runtimeHelpers; loaderHelpers = globalObjects.loaderHelpers; exportedRuntimeAPI = globalObjects.api; diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index 8bcfe63b16f9ff..dd8c7b8f89125a 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -54,13 +54,13 @@ const checkAssert = }; const checkNoLoader = { - pattern: /thisIsLoaderModuleRollupGuard/gm, - failure: "module should not contain thisIsLoaderModuleRollupGuard member. This is probably duplicated code in the output caused by a dependency outside on the loader module." + pattern: /_loaderModuleLoaded/gm, + failure: "module should not contain loaderModuleLoaded member. This is probably duplicated code in the output caused by a dependency outside on the loader module." }; const checkNoRuntime = { - pattern: /thisIsRuntimeModuleRollupGuard/gm, - failure: "module should not contain thisIsRuntimeModuleRollupGuard member. This is probably duplicated code in the output caused by a dependency on the runtime module." + pattern: /_runtimeModuleLoaded/gm, + failure: "module should not contain runtimeModuleLoaded member. This is probably duplicated code in the output caused by a dependency on the runtime module." }; From b6ad41e8126b9f1243ed43d8c5bd330553e6b939 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 4 May 2023 16:47:41 +0200 Subject: [PATCH 05/25] fix dry run and snapshot --- .../InteropServices/JavaScript/SecondRuntimeTest.js | 9 +++++++-- src/mono/wasm/runtime/dotnet.d.ts | 4 ++++ src/mono/wasm/runtime/loader/assets.ts | 3 +++ src/mono/wasm/runtime/loader/config.ts | 1 + src/mono/wasm/runtime/snapshot.ts | 1 + src/mono/wasm/runtime/types/index.ts | 6 +++++- src/mono/wasm/runtime/types/internal.ts | 1 + src/mono/wasm/test-main.js | 1 + 8 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/SecondRuntimeTest.js b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/SecondRuntimeTest.js index 7abbf83d1f7cd5..fa0b5d9f52eb8b 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/SecondRuntimeTest.js +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/SecondRuntimeTest.js @@ -1,6 +1,11 @@ export async function runSecondRuntimeAndTestStaticState() { - const { dotnet: dotnet2 } = await import('./dotnet.js?2'); - const runtime2 = await dotnet2.create(); + const { dotnet: dotnet2 } = await import('./dotnet.js?instance=2'); + const runtime2 = await dotnet2 + .withStartupMemoryCache(false) + .withConfig({ + assetUniqueQuery: "?instance=2", + }) + .create(); const increment1 = await getIncrementStateFunction(App.runtime); const increment2 = await getIncrementStateFunction(runtime2); diff --git a/src/mono/wasm/runtime/dotnet.d.ts b/src/mono/wasm/runtime/dotnet.d.ts index c1f6826b051959..d5cbed9f3354f7 100644 --- a/src/mono/wasm/runtime/dotnet.d.ts +++ b/src/mono/wasm/runtime/dotnet.d.ts @@ -139,6 +139,10 @@ type MonoConfig = { * application environment */ applicationEnvironment?: string; + /** + * query string to be used for asset loading + */ + assetUniqueQuery?: string; }; interface ResourceRequest { name: string; diff --git a/src/mono/wasm/runtime/loader/assets.ts b/src/mono/wasm/runtime/loader/assets.ts index 2a1bf7432a5449..a99f80a754a332 100644 --- a/src/mono/wasm/runtime/loader/assets.ts +++ b/src/mono/wasm/runtime/loader/assets.ts @@ -371,6 +371,9 @@ function resolve_path(asset: AssetEntry, sourcePrefix: string): string { attemptUrl = sourcePrefix + asset.name; } attemptUrl = loaderHelpers.locateFile(attemptUrl); + if (loaderHelpers.assetUniqueQuery) { + attemptUrl = attemptUrl + loaderHelpers.assetUniqueQuery; + } } else { attemptUrl = asset.resolvedUrl; diff --git a/src/mono/wasm/runtime/loader/config.ts b/src/mono/wasm/runtime/loader/config.ts index 1c460f74ded091..a3cad5e37ffda2 100644 --- a/src/mono/wasm/runtime/loader/config.ts +++ b/src/mono/wasm/runtime/loader/config.ts @@ -49,6 +49,7 @@ export function normalizeConfig() { config.diagnosticTracing = true; } loaderHelpers.diagnosticTracing = !!config.diagnosticTracing; + loaderHelpers.assetUniqueQuery = config.assetUniqueQuery; runtimeHelpers.waitForDebugger = config.waitForDebugger; config.startupMemoryCache = !!config.startupMemoryCache; if (config.startupMemoryCache && runtimeHelpers.waitForDebugger) { diff --git a/src/mono/wasm/runtime/snapshot.ts b/src/mono/wasm/runtime/snapshot.ts index 5c1d109342e916..571f6e9880014d 100644 --- a/src/mono/wasm/runtime/snapshot.ts +++ b/src/mono/wasm/runtime/snapshot.ts @@ -175,6 +175,7 @@ async function getCacheKey(): Promise { delete inputs.maxParallelDownloads; delete inputs.enableDownloadRetry; delete inputs.exitAfterSnapshot; + delete inputs.assetUniqueQuery; inputs.GitHash = GitHash; inputs.ProductVersion = ProductVersion; diff --git a/src/mono/wasm/runtime/types/index.ts b/src/mono/wasm/runtime/types/index.ts index de166381096d11..8698b65f5f59a0 100644 --- a/src/mono/wasm/runtime/types/index.ts +++ b/src/mono/wasm/runtime/types/index.ts @@ -82,7 +82,11 @@ export type MonoConfig = { /** * application environment */ - applicationEnvironment?: string + applicationEnvironment?: string, + /** + * query string to be used for asset loading + */ + assetUniqueQuery?: string, }; export interface ResourceRequest { diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts index a77c577f645d85..d7c4fb95e275af 100644 --- a/src/mono/wasm/runtime/types/internal.ts +++ b/src/mono/wasm/runtime/types/internal.ts @@ -103,6 +103,7 @@ export type LoaderHelpers = { _loaded_files: { url: string, file: string }[]; scriptDirectory: string scriptUrl: string + assetUniqueQuery?: string preferredIcuAsset: string | null, invariantMode: boolean, diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index 63dc5d143f7aff..90371a45707e30 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -305,6 +305,7 @@ async function dry_run(runArgs) { appendElementOnExit: false, logExitCode: false, pthreadPoolSize: 0, + assetUniqueQuery: "?dry_run=true", // this just means to not continue startup after the snapshot is taken. // If there was previously a matching snapshot, it will be used. exitAfterSnapshot: true From 4192e717a76aeda074f6a410dc4c00383a6d0eaf Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 4 May 2023 18:45:45 +0200 Subject: [PATCH 06/25] wip --- src/mono/wasm/runtime/net6-legacy/export-types.ts | 4 ---- src/mono/wasm/runtime/net6-legacy/exports-legacy.ts | 1 - src/tasks/WasmAppBuilder/WasmAppBuilder.cs | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/mono/wasm/runtime/net6-legacy/export-types.ts b/src/mono/wasm/runtime/net6-legacy/export-types.ts index 78d695de27c962..7d9e4d0bc0729d 100644 --- a/src/mono/wasm/runtime/net6-legacy/export-types.ts +++ b/src/mono/wasm/runtime/net6-legacy/export-types.ts @@ -106,10 +106,6 @@ export type MONOType = { * @deprecated Please use config.assets instead */ mono_wasm_load_data_archive: (data: Uint8Array, prefix: string) => boolean; - /** - * @deprecated Please use configSrc instead - */ - mono_wasm_load_config: (configFilePath: string) => Promise; /** * @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead. */ diff --git a/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts b/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts index 4c61e88fca9a5d..5225d2df8cb7ed 100644 --- a/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts +++ b/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts @@ -26,7 +26,6 @@ export function export_mono_api(): MONOType { mono_wasm_load_icu_data, mono_wasm_runtime_ready, mono_wasm_load_data_archive, - mono_wasm_load_config: null as any,//TODO ZAMO mono_wasm_new_root_buffer, mono_wasm_new_root, mono_wasm_new_external_root, diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index 52c91909a3e711..7370e93939f74d 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -229,7 +229,7 @@ protected override bool ExecuteInternal() { config.Assets.Add(new RuntimeJsEntry (name, Utils.ComputeIntegrity(item.ItemSpec)) ); } - else if (IncludeThreadsWorker && name == "dotnet.worker.js") + else if (IncludeThreadsWorker && name == "dotnet.native.worker.js") { config.Assets.Add(new ThreadsWorkerEntry (name, Utils.ComputeIntegrity(item.ItemSpec))); } From aaee77f863ad2f0687011d90069974fc249a749d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 5 May 2023 12:55:14 +0200 Subject: [PATCH 07/25] fix --- src/mono/wasm/runtime/dotnet-legacy.d.ts | 4 ---- src/mono/wasm/runtime/loader/blazor/_Integration.ts | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/mono/wasm/runtime/dotnet-legacy.d.ts b/src/mono/wasm/runtime/dotnet-legacy.d.ts index 3dcc0104e6eee5..ba286033fed3ea 100644 --- a/src/mono/wasm/runtime/dotnet-legacy.d.ts +++ b/src/mono/wasm/runtime/dotnet-legacy.d.ts @@ -158,10 +158,6 @@ type MONOType = { * @deprecated Please use config.assets instead */ mono_wasm_load_data_archive: (data: Uint8Array, prefix: string) => boolean; - /** - * @deprecated Please use configSrc instead - */ - mono_wasm_load_config: (configFilePath: string) => Promise; /** * @deprecated Please use [JSImportAttribute] or [JSExportAttribute] for interop instead. */ diff --git a/src/mono/wasm/runtime/loader/blazor/_Integration.ts b/src/mono/wasm/runtime/loader/blazor/_Integration.ts index 88203e1b2aa593..85e6988186e613 100644 --- a/src/mono/wasm/runtime/loader/blazor/_Integration.ts +++ b/src/mono/wasm/runtime/loader/blazor/_Integration.ts @@ -89,10 +89,10 @@ export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, appl moduleConfig.enableDownloadRetry = false; // disable retry downloads moduleConfig.mainAssemblyName = resourceLoader.bootConfig.entryAssembly; - moduleConfig = { + // FIXME this mix of both formats is ugly temporary hack + Object.assign(moduleConfig, { ...resourceLoader.bootConfig, - ...moduleConfig - }; + }); if (resourceLoader.bootConfig.startupMemoryCache !== undefined) { moduleConfig.startupMemoryCache = resourceLoader.bootConfig.startupMemoryCache; From 731dc892ea32f48f2543be8c0267c6954f95381c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 5 May 2023 13:51:35 +0200 Subject: [PATCH 08/25] Update Wasm SDK to process new js files. Put fingerprint on runtime and native js files, remove it from loader js --- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 2 -- .../AssetsComputingHelper.cs | 9 ++++++- .../ComputeWasmBuildAssets.cs | 6 ++--- .../ComputeWasmPublishAssets.cs | 27 ++++++++++--------- .../GenerateWasmBootJson.cs | 5 ++-- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 47b4cf3206231a..02e7a191e2603a 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -55,7 +55,6 @@ Copyright (c) .NET Foundation. All rights reserved. <_AggressiveAttributeTrimming Condition="'$(_AggressiveAttributeTrimming)' == ''">true false true - false false @@ -203,7 +202,6 @@ Copyright (c) .NET Foundation. All rights reserved. InvariantGlobalization="$(_WasmInvariantGlobalization)" CopySymbols="$(_WasmCopyOutputSymbolsToOutputDirectory)" OutputPath="$(OutputPath)" - FingerprintDotNetJs="$(WasmFingerprintDotnetJs)" EnableThreads="$(_WasmEnableThreads)" > diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs index 46bc35c0325ef3..41722523d284d0 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs @@ -19,6 +19,13 @@ public class AssetsComputingHelper "Microsoft.NETCore.App.Runtime.Mono.perftrace.browser-wasm", }; + private static readonly string[] dotnetJsSingleThreadNames = new[] + { + "dotnet", + "dotnet.native", + "dotnet.runtime" + }; + public static bool ShouldFilterCandidate( ITaskItem candidate, bool timezoneSupport, @@ -50,7 +57,7 @@ public static bool ShouldFilterCandidate( ".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor", ".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor", ".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor", - ".js" when assetType == "native" && !(fileName == "dotnet" || enableThreads && fileName == "dotnet.worker") => $"{fileName}{extension} is not used by Blazor", + ".js" when assetType == "native" && !(dotnetJsSingleThreadNames.Contains(fileName) || enableThreads && fileName == "dotnet.native.worker") => $"{fileName}{extension} is not used by Blazor", ".pdb" when !copySymbols => "copying symbols is disabled", ".symbols" when fromMonoPackage => "extension .symbols is not required.", _ => null diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs index 97caad5a385746..c8367399330a88 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs @@ -43,8 +43,6 @@ public class ComputeWasmBuildAssets : Task [Required] public bool CopySymbols { get; set; } - public bool FingerprintDotNetJs { get; set; } - public bool EnableThreads { get; set; } [Output] @@ -107,11 +105,11 @@ public override bool Execute() } string candidateFileName = candidate.GetMetadata("FileName"); - if ((candidateFileName == "dotnet" || candidateFileName == "dotnet.worker") && candidate.GetMetadata("Extension") == ".js") + if (candidateFileName.StartsWith("dotnet") && candidate.GetMetadata("Extension") == ".js") { string newDotnetJSFileName = null; string newDotNetJSFullPath = null; - if (FingerprintDotNetJs) + if (candidateFileName != "dotnet") { var itemHash = FileHasher.GetFileHash(candidate.ItemSpec); newDotnetJSFileName = $"{candidateFileName}.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js"; diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs index 2ccb0eee90e86e..78abbed7286174 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -165,11 +165,10 @@ private List ProcessNativeAssets( { var key = kvp.Key; var asset = kvp.Value; - var isDotNetJs = IsDotNetJs(key); - var isDotNetWorkerJs = IsDotNetWorkerJs(key); + var isDotNetJs = IsAnyDotNetJs(key); var isDotNetWasm = IsDotNetWasm(key); - if (!isDotNetJs && !isDotNetWasm && !isDotNetWorkerJs) + if (!isDotNetJs && !isDotNetWasm) { if (resolvedNativeAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing)) { @@ -198,9 +197,17 @@ private List ProcessNativeAssets( continue; } - if (isDotNetJs || isDotNetWorkerJs) + if (isDotNetJs) { - var baseName = isDotNetWorkerJs ? "dotnet.worker" : "dotnet"; + var baseName = Path.GetFileNameWithoutExtension(key); + if (baseName.StartsWith("dotnet.native")) + baseName = "dotnet.native"; + else if (baseName.StartsWith("dotnet.runtime")) + baseName = "dotnet.runtime"; + else if (baseName.StartsWith("dotnet.worker")) + baseName = "dotnet.worker"; + else if (baseName.StartsWith("dotnet")) + baseName = "dotnet"; var aotDotNetJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == $"{baseName}.js"); ITaskItem newDotNetJs = null; @@ -268,16 +275,10 @@ private List ProcessNativeAssets( return nativeStaticWebAssets; - static bool IsDotNetJs(string key) + static bool IsAnyDotNetJs(string key) { var fileName = Path.GetFileName(key); - return fileName.StartsWith("dotnet.native.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker"); - } - - static bool IsDotNetWorkerJs(string key) - { - var fileName = Path.GetFileName(key); - return fileName.StartsWith("dotnet.native.worker.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal); + return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal); } static bool IsDotNetWasm(string key) => string.Equals("dotnet.native.wasm", Path.GetFileName(key), StringComparison.Ordinal); diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs index 31ed093e9a202f..0e8dc24e3e23a4 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs @@ -196,8 +196,7 @@ public void WriteBootJson(Stream output, string entryAssemblyName) string.Equals(assetTraitValue, "native", StringComparison.OrdinalIgnoreCase)) { Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a native application resource.", resource.ItemSpec); - if (string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase) && - string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) + if (fileName.StartsWith("dotnet", StringComparison.OrdinalIgnoreCase) && string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) { behavior = "dotnetwasm"; } @@ -286,7 +285,7 @@ public void WriteBootJson(Stream output, string entryAssemblyName) UseSimpleDictionaryFormat = true }); - result.extensions = new Dictionary> (); + result.extensions = new Dictionary>(); foreach (var configExtension in Extensions) { var key = configExtension.GetMetadata("key"); From 8e63d87886950ed891552fe2b4e55211f2f7b0f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Fri, 5 May 2023 14:40:53 +0200 Subject: [PATCH 09/25] Fix relative path to js modules --- src/mono/wasm/runtime/loader/blazor/_Integration.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mono/wasm/runtime/loader/blazor/_Integration.ts b/src/mono/wasm/runtime/loader/blazor/_Integration.ts index 85e6988186e613..e81f60707e1876 100644 --- a/src/mono/wasm/runtime/loader/blazor/_Integration.ts +++ b/src/mono/wasm/runtime/loader/blazor/_Integration.ts @@ -147,9 +147,11 @@ export function mapBootConfigToMonoConfig(moduleConfig: MonoConfigInternal, appl } else if (behavior === "dotnetwasm") { continue; } + + const resolvedUrl = name.endsWith(".js") ? `./${name}` : `_framework/${name}`; const asset: AssetEntry = { name, - resolvedUrl: `_framework/${name}`, + resolvedUrl, hash: resources.runtime[name], behavior, }; From 998b9cb7619d5e34996c6346489b76d8118275c0 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 9 May 2023 12:30:41 +0200 Subject: [PATCH 10/25] fix merge --- .../runtime/jiterpreter-trace-generator.ts | 529 +++++++++--------- 1 file changed, 264 insertions(+), 265 deletions(-) diff --git a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts index f3524af57180cf..5243e11d61dc65 100644 --- a/src/mono/wasm/runtime/jiterpreter-trace-generator.ts +++ b/src/mono/wasm/runtime/jiterpreter-trace-generator.ts @@ -44,25 +44,25 @@ import { /* struct MonoVTable { - MonoClass *klass; // 0 - MonoGCDescriptor gc_descr; // 4 - MonoDomain *domain; // 8 - gpointer type; // 12 - guint8 *interface_bitmap; // 16 - guint32 max_interface_id; // 20 - guint8 rank; // 21 - guint8 initialized; // 22 - guint8 flags; + MonoClass *klass; // 0 + MonoGCDescriptor gc_descr; // 4 + MonoDomain *domain; // 8 + gpointer type; // 12 + guint8 *interface_bitmap; // 16 + guint32 max_interface_id; // 20 + guint8 rank; // 21 + guint8 initialized; // 22 + guint8 flags; */ /* struct InterpFrame { - InterpFrame *parent; // 0 - InterpMethod *imethod; // 4 - stackval *retval; // 8 - stackval *stack; // 12 - InterpFrame *next_free; // 16 - InterpState state; // 20 + InterpFrame *parent; // 0 + InterpMethod *imethod; // 4 + stackval *retval; // 8 + stackval *stack; // 12 + InterpFrame *next_free; // 16 + InterpState state; // 20 }; struct InterpMethod { @@ -388,10 +388,10 @@ export function generateWasmBody( const sizeOffset = getArgU16(ip, 3), valueOffset = getArgU16(ip, 2), destOffset = getArgU16(ip, 1); - /* - constantSize = get_known_constant_value(sizeOffset), - constantValue = get_known_constant_value(valueOffset); - */ + /* + constantSize = get_known_constant_value(sizeOffset), + constantValue = get_known_constant_value(valueOffset); + */ // TODO: Handle constant size initblks. Not sure if they matter though // FIXME: This will cause an erroneous bailout if dest and size are both 0 @@ -1108,7 +1108,7 @@ export function generateWasmBody( case MintOpcode.MINT_CONV_I8_R4: case MintOpcode.MINT_CONV_I8_R8: { const isF32 = (opcode === MintOpcode.MINT_CONV_I4_R4) || - (opcode === MintOpcode.MINT_CONV_I8_R4), + (opcode === MintOpcode.MINT_CONV_I8_R4), isI64 = (opcode === MintOpcode.MINT_CONV_I8_R4) || (opcode === MintOpcode.MINT_CONV_I8_R8), limit = isI64 @@ -1471,7 +1471,7 @@ function append_branch_target_block(builder: WasmBuilder, ip: MintOpcodePtr, isB builder.cfg.startBranchBlock(ip, isBackBranchTarget); } -function append_ldloc (builder: WasmBuilder, offset: number, opcodeOrPrefix: WasmOpcode, simdOpcode?: WasmSimdOpcode) { +function append_ldloc(builder: WasmBuilder, offset: number, opcodeOrPrefix: WasmOpcode, simdOpcode?: WasmSimdOpcode) { builder.local("pLocals"); builder.appendU8(opcodeOrPrefix); if (simdOpcode !== undefined) { @@ -1489,7 +1489,7 @@ function append_ldloc (builder: WasmBuilder, offset: number, opcodeOrPrefix: Was // where the offset+alignment pair is referred to as a 'memarg' by the spec. // The actual store operation is equivalent to `pBase[offset] = value` (alignment has no // observable impact on behavior, other than causing compilation failures if out of range) -function append_stloc_tail (builder: WasmBuilder, offset: number, opcodeOrPrefix: WasmOpcode, simdOpcode?: WasmSimdOpcode) { +function append_stloc_tail(builder: WasmBuilder, offset: number, opcodeOrPrefix: WasmOpcode, simdOpcode?: WasmSimdOpcode) { builder.appendU8(opcodeOrPrefix); if (simdOpcode !== undefined) { // This looks wrong but I assure you it's correct. @@ -1769,9 +1769,9 @@ function emit_fieldop( (opcode <= MintOpcode.MINT_LDFLDA_UNSAFE) ) || ( - (opcode >= MintOpcode.MINT_LDSFLD_I1) && - (opcode <= MintOpcode.MINT_LDSFLD_W) - ); + (opcode >= MintOpcode.MINT_LDSFLD_I1) && + (opcode <= MintOpcode.MINT_LDSFLD_W) + ); const objectOffset = getArgU16(ip, isLoad ? 2 : 1), fieldOffset = getArgU16(ip, 3), @@ -1955,9 +1955,9 @@ function emit_sfieldop( (opcode <= MintOpcode.MINT_LDFLDA_UNSAFE) ) || ( - (opcode >= MintOpcode.MINT_LDSFLD_I1) && - (opcode <= MintOpcode.MINT_LDSFLD_W) - ); + (opcode >= MintOpcode.MINT_LDSFLD_I1) && + (opcode <= MintOpcode.MINT_LDSFLD_W) + ); const localOffset = getArgU16(ip, 1), pVtable = get_imethod_data(frame, getArgU16(ip, 2)), @@ -2067,24 +2067,24 @@ const floatToIntTable: { [opcode: number]: WasmOpcode } = { // thanks for making this as complex as possible, typescript const unopTable: { [opcode: number]: OpRec3 | undefined } = { - [MintOpcode.MINT_CEQ0_I4]: [WasmOpcode.i32_eqz, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD1_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SUB1_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_NEG_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_NOT_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CEQ0_I4]: [WasmOpcode.i32_eqz, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD1_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SUB1_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_NEG_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_NOT_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD1_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SUB1_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_NEG_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_NOT_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_ADD1_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SUB1_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_NEG_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_NOT_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_ADD_I4_IMM]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_MUL_I4_IMM]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD_I8_IMM]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_MUL_I8_IMM]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_ADD_I4_IMM]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_MUL_I4_IMM]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD_I8_IMM]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_MUL_I8_IMM]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_NEG_R4]: [WasmOpcode.f32_neg, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_NEG_R8]: [WasmOpcode.f64_neg, WasmOpcode.f64_load, WasmOpcode.f64_store], + [MintOpcode.MINT_NEG_R4]: [WasmOpcode.f32_neg, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_NEG_R8]: [WasmOpcode.f64_neg, WasmOpcode.f64_load, WasmOpcode.f64_store], [MintOpcode.MINT_CONV_R4_I4]: [WasmOpcode.f32_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f32_store], [MintOpcode.MINT_CONV_R8_I4]: [WasmOpcode.f64_convert_s_i32, WasmOpcode.i32_load, WasmOpcode.f64_store], @@ -2092,40 +2092,40 @@ const unopTable: { [opcode: number]: OpRec3 | undefined } = { [MintOpcode.MINT_CONV_R4_I8]: [WasmOpcode.f32_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f32_store], [MintOpcode.MINT_CONV_R8_I8]: [WasmOpcode.f64_convert_s_i64, WasmOpcode.i64_load, WasmOpcode.f64_store], [MintOpcode.MINT_CONV_R_UN_I8]: [WasmOpcode.f64_convert_u_i64, WasmOpcode.i64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_CONV_R8_R4]: [WasmOpcode.f64_promote_f32, WasmOpcode.f32_load, WasmOpcode.f64_store], - [MintOpcode.MINT_CONV_R4_R8]: [WasmOpcode.f32_demote_f64, WasmOpcode.f64_load, WasmOpcode.f32_store], - - [MintOpcode.MINT_CONV_I8_I4]: [WasmOpcode.nop, WasmOpcode.i64_load32_s, WasmOpcode.i64_store], - [MintOpcode.MINT_CONV_I8_U4]: [WasmOpcode.nop, WasmOpcode.i64_load32_u, WasmOpcode.i64_store], - - [MintOpcode.MINT_CONV_U1_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_U2_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I1_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I2_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CONV_U1_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_U2_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I1_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CONV_I2_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_SHL_I4_IMM]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHL_I8_IMM]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHR_I4_IMM]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHR_I8_IMM]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHR_UN_I4_IMM]: [WasmOpcode.i32_shr_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHR_UN_I8_IMM]: [WasmOpcode.i64_shr_u, WasmOpcode.i64_load, WasmOpcode.i64_store], - - [MintOpcode.MINT_ROL_I4_IMM]: [WasmOpcode.i32_rotl, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ROL_I8_IMM]: [WasmOpcode.i64_rotl, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_ROR_I4_IMM]: [WasmOpcode.i32_rotr, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ROR_I8_IMM]: [WasmOpcode.i64_rotr, WasmOpcode.i64_load, WasmOpcode.i64_store], - - [MintOpcode.MINT_CLZ_I4]: [WasmOpcode.i32_clz, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CTZ_I4]: [WasmOpcode.i32_ctz, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_POPCNT_I4]: [WasmOpcode.i32_popcnt, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLZ_I8]: [WasmOpcode.i64_clz, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_CTZ_I8]: [WasmOpcode.i64_ctz, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_POPCNT_I8]: [WasmOpcode.i64_popcnt, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_CONV_R8_R4]: [WasmOpcode.f64_promote_f32, WasmOpcode.f32_load, WasmOpcode.f64_store], + [MintOpcode.MINT_CONV_R4_R8]: [WasmOpcode.f32_demote_f64, WasmOpcode.f64_load, WasmOpcode.f32_store], + + [MintOpcode.MINT_CONV_I8_I4]: [WasmOpcode.nop, WasmOpcode.i64_load32_s, WasmOpcode.i64_store], + [MintOpcode.MINT_CONV_I8_U4]: [WasmOpcode.nop, WasmOpcode.i64_load32_u, WasmOpcode.i64_store], + + [MintOpcode.MINT_CONV_U1_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_U2_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I1_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I2_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CONV_U1_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_U2_I8]: [WasmOpcode.i32_and, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I1_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CONV_I2_I8]: [WasmOpcode.i32_shr_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_SHL_I4_IMM]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHL_I8_IMM]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHR_I4_IMM]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHR_I8_IMM]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHR_UN_I4_IMM]: [WasmOpcode.i32_shr_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHR_UN_I8_IMM]: [WasmOpcode.i64_shr_u, WasmOpcode.i64_load, WasmOpcode.i64_store], + + [MintOpcode.MINT_ROL_I4_IMM]: [WasmOpcode.i32_rotl, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ROL_I8_IMM]: [WasmOpcode.i64_rotl, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_ROR_I4_IMM]: [WasmOpcode.i32_rotr, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ROR_I8_IMM]: [WasmOpcode.i64_rotr, WasmOpcode.i64_load, WasmOpcode.i64_store], + + [MintOpcode.MINT_CLZ_I4]: [WasmOpcode.i32_clz, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CTZ_I4]: [WasmOpcode.i32_ctz, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_POPCNT_I4]: [WasmOpcode.i32_popcnt, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLZ_I8]: [WasmOpcode.i64_clz, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_CTZ_I8]: [WasmOpcode.i64_ctz, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_POPCNT_I8]: [WasmOpcode.i64_popcnt, WasmOpcode.i64_load, WasmOpcode.i64_store], }; // HACK: Generating correct wasm for these is non-trivial so we hand them off to C. @@ -2156,152 +2156,152 @@ const intrinsicFpBinops: { [opcode: number]: WasmOpcode } = { }; const binopTable: { [opcode: number]: OpRec3 | OpRec4 | undefined } = { - [MintOpcode.MINT_ADD_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_ADD_OVF_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_ADD_OVF_UN_I4]: [WasmOpcode.i32_add, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SUB_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_MUL_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SUB_I4]: [WasmOpcode.i32_sub, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_MUL_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_MUL_OVF_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_MUL_OVF_UN_I4]: [WasmOpcode.i32_mul, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_DIV_I4]: [WasmOpcode.i32_div_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_DIV_I4]: [WasmOpcode.i32_div_s, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_DIV_UN_I4]: [WasmOpcode.i32_div_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_REM_I4]: [WasmOpcode.i32_rem_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_REM_I4]: [WasmOpcode.i32_rem_s, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_REM_UN_I4]: [WasmOpcode.i32_rem_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_AND_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_OR_I4]: [WasmOpcode.i32_or, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_XOR_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHL_I4]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_SHR_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_AND_I4]: [WasmOpcode.i32_and, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_OR_I4]: [WasmOpcode.i32_or, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_XOR_I4]: [WasmOpcode.i32_xor, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHL_I4]: [WasmOpcode.i32_shl, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_SHR_I4]: [WasmOpcode.i32_shr_s, WasmOpcode.i32_load, WasmOpcode.i32_store], [MintOpcode.MINT_SHR_UN_I4]: [WasmOpcode.i32_shr_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_ADD_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SUB_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_MUL_I8]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_DIV_I8]: [WasmOpcode.i64_div_s, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_REM_I8]: [WasmOpcode.i64_rem_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_ADD_I8]: [WasmOpcode.i64_add, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SUB_I8]: [WasmOpcode.i64_sub, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_MUL_I8]: [WasmOpcode.i64_mul, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_DIV_I8]: [WasmOpcode.i64_div_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_REM_I8]: [WasmOpcode.i64_rem_s, WasmOpcode.i64_load, WasmOpcode.i64_store], [MintOpcode.MINT_DIV_UN_I8]: [WasmOpcode.i64_div_u, WasmOpcode.i64_load, WasmOpcode.i64_store], [MintOpcode.MINT_REM_UN_I8]: [WasmOpcode.i64_rem_u, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_AND_I8]: [WasmOpcode.i64_and, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_OR_I8]: [WasmOpcode.i64_or, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_XOR_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHL_I8]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_SHR_I8]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_AND_I8]: [WasmOpcode.i64_and, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_OR_I8]: [WasmOpcode.i64_or, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_XOR_I8]: [WasmOpcode.i64_xor, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHL_I8]: [WasmOpcode.i64_shl, WasmOpcode.i64_load, WasmOpcode.i64_store], + [MintOpcode.MINT_SHR_I8]: [WasmOpcode.i64_shr_s, WasmOpcode.i64_load, WasmOpcode.i64_store], [MintOpcode.MINT_SHR_UN_I8]: [WasmOpcode.i64_shr_u, WasmOpcode.i64_load, WasmOpcode.i64_store], - [MintOpcode.MINT_ADD_R4]: [WasmOpcode.f32_add, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_SUB_R4]: [WasmOpcode.f32_sub, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_MUL_R4]: [WasmOpcode.f32_mul, WasmOpcode.f32_load, WasmOpcode.f32_store], - [MintOpcode.MINT_DIV_R4]: [WasmOpcode.f32_div, WasmOpcode.f32_load, WasmOpcode.f32_store], - - [MintOpcode.MINT_ADD_R8]: [WasmOpcode.f64_add, WasmOpcode.f64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_SUB_R8]: [WasmOpcode.f64_sub, WasmOpcode.f64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_MUL_R8]: [WasmOpcode.f64_mul, WasmOpcode.f64_load, WasmOpcode.f64_store], - [MintOpcode.MINT_DIV_R8]: [WasmOpcode.f64_div, WasmOpcode.f64_load, WasmOpcode.f64_store], - - [MintOpcode.MINT_CEQ_I4]: [WasmOpcode.i32_eq, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CNE_I4]: [WasmOpcode.i32_ne, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLT_I4]: [WasmOpcode.i32_lt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_I4]: [WasmOpcode.i32_gt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_I4]: [WasmOpcode.i32_le_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_I4]: [WasmOpcode.i32_ge_s, WasmOpcode.i32_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CLT_UN_I4]: [WasmOpcode.i32_lt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_UN_I4]: [WasmOpcode.i32_gt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_UN_I4]: [WasmOpcode.i32_le_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_UN_I4]: [WasmOpcode.i32_ge_u, WasmOpcode.i32_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CEQ_I8]: [WasmOpcode.i64_eq, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CNE_I8]: [WasmOpcode.i64_ne, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLT_I8]: [WasmOpcode.i64_lt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_I8]: [WasmOpcode.i64_gt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_I8]: [WasmOpcode.i64_le_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_I8]: [WasmOpcode.i64_ge_s, WasmOpcode.i64_load, WasmOpcode.i32_store], - - [MintOpcode.MINT_CLT_UN_I8]: [WasmOpcode.i64_lt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGT_UN_I8]: [WasmOpcode.i64_gt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CLE_UN_I8]: [WasmOpcode.i64_le_u, WasmOpcode.i64_load, WasmOpcode.i32_store], - [MintOpcode.MINT_CGE_UN_I8]: [WasmOpcode.i64_ge_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_ADD_R4]: [WasmOpcode.f32_add, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_SUB_R4]: [WasmOpcode.f32_sub, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_MUL_R4]: [WasmOpcode.f32_mul, WasmOpcode.f32_load, WasmOpcode.f32_store], + [MintOpcode.MINT_DIV_R4]: [WasmOpcode.f32_div, WasmOpcode.f32_load, WasmOpcode.f32_store], + + [MintOpcode.MINT_ADD_R8]: [WasmOpcode.f64_add, WasmOpcode.f64_load, WasmOpcode.f64_store], + [MintOpcode.MINT_SUB_R8]: [WasmOpcode.f64_sub, WasmOpcode.f64_load, WasmOpcode.f64_store], + [MintOpcode.MINT_MUL_R8]: [WasmOpcode.f64_mul, WasmOpcode.f64_load, WasmOpcode.f64_store], + [MintOpcode.MINT_DIV_R8]: [WasmOpcode.f64_div, WasmOpcode.f64_load, WasmOpcode.f64_store], + + [MintOpcode.MINT_CEQ_I4]: [WasmOpcode.i32_eq, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CNE_I4]: [WasmOpcode.i32_ne, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLT_I4]: [WasmOpcode.i32_lt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_I4]: [WasmOpcode.i32_gt_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_I4]: [WasmOpcode.i32_le_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_I4]: [WasmOpcode.i32_ge_s, WasmOpcode.i32_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CLT_UN_I4]: [WasmOpcode.i32_lt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_UN_I4]: [WasmOpcode.i32_gt_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_UN_I4]: [WasmOpcode.i32_le_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_UN_I4]: [WasmOpcode.i32_ge_u, WasmOpcode.i32_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CEQ_I8]: [WasmOpcode.i64_eq, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CNE_I8]: [WasmOpcode.i64_ne, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLT_I8]: [WasmOpcode.i64_lt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_I8]: [WasmOpcode.i64_gt_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_I8]: [WasmOpcode.i64_le_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_I8]: [WasmOpcode.i64_ge_s, WasmOpcode.i64_load, WasmOpcode.i32_store], + + [MintOpcode.MINT_CLT_UN_I8]: [WasmOpcode.i64_lt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGT_UN_I8]: [WasmOpcode.i64_gt_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CLE_UN_I8]: [WasmOpcode.i64_le_u, WasmOpcode.i64_load, WasmOpcode.i32_store], + [MintOpcode.MINT_CGE_UN_I8]: [WasmOpcode.i64_ge_u, WasmOpcode.i64_load, WasmOpcode.i32_store], }; const relopbranchTable: { [opcode: number]: [comparisonOpcode: MintOpcode, immediateOpcode: WasmOpcode | false, isSafepoint: boolean] | MintOpcode | undefined } = { - [MintOpcode.MINT_BEQ_I4_S]: MintOpcode.MINT_CEQ_I4, - [MintOpcode.MINT_BNE_UN_I4_S]: MintOpcode.MINT_CNE_I4, - [MintOpcode.MINT_BGT_I4_S]: MintOpcode.MINT_CGT_I4, - [MintOpcode.MINT_BGT_UN_I4_S]: MintOpcode.MINT_CGT_UN_I4, - [MintOpcode.MINT_BLT_I4_S]: MintOpcode.MINT_CLT_I4, - [MintOpcode.MINT_BLT_UN_I4_S]: MintOpcode.MINT_CLT_UN_I4, - [MintOpcode.MINT_BGE_I4_S]: MintOpcode.MINT_CGE_I4, - [MintOpcode.MINT_BGE_UN_I4_S]: MintOpcode.MINT_CGE_UN_I4, - [MintOpcode.MINT_BLE_I4_S]: MintOpcode.MINT_CLE_I4, - [MintOpcode.MINT_BLE_UN_I4_S]: MintOpcode.MINT_CLE_UN_I4, - - [MintOpcode.MINT_BEQ_I4_SP]: [MintOpcode.MINT_CEQ_I4, false, true], - [MintOpcode.MINT_BNE_UN_I4_SP]: [MintOpcode.MINT_CNE_I4, false, true], - [MintOpcode.MINT_BGT_I4_SP]: [MintOpcode.MINT_CGT_I4, false, true], - [MintOpcode.MINT_BGT_UN_I4_SP]: [MintOpcode.MINT_CGT_UN_I4, false, true], - [MintOpcode.MINT_BLT_I4_SP]: [MintOpcode.MINT_CLT_I4, false, true], - [MintOpcode.MINT_BLT_UN_I4_SP]: [MintOpcode.MINT_CLT_UN_I4, false, true], - [MintOpcode.MINT_BGE_I4_SP]: [MintOpcode.MINT_CGE_I4, false, true], - [MintOpcode.MINT_BGE_UN_I4_SP]: [MintOpcode.MINT_CGE_UN_I4, false, true], - [MintOpcode.MINT_BLE_I4_SP]: [MintOpcode.MINT_CLE_I4, false, true], - [MintOpcode.MINT_BLE_UN_I4_SP]: [MintOpcode.MINT_CLE_UN_I4, false, true], - - [MintOpcode.MINT_BEQ_I4_IMM_SP]: [MintOpcode.MINT_CEQ_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BNE_UN_I4_IMM_SP]: [MintOpcode.MINT_CNE_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BGT_I4_IMM_SP]: [MintOpcode.MINT_CGT_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BEQ_I4_S]: MintOpcode.MINT_CEQ_I4, + [MintOpcode.MINT_BNE_UN_I4_S]: MintOpcode.MINT_CNE_I4, + [MintOpcode.MINT_BGT_I4_S]: MintOpcode.MINT_CGT_I4, + [MintOpcode.MINT_BGT_UN_I4_S]: MintOpcode.MINT_CGT_UN_I4, + [MintOpcode.MINT_BLT_I4_S]: MintOpcode.MINT_CLT_I4, + [MintOpcode.MINT_BLT_UN_I4_S]: MintOpcode.MINT_CLT_UN_I4, + [MintOpcode.MINT_BGE_I4_S]: MintOpcode.MINT_CGE_I4, + [MintOpcode.MINT_BGE_UN_I4_S]: MintOpcode.MINT_CGE_UN_I4, + [MintOpcode.MINT_BLE_I4_S]: MintOpcode.MINT_CLE_I4, + [MintOpcode.MINT_BLE_UN_I4_S]: MintOpcode.MINT_CLE_UN_I4, + + [MintOpcode.MINT_BEQ_I4_SP]: [MintOpcode.MINT_CEQ_I4, false, true], + [MintOpcode.MINT_BNE_UN_I4_SP]: [MintOpcode.MINT_CNE_I4, false, true], + [MintOpcode.MINT_BGT_I4_SP]: [MintOpcode.MINT_CGT_I4, false, true], + [MintOpcode.MINT_BGT_UN_I4_SP]: [MintOpcode.MINT_CGT_UN_I4, false, true], + [MintOpcode.MINT_BLT_I4_SP]: [MintOpcode.MINT_CLT_I4, false, true], + [MintOpcode.MINT_BLT_UN_I4_SP]: [MintOpcode.MINT_CLT_UN_I4, false, true], + [MintOpcode.MINT_BGE_I4_SP]: [MintOpcode.MINT_CGE_I4, false, true], + [MintOpcode.MINT_BGE_UN_I4_SP]: [MintOpcode.MINT_CGE_UN_I4, false, true], + [MintOpcode.MINT_BLE_I4_SP]: [MintOpcode.MINT_CLE_I4, false, true], + [MintOpcode.MINT_BLE_UN_I4_SP]: [MintOpcode.MINT_CLE_UN_I4, false, true], + + [MintOpcode.MINT_BEQ_I4_IMM_SP]: [MintOpcode.MINT_CEQ_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BNE_UN_I4_IMM_SP]: [MintOpcode.MINT_CNE_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BGT_I4_IMM_SP]: [MintOpcode.MINT_CGT_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BGT_UN_I4_IMM_SP]: [MintOpcode.MINT_CGT_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BLT_I4_IMM_SP]: [MintOpcode.MINT_CLT_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BLT_I4_IMM_SP]: [MintOpcode.MINT_CLT_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BLT_UN_I4_IMM_SP]: [MintOpcode.MINT_CLT_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BGE_I4_IMM_SP]: [MintOpcode.MINT_CGE_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BGE_I4_IMM_SP]: [MintOpcode.MINT_CGE_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BGE_UN_I4_IMM_SP]: [MintOpcode.MINT_CGE_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BLE_I4_IMM_SP]: [MintOpcode.MINT_CLE_I4, WasmOpcode.i32_const, true], + [MintOpcode.MINT_BLE_I4_IMM_SP]: [MintOpcode.MINT_CLE_I4, WasmOpcode.i32_const, true], [MintOpcode.MINT_BLE_UN_I4_IMM_SP]: [MintOpcode.MINT_CLE_UN_I4, WasmOpcode.i32_const, true], - [MintOpcode.MINT_BEQ_I8_S]: MintOpcode.MINT_CEQ_I8, - [MintOpcode.MINT_BNE_UN_I8_S]: MintOpcode.MINT_CNE_I8, - [MintOpcode.MINT_BGT_I8_S]: MintOpcode.MINT_CGT_I8, - [MintOpcode.MINT_BGT_UN_I8_S]: MintOpcode.MINT_CGT_UN_I8, - [MintOpcode.MINT_BLT_I8_S]: MintOpcode.MINT_CLT_I8, - [MintOpcode.MINT_BLT_UN_I8_S]: MintOpcode.MINT_CLT_UN_I8, - [MintOpcode.MINT_BGE_I8_S]: MintOpcode.MINT_CGE_I8, - [MintOpcode.MINT_BGE_UN_I8_S]: MintOpcode.MINT_CGE_UN_I8, - [MintOpcode.MINT_BLE_I8_S]: MintOpcode.MINT_CLE_I8, - [MintOpcode.MINT_BLE_UN_I8_S]: MintOpcode.MINT_CLE_UN_I8, - - [MintOpcode.MINT_BEQ_I8_IMM_SP]: [MintOpcode.MINT_CEQ_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BEQ_I8_S]: MintOpcode.MINT_CEQ_I8, + [MintOpcode.MINT_BNE_UN_I8_S]: MintOpcode.MINT_CNE_I8, + [MintOpcode.MINT_BGT_I8_S]: MintOpcode.MINT_CGT_I8, + [MintOpcode.MINT_BGT_UN_I8_S]: MintOpcode.MINT_CGT_UN_I8, + [MintOpcode.MINT_BLT_I8_S]: MintOpcode.MINT_CLT_I8, + [MintOpcode.MINT_BLT_UN_I8_S]: MintOpcode.MINT_CLT_UN_I8, + [MintOpcode.MINT_BGE_I8_S]: MintOpcode.MINT_CGE_I8, + [MintOpcode.MINT_BGE_UN_I8_S]: MintOpcode.MINT_CGE_UN_I8, + [MintOpcode.MINT_BLE_I8_S]: MintOpcode.MINT_CLE_I8, + [MintOpcode.MINT_BLE_UN_I8_S]: MintOpcode.MINT_CLE_UN_I8, + + [MintOpcode.MINT_BEQ_I8_IMM_SP]: [MintOpcode.MINT_CEQ_I8, WasmOpcode.i64_const, true], // FIXME: Missing compare opcode // [MintOpcode.MINT_BNE_UN_I8_IMM_SP]: [MintOpcode.MINT_CNE_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BGT_I8_IMM_SP]: [MintOpcode.MINT_CGT_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BGT_I8_IMM_SP]: [MintOpcode.MINT_CGT_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BGT_UN_I8_IMM_SP]: [MintOpcode.MINT_CGT_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BLT_I8_IMM_SP]: [MintOpcode.MINT_CLT_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BLT_I8_IMM_SP]: [MintOpcode.MINT_CLT_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BLT_UN_I8_IMM_SP]: [MintOpcode.MINT_CLT_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BGE_I8_IMM_SP]: [MintOpcode.MINT_CGE_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BGE_I8_IMM_SP]: [MintOpcode.MINT_CGE_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BGE_UN_I8_IMM_SP]: [MintOpcode.MINT_CGE_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BLE_I8_IMM_SP]: [MintOpcode.MINT_CLE_I8, WasmOpcode.i64_const, true], + [MintOpcode.MINT_BLE_I8_IMM_SP]: [MintOpcode.MINT_CLE_I8, WasmOpcode.i64_const, true], [MintOpcode.MINT_BLE_UN_I8_IMM_SP]: [MintOpcode.MINT_CLE_UN_I8, WasmOpcode.i64_const, true], - [MintOpcode.MINT_BEQ_R4_S]: MintOpcode.MINT_CEQ_R4, - [MintOpcode.MINT_BNE_UN_R4_S]: JiterpSpecialOpcode.CNE_UN_R4, - [MintOpcode.MINT_BGT_R4_S]: MintOpcode.MINT_CGT_R4, - [MintOpcode.MINT_BGT_UN_R4_S]: MintOpcode.MINT_CGT_UN_R4, - [MintOpcode.MINT_BLT_R4_S]: MintOpcode.MINT_CLT_R4, - [MintOpcode.MINT_BLT_UN_R4_S]: MintOpcode.MINT_CLT_UN_R4, - [MintOpcode.MINT_BGE_R4_S]: MintOpcode.MINT_CGE_R4, - [MintOpcode.MINT_BGE_UN_R4_S]: JiterpSpecialOpcode.CGE_UN_R4, - [MintOpcode.MINT_BLE_R4_S]: MintOpcode.MINT_CLE_R4, - [MintOpcode.MINT_BLE_UN_R4_S]: JiterpSpecialOpcode.CLE_UN_R4, - - [MintOpcode.MINT_BEQ_R8_S]: MintOpcode.MINT_CEQ_R8, - [MintOpcode.MINT_BNE_UN_R8_S]: JiterpSpecialOpcode.CNE_UN_R8, - [MintOpcode.MINT_BGT_R8_S]: MintOpcode.MINT_CGT_R8, - [MintOpcode.MINT_BGT_UN_R8_S]: MintOpcode.MINT_CGT_UN_R8, - [MintOpcode.MINT_BLT_R8_S]: MintOpcode.MINT_CLT_R8, - [MintOpcode.MINT_BLT_UN_R8_S]: MintOpcode.MINT_CLT_UN_R8, - [MintOpcode.MINT_BGE_R8_S]: MintOpcode.MINT_CGE_R8, - [MintOpcode.MINT_BGE_UN_R8_S]: JiterpSpecialOpcode.CGE_UN_R8, - [MintOpcode.MINT_BLE_R8_S]: MintOpcode.MINT_CLE_R8, - [MintOpcode.MINT_BLE_UN_R8_S]: JiterpSpecialOpcode.CLE_UN_R8, + [MintOpcode.MINT_BEQ_R4_S]: MintOpcode.MINT_CEQ_R4, + [MintOpcode.MINT_BNE_UN_R4_S]: JiterpSpecialOpcode.CNE_UN_R4, + [MintOpcode.MINT_BGT_R4_S]: MintOpcode.MINT_CGT_R4, + [MintOpcode.MINT_BGT_UN_R4_S]: MintOpcode.MINT_CGT_UN_R4, + [MintOpcode.MINT_BLT_R4_S]: MintOpcode.MINT_CLT_R4, + [MintOpcode.MINT_BLT_UN_R4_S]: MintOpcode.MINT_CLT_UN_R4, + [MintOpcode.MINT_BGE_R4_S]: MintOpcode.MINT_CGE_R4, + [MintOpcode.MINT_BGE_UN_R4_S]: JiterpSpecialOpcode.CGE_UN_R4, + [MintOpcode.MINT_BLE_R4_S]: MintOpcode.MINT_CLE_R4, + [MintOpcode.MINT_BLE_UN_R4_S]: JiterpSpecialOpcode.CLE_UN_R4, + + [MintOpcode.MINT_BEQ_R8_S]: MintOpcode.MINT_CEQ_R8, + [MintOpcode.MINT_BNE_UN_R8_S]: JiterpSpecialOpcode.CNE_UN_R8, + [MintOpcode.MINT_BGT_R8_S]: MintOpcode.MINT_CGT_R8, + [MintOpcode.MINT_BGT_UN_R8_S]: MintOpcode.MINT_CGT_UN_R8, + [MintOpcode.MINT_BLT_R8_S]: MintOpcode.MINT_CLT_R8, + [MintOpcode.MINT_BLT_UN_R8_S]: MintOpcode.MINT_CLT_UN_R8, + [MintOpcode.MINT_BGE_R8_S]: MintOpcode.MINT_CGE_R8, + [MintOpcode.MINT_BGE_UN_R8_S]: JiterpSpecialOpcode.CGE_UN_R8, + [MintOpcode.MINT_BLE_R8_S]: MintOpcode.MINT_CLE_R8, + [MintOpcode.MINT_BLE_UN_R8_S]: JiterpSpecialOpcode.CLE_UN_R8, }; function emit_binop(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { @@ -2603,7 +2603,6 @@ function emit_branch( builder: WasmBuilder, ip: MintOpcodePtr, frame: NativePointer, opcode: MintOpcode, displacement?: number ): boolean { - const info = OpcodeInfo[opcode]; const isSafepoint = (opcode >= MintOpcode.MINT_BRFALSE_I4_SP) && (opcode <= MintOpcode.MINT_BLT_UN_I8_IMM_SP); eraseInferredState(); @@ -2828,55 +2827,55 @@ function emit_relop_branch( } const mathIntrinsicTable: { [opcode: number]: [isUnary: boolean, isF32: boolean, opcodeOrFuncName: WasmOpcode | string] } = { - [MintOpcode.MINT_SQRT]: [true, false, WasmOpcode.f64_sqrt], - [MintOpcode.MINT_SQRTF]: [true, true, WasmOpcode.f32_sqrt], - [MintOpcode.MINT_CEILING]: [true, false, WasmOpcode.f64_ceil], - [MintOpcode.MINT_CEILINGF]: [true, true, WasmOpcode.f32_ceil], - [MintOpcode.MINT_FLOOR]: [true, false, WasmOpcode.f64_floor], - [MintOpcode.MINT_FLOORF]: [true, true, WasmOpcode.f32_floor], - [MintOpcode.MINT_ABS]: [true, false, WasmOpcode.f64_abs], - [MintOpcode.MINT_ABSF]: [true, true, WasmOpcode.f32_abs], - - [MintOpcode.MINT_ACOS]: [true, false, "acos"], - [MintOpcode.MINT_ACOSF]: [true, true, "acosf"], - [MintOpcode.MINT_ACOSH]: [true, false, "acosh"], - [MintOpcode.MINT_ACOSHF]: [true, true, "acoshf"], - [MintOpcode.MINT_COS]: [true, false, "cos"], - [MintOpcode.MINT_COSF]: [true, true, "cosf"], - [MintOpcode.MINT_ASIN]: [true, false, "asin"], - [MintOpcode.MINT_ASINF]: [true, true, "asinf"], - [MintOpcode.MINT_ASINH]: [true, false, "asinh"], - [MintOpcode.MINT_ASINHF]: [true, true, "asinhf"], - [MintOpcode.MINT_SIN]: [true, false, "sin"], - [MintOpcode.MINT_SINF]: [true, true, "sinf"], - [MintOpcode.MINT_ATAN]: [true, false, "atan"], - [MintOpcode.MINT_ATANF]: [true, true, "atanf"], - [MintOpcode.MINT_ATANH]: [true, false, "atanh"], - [MintOpcode.MINT_ATANHF]: [true, true, "atanhf"], - [MintOpcode.MINT_TAN]: [true, false, "tan"], - [MintOpcode.MINT_TANF]: [true, true, "tanf"], - [MintOpcode.MINT_CBRT]: [true, false, "cbrt"], - [MintOpcode.MINT_CBRTF]: [true, true, "cbrtf"], - [MintOpcode.MINT_EXP]: [true, false, "exp"], - [MintOpcode.MINT_EXPF]: [true, true, "expf"], - [MintOpcode.MINT_LOG]: [true, false, "log"], - [MintOpcode.MINT_LOGF]: [true, true, "logf"], - [MintOpcode.MINT_LOG2]: [true, false, "log2"], - [MintOpcode.MINT_LOG2F]: [true, true, "log2f"], - [MintOpcode.MINT_LOG10]: [true, false, "log10"], - [MintOpcode.MINT_LOG10F]: [true, true, "log10f"], - - [MintOpcode.MINT_MIN]: [false, false, WasmOpcode.f64_min], - [MintOpcode.MINT_MINF]: [false, true, WasmOpcode.f32_min], - [MintOpcode.MINT_MAX]: [false, false, WasmOpcode.f64_max], - [MintOpcode.MINT_MAXF]: [false, true, WasmOpcode.f32_max], - - [MintOpcode.MINT_ATAN2]: [false, false, "atan2"], - [MintOpcode.MINT_ATAN2F]: [false, true, "atan2f"], - [MintOpcode.MINT_POW]: [false, false, "pow"], - [MintOpcode.MINT_POWF]: [false, true, "powf"], - [MintOpcode.MINT_REM_R8]: [false, false, "fmod"], - [MintOpcode.MINT_REM_R4]: [false, true, "fmodf"], + [MintOpcode.MINT_SQRT]: [true, false, WasmOpcode.f64_sqrt], + [MintOpcode.MINT_SQRTF]: [true, true, WasmOpcode.f32_sqrt], + [MintOpcode.MINT_CEILING]: [true, false, WasmOpcode.f64_ceil], + [MintOpcode.MINT_CEILINGF]: [true, true, WasmOpcode.f32_ceil], + [MintOpcode.MINT_FLOOR]: [true, false, WasmOpcode.f64_floor], + [MintOpcode.MINT_FLOORF]: [true, true, WasmOpcode.f32_floor], + [MintOpcode.MINT_ABS]: [true, false, WasmOpcode.f64_abs], + [MintOpcode.MINT_ABSF]: [true, true, WasmOpcode.f32_abs], + + [MintOpcode.MINT_ACOS]: [true, false, "acos"], + [MintOpcode.MINT_ACOSF]: [true, true, "acosf"], + [MintOpcode.MINT_ACOSH]: [true, false, "acosh"], + [MintOpcode.MINT_ACOSHF]: [true, true, "acoshf"], + [MintOpcode.MINT_COS]: [true, false, "cos"], + [MintOpcode.MINT_COSF]: [true, true, "cosf"], + [MintOpcode.MINT_ASIN]: [true, false, "asin"], + [MintOpcode.MINT_ASINF]: [true, true, "asinf"], + [MintOpcode.MINT_ASINH]: [true, false, "asinh"], + [MintOpcode.MINT_ASINHF]: [true, true, "asinhf"], + [MintOpcode.MINT_SIN]: [true, false, "sin"], + [MintOpcode.MINT_SINF]: [true, true, "sinf"], + [MintOpcode.MINT_ATAN]: [true, false, "atan"], + [MintOpcode.MINT_ATANF]: [true, true, "atanf"], + [MintOpcode.MINT_ATANH]: [true, false, "atanh"], + [MintOpcode.MINT_ATANHF]: [true, true, "atanhf"], + [MintOpcode.MINT_TAN]: [true, false, "tan"], + [MintOpcode.MINT_TANF]: [true, true, "tanf"], + [MintOpcode.MINT_CBRT]: [true, false, "cbrt"], + [MintOpcode.MINT_CBRTF]: [true, true, "cbrtf"], + [MintOpcode.MINT_EXP]: [true, false, "exp"], + [MintOpcode.MINT_EXPF]: [true, true, "expf"], + [MintOpcode.MINT_LOG]: [true, false, "log"], + [MintOpcode.MINT_LOGF]: [true, true, "logf"], + [MintOpcode.MINT_LOG2]: [true, false, "log2"], + [MintOpcode.MINT_LOG2F]: [true, true, "log2f"], + [MintOpcode.MINT_LOG10]: [true, false, "log10"], + [MintOpcode.MINT_LOG10F]: [true, true, "log10f"], + + [MintOpcode.MINT_MIN]: [false, false, WasmOpcode.f64_min], + [MintOpcode.MINT_MINF]: [false, true, WasmOpcode.f32_min], + [MintOpcode.MINT_MAX]: [false, false, WasmOpcode.f64_max], + [MintOpcode.MINT_MAXF]: [false, true, WasmOpcode.f32_max], + + [MintOpcode.MINT_ATAN2]: [false, false, "atan2"], + [MintOpcode.MINT_ATAN2F]: [false, true, "atan2f"], + [MintOpcode.MINT_POW]: [false, false, "pow"], + [MintOpcode.MINT_POWF]: [false, true, "powf"], + [MintOpcode.MINT_REM_R8]: [false, false, "fmod"], + [MintOpcode.MINT_REM_R4]: [false, true, "fmodf"], }; function emit_math_intrinsic(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode): boolean { @@ -2939,17 +2938,17 @@ function emit_indirectop(builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOp (opcode <= MintOpcode.MINT_LDIND_OFFSET_IMM_I8) ) || ( - (opcode >= MintOpcode.MINT_STIND_OFFSET_I1) && - (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) - ) || isAddMul; + (opcode >= MintOpcode.MINT_STIND_OFFSET_I1) && + (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) + ) || isAddMul; const isImm = ( (opcode >= MintOpcode.MINT_LDIND_OFFSET_IMM_I1) && (opcode <= MintOpcode.MINT_LDIND_OFFSET_IMM_I8) ) || ( - (opcode >= MintOpcode.MINT_STIND_OFFSET_IMM_I1) && - (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) - ) || isAddMul; + (opcode >= MintOpcode.MINT_STIND_OFFSET_IMM_I1) && + (opcode <= MintOpcode.MINT_STIND_OFFSET_IMM_I8) + ) || isAddMul; let valueVarIndex, addressVarIndex, offsetVarIndex = -1, constantOffset = 0, constantMultiplier = 1; @@ -3316,9 +3315,9 @@ function emit_arrayop(builder: WasmBuilder, frame: NativePointer, ip: MintOpcode const vec128Test = "0061736d0100000001040160000003020100070801047465737400000a090107004100fd111a0b"; -let wasmSimdSupported : boolean | undefined; +let wasmSimdSupported: boolean | undefined; -function getIsWasmSimdSupported () : boolean { +function getIsWasmSimdSupported(): boolean { if (wasmSimdSupported !== undefined) return wasmSimdSupported; @@ -3337,10 +3336,10 @@ function getIsWasmSimdSupported () : boolean { return wasmSimdSupported; } -function get_import_name ( +function get_import_name( builder: WasmBuilder, typeName: string, functionPtr: number -) : string { +): string { const name = `${typeName}_${functionPtr.toString(16)}`; if (typeof (builder.importedFunctions[name]) !== "object") builder.defineImportedFunction("s", name, typeName, false, functionPtr); @@ -3369,11 +3368,11 @@ const simdCreateStoreOps = { [MintOpcode.MINT_SIMD_V128_I8_CREATE]: WasmOpcode.i64_store, }; -function emit_simd ( +function emit_simd( builder: WasmBuilder, ip: MintOpcodePtr, opcode: MintOpcode, opname: string, argCount: number, index: number -) : boolean { +): boolean { // First, if compiling an intrinsic attempt to emit the special vectorized implementation // We only do this if SIMD is enabled since we'll be using the v128 opcodes. if (builder.options.enableSimd && getIsWasmSimdSupported()) { @@ -3470,24 +3469,24 @@ function emit_simd ( } } -function append_simd_store (builder: WasmBuilder, ip: MintOpcodePtr) { +function append_simd_store(builder: WasmBuilder, ip: MintOpcodePtr) { append_stloc_tail(builder, getArgU16(ip, 1), WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_store); } -function append_simd_2_load (builder: WasmBuilder, ip: MintOpcodePtr, loadOp?: WasmSimdOpcode) { +function append_simd_2_load(builder: WasmBuilder, ip: MintOpcodePtr, loadOp?: WasmSimdOpcode) { builder.local("pLocals"); // This || is harmless since v128_load is 0 append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.PREFIX_simd, loadOp || WasmSimdOpcode.v128_load); } -function append_simd_3_load (builder: WasmBuilder, ip: MintOpcodePtr) { +function append_simd_3_load(builder: WasmBuilder, ip: MintOpcodePtr) { builder.local("pLocals"); append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_load); // FIXME: Can rhs be a scalar? We handle shifts separately already append_ldloc(builder, getArgU16(ip, 3), WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_load); } -function append_simd_4_load (builder: WasmBuilder, ip: MintOpcodePtr) { +function append_simd_4_load(builder: WasmBuilder, ip: MintOpcodePtr) { builder.local("pLocals"); append_ldloc(builder, getArgU16(ip, 2), WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_load); append_ldloc(builder, getArgU16(ip, 3), WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_load); @@ -3510,14 +3509,14 @@ const simdShiftTable = new Set([ SimdIntrinsic3.V128_I8_URIGHT_SHIFT, ]); -function append_stloc_simd_zero (builder: WasmBuilder, offset: number) { +function append_stloc_simd_zero(builder: WasmBuilder, offset: number) { builder.local("pLocals"); builder.appendSimd(WasmSimdOpcode.v128_const); builder.appendBytes(new Uint8Array(sizeOfV128)); append_stloc_tail(builder, offset, WasmOpcode.PREFIX_simd, WasmSimdOpcode.v128_store); } -function emit_simd_2 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic2) : boolean { +function emit_simd_2(builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic2): boolean { const simple = cwraps.mono_jiterp_get_simd_opcode(1, index); if (simple) { append_simd_2_load(builder, ip); @@ -3578,7 +3577,7 @@ function emit_simd_2 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrin } } -function emit_simd_3 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic3) : boolean { +function emit_simd_3(builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic3): boolean { const simple = cwraps.mono_jiterp_get_simd_opcode(2, index); if (simple) { const isShift = simdShiftTable.has(index); @@ -3614,7 +3613,7 @@ function emit_simd_3 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrin return false; } -function emit_simd_4 (builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic4) : boolean { +function emit_simd_4(builder: WasmBuilder, ip: MintOpcodePtr, index: SimdIntrinsic4): boolean { const simple = cwraps.mono_jiterp_get_simd_opcode(3, index); if (simple) { append_simd_4_load(builder, ip); From dcaac7b05b75fc501a363ede662056473191ba7d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 9 May 2023 18:34:48 +0200 Subject: [PATCH 11/25] use fixed version of chrome --- eng/testing/ProvisioningVersions.props | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/eng/testing/ProvisioningVersions.props b/eng/testing/ProvisioningVersions.props index 96a82270a9d96c..b295c1b59176c5 100644 --- a/eng/testing/ProvisioningVersions.props +++ b/eng/testing/ProvisioningVersions.props @@ -44,17 +44,17 @@ - true + false - 109.0.5414.119 - 1070088 + 113.0.5672.63 + 1121455 <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1070096 - 109.0.5414.120 - 1070088 + 113.0.5672.64 + 1121455 <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1070094 From fc785ae2f345c6c14b7f7deab87fcf56f8b6f848 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 9 May 2023 18:35:26 +0200 Subject: [PATCH 12/25] fix http on node, fix API propagation on node --- src/mono/wasm/runtime/http.ts | 10 ++++++---- src/mono/wasm/runtime/loader/globals.ts | 3 +++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/mono/wasm/runtime/http.ts b/src/mono/wasm/runtime/http.ts index 38e747f26ea798..ef0ee24edba18e 100644 --- a/src/mono/wasm/runtime/http.ts +++ b/src/mono/wasm/runtime/http.ts @@ -65,11 +65,13 @@ function get_response_headers(res: ResponseExtension): void { if (!res.__headerNames) { res.__headerNames = []; res.__headerValues = []; - const entries: Iterable = (res.headers).entries(); + if (res.headers && (res.headers).entries) { + const entries: Iterable = (res.headers).entries(); - for (const pair of entries) { - res.__headerNames.push(pair[0]); - res.__headerValues.push(pair[1]); + for (const pair of entries) { + res.__headerNames.push(pair[0]); + res.__headerValues.push(pair[1]); + } } } } diff --git a/src/mono/wasm/runtime/loader/globals.ts b/src/mono/wasm/runtime/loader/globals.ts index 49f8d1e903126e..feb3e05c30ef87 100644 --- a/src/mono/wasm/runtime/loader/globals.ts +++ b/src/mono/wasm/runtime/loader/globals.ts @@ -30,6 +30,9 @@ export function setLoaderGlobals( loaderHelpers = globalObjects.loaderHelpers; exportedRuntimeAPI = globalObjects.api; INTERNAL = globalObjects.internal; + Object.assign(exportedRuntimeAPI, { + INTERNAL + }); Object.assign(globalObjects.module, { disableDotnet6Compatibility: true, From f22f159140ffa42534fe37c5c6ef7b2654cab089 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 10 May 2023 10:43:14 +0200 Subject: [PATCH 13/25] fix --- .../build/Microsoft.NET.Sdk.WebAssembly.Browser.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 02e7a191e2603a..aa1199d50f7c83 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -188,7 +188,7 @@ Copyright (c) .NET Foundation. All rights reserved. + Condition="@(WasmNativeAsset->Count()) > 0 and '%(FileName)' == 'dotnet.native' and ('%(Extension)' == '.wasm' or '%(Extension)' == '.js')" /> Date: Wed, 10 May 2023 14:17:46 +0200 Subject: [PATCH 14/25] Fix fingerprinting dotnet.js when requested (= .NET 6+7 Blazor) --- .../build/Microsoft.NET.Sdk.WebAssembly.Browser.targets | 2 ++ .../ComputeWasmBuildAssets.cs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 02e7a191e2603a..47b4cf3206231a 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -55,6 +55,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_AggressiveAttributeTrimming Condition="'$(_AggressiveAttributeTrimming)' == ''">true false true + false false @@ -202,6 +203,7 @@ Copyright (c) .NET Foundation. All rights reserved. InvariantGlobalization="$(_WasmInvariantGlobalization)" CopySymbols="$(_WasmCopyOutputSymbolsToOutputDirectory)" OutputPath="$(OutputPath)" + FingerprintDotNetJs="$(WasmFingerprintDotnetJs)" EnableThreads="$(_WasmEnableThreads)" > diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs index c8367399330a88..d8fe399652dc7a 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs @@ -43,6 +43,8 @@ public class ComputeWasmBuildAssets : Task [Required] public bool CopySymbols { get; set; } + public bool FingerprintDotNetJs { get; set; } + public bool EnableThreads { get; set; } [Output] @@ -109,7 +111,7 @@ public override bool Execute() { string newDotnetJSFileName = null; string newDotNetJSFullPath = null; - if (candidateFileName != "dotnet") + if (candidateFileName != "dotnet" || FingerprintDotNetJs) { var itemHash = FileHasher.GetFileHash(candidate.ItemSpec); newDotnetJSFileName = $"{candidateFileName}.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js"; From 8f1c76376db2fe0323c54acf880eafee1205d11d Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 10 May 2023 14:58:23 +0200 Subject: [PATCH 15/25] wip --- src/mono/wasm/build/WasmApp.targets | 4 +- src/mono/wasm/runtime/assets.ts | 14 +-- .../diagnostics/server_pthread/mock-remote.ts | 4 +- src/mono/wasm/runtime/es6/dotnet.es6.lib.js | 1 - src/mono/wasm/runtime/export-api.ts | 4 +- src/mono/wasm/runtime/invoke-cs.ts | 4 +- src/mono/wasm/runtime/invoke-js.ts | 10 +-- src/mono/wasm/runtime/loader/config.ts | 2 +- src/mono/wasm/runtime/loader/globals.ts | 4 + src/mono/wasm/runtime/loader/polyfills.ts | 10 +-- src/mono/wasm/runtime/loader/run.ts | 90 +++++++++++-------- src/mono/wasm/runtime/loader/worker.ts | 53 +++++++++++ src/mono/wasm/runtime/logging.ts | 4 +- .../runtime/net6-legacy/exports-legacy.ts | 4 +- src/mono/wasm/runtime/polyfills.ts | 1 - .../wasm/runtime/pthreads/browser/index.ts | 4 +- .../shared/emscripten-replacements.ts | 4 +- .../wasm/runtime/pthreads/shared/index.ts | 9 -- .../wasm/runtime/pthreads/worker/index.ts | 43 ++------- src/mono/wasm/runtime/snapshot.ts | 2 +- src/mono/wasm/runtime/startup.ts | 70 +++++++-------- src/mono/wasm/runtime/types/internal.ts | 20 ++++- 22 files changed, 204 insertions(+), 157 deletions(-) create mode 100644 src/mono/wasm/runtime/loader/worker.ts diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index de7b759dfb4fce..94bd9fe54f9d8c 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -329,7 +329,7 @@ false <_HasDotnetWasm Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.wasm'">true - <_HasDotnetJsWorker Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.worker.js'">true + <_HasDotnetJsWorker Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.worker.js'">true <_HasDotnetJsSymbols Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.js.symbols'">true <_HasDotnetNativeJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.native.js'">true <_WasmIcuDataFileName Condition="'$(WasmIcuDataFileName)' != '' and Exists('$(WasmIcuDataFileName)')">$(WasmIcuDataFileName) @@ -347,7 +347,7 @@ - + `Expected ${loaderHelpers.expected_downloaded_assets_count} assets to be downloaded, but only finished ${loaderHelpers.actual_downloaded_assets_count}`); mono_assert(loaderHelpers.actual_instantiated_assets_count == loaderHelpers.expected_instantiated_assets_count, () => `Expected ${loaderHelpers.expected_instantiated_assets_count} assets to be in memory, but only instantiated ${loaderHelpers.actual_instantiated_assets_count}`); loaderHelpers._loaded_files.forEach(value => loaderHelpers.loadedFiles.push(value.url)); - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: all assets are loaded in wasm memory"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: all assets are loaded in wasm memory"); } } diff --git a/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts b/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts index 0355e0ccef7942..97fe3804a2f1e7 100644 --- a/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts +++ b/src/mono/wasm/runtime/diagnostics/server_pthread/mock-remote.ts @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. import monoDiagnosticsMock from "consts:monoDiagnosticsMock"; -import { loaderHelpers } from "../../globals"; import type { Mock } from "../mock"; import { mock } from "../mock"; +import { runtimeHelpers } from "../../globals"; export function importAndInstantiateMock(mockURL: string): Promise { if (monoDiagnosticsMock) { @@ -12,7 +12,7 @@ export function importAndInstantiateMock(mockURL: string): Promise { const scriptURL = mockURL.substring(mockPrefix.length); return import(scriptURL).then((mockModule) => { const script = mockModule.default; - return mock(script, { trace: loaderHelpers.diagnosticTracing }); + return mock(script, { trace: runtimeHelpers.diagnosticTracing }); }); } else { return Promise.resolve(undefined as unknown as Mock); diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js index c7564ada640791..68a88991766d2a 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js @@ -11,7 +11,6 @@ const DISABLE_LEGACY_JS_INTEROP = process.env.DISABLE_LEGACY_JS_INTEROP === "1"; function setup(disableLegacyJsInterop) { const pthreadReplacements = {}; const dotnet_replacements = { - scriptUrl: import.meta.url, fetch: globalThis.fetch, require, updateMemoryViews, diff --git a/src/mono/wasm/runtime/export-api.ts b/src/mono/wasm/runtime/export-api.ts index 2b6134c0ea0da1..68b5a4f65ba659 100644 --- a/src/mono/wasm/runtime/export-api.ts +++ b/src/mono/wasm/runtime/export-api.ts @@ -3,12 +3,12 @@ import type { MonoConfig, APIType } from "./types"; -import { loaderHelpers } from "./globals"; import { mono_wasm_get_assembly_exports } from "./invoke-cs"; import { mono_wasm_set_module_imports } from "./invoke-js"; import { getB32, getF32, getF64, getI16, getI32, getI52, getI64Big, getI8, getU16, getU32, getU52, getU8, setB32, setF32, setF64, setI16, setI32, setI52, setI64Big, setI8, setU16, setU32, setU52, setU8 } from "./memory"; import { mono_run_main, mono_run_main_and_exit } from "./run"; import { mono_wasm_setenv } from "./startup"; +import { runtimeHelpers } from "./globals"; export function export_api(): any { const api: APIType = { @@ -18,7 +18,7 @@ export function export_api(): any { getAssemblyExports: mono_wasm_get_assembly_exports, setModuleImports: mono_wasm_set_module_imports, getConfig: (): MonoConfig => { - return loaderHelpers.config; + return runtimeHelpers.config; }, setHeapB32: setB32, setHeapU8: setU8, diff --git a/src/mono/wasm/runtime/invoke-cs.ts b/src/mono/wasm/runtime/invoke-cs.ts index 990d258e40d1c8..5ab7d467e6dbf2 100644 --- a/src/mono/wasm/runtime/invoke-cs.ts +++ b/src/mono/wasm/runtime/invoke-cs.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import MonoWasmThreads from "consts:monoWasmThreads"; -import { Module, loaderHelpers, runtimeHelpers } from "./globals"; +import { Module, runtimeHelpers } from "./globals"; import { bind_arg_marshal_to_cs } from "./marshal-to-cs"; import { marshal_exception_to_js, bind_arg_marshal_to_js } from "./marshal-to-js"; import { @@ -29,7 +29,7 @@ export function mono_wasm_bind_cs_function(fully_qualified_name: MonoStringRef, const js_fqn = conv_string_root(fqn_root)!; mono_assert(js_fqn, "fully_qualified_name must be string"); - if (loaderHelpers.diagnosticTracing) { + if (runtimeHelpers.diagnosticTracing) { console.debug(`MONO_WASM: Binding [JSExport] ${js_fqn}`); } diff --git a/src/mono/wasm/runtime/invoke-js.ts b/src/mono/wasm/runtime/invoke-js.ts index 47b47e5810f508..4080ff1885a521 100644 --- a/src/mono/wasm/runtime/invoke-js.ts +++ b/src/mono/wasm/runtime/invoke-js.ts @@ -7,7 +7,7 @@ import { setI32_unchecked } from "./memory"; import { conv_string_root, js_string_to_mono_string_root } from "./strings"; import { MonoObject, MonoObjectRef, MonoString, MonoStringRef, JSFunctionSignature, JSMarshalerArguments, WasmRoot, BoundMarshalerToJs, JSFnHandle, BoundMarshalerToCs, JSHandle, MarshalerType } from "./types/internal"; import { Int32Ptr } from "./types/emscripten"; -import { INTERNAL, Module, loaderHelpers } from "./globals"; +import { INTERNAL, Module, runtimeHelpers } from "./globals"; import { bind_arg_marshal_to_js } from "./marshal-to-js"; import { mono_wasm_new_external_root } from "./roots"; import { mono_wasm_symbolicate_string } from "./logging"; @@ -28,7 +28,7 @@ export function mono_wasm_bind_js_function(function_name: MonoStringRef, module_ const js_function_name = conv_string_root(function_name_root)!; const mark = startMeasure(); const js_module_name = conv_string_root(module_name_root)!; - if (loaderHelpers.diagnosticTracing) { + if (runtimeHelpers.diagnosticTracing) { console.debug(`MONO_WASM: Binding [JSImport] ${js_function_name} from ${js_module_name}`); } const fn = mono_wasm_lookup_function(js_function_name, js_module_name); @@ -249,7 +249,7 @@ export function mono_wasm_invoke_import(fn_handle: JSFnHandle, args: JSMarshaler export function mono_wasm_set_module_imports(module_name: string, moduleImports: any) { importedModules.set(module_name, moduleImports); - if (loaderHelpers.diagnosticTracing) + if (runtimeHelpers.diagnosticTracing) console.debug(`MONO_WASM: added module imports '${module_name}'`); } @@ -324,7 +324,7 @@ export function dynamic_import(module_name: string, module_url: string): Promise let promise = importedModulesPromises.get(module_name); const newPromise = !promise; if (newPromise) { - if (loaderHelpers.diagnosticTracing) + if (runtimeHelpers.diagnosticTracing) console.debug(`MONO_WASM: importing ES6 module '${module_name}' from '${module_url}'`); promise = import(/* webpackIgnore: true */module_url); importedModulesPromises.set(module_name, promise); @@ -334,7 +334,7 @@ export function dynamic_import(module_name: string, module_url: string): Promise const module = await promise; if (newPromise) { importedModules.set(module_name, module); - if (loaderHelpers.diagnosticTracing) + if (runtimeHelpers.diagnosticTracing) console.debug(`MONO_WASM: imported ES6 module '${module_name}' from '${module_url}'`); } return module; diff --git a/src/mono/wasm/runtime/loader/config.ts b/src/mono/wasm/runtime/loader/config.ts index a3cad5e37ffda2..28fa63462cce06 100644 --- a/src/mono/wasm/runtime/loader/config.ts +++ b/src/mono/wasm/runtime/loader/config.ts @@ -48,7 +48,7 @@ export function normalizeConfig() { if (config.diagnosticTracing === undefined && BuildConfiguration === "Debug") { config.diagnosticTracing = true; } - loaderHelpers.diagnosticTracing = !!config.diagnosticTracing; + runtimeHelpers.diagnosticTracing = loaderHelpers.diagnosticTracing = !!config.diagnosticTracing; loaderHelpers.assetUniqueQuery = config.assetUniqueQuery; runtimeHelpers.waitForDebugger = config.waitForDebugger; config.startupMemoryCache = !!config.startupMemoryCache; diff --git a/src/mono/wasm/runtime/loader/globals.ts b/src/mono/wasm/runtime/loader/globals.ts index feb3e05c30ef87..f221d467e3b82c 100644 --- a/src/mono/wasm/runtime/loader/globals.ts +++ b/src/mono/wasm/runtime/loader/globals.ts @@ -38,6 +38,10 @@ export function setLoaderGlobals( disableDotnet6Compatibility: true, config: { environmentVariables: {} } }); + Object.assign(runtimeHelpers, { + config: globalObjects.module.config, + diagnosticTracing: false, + }); Object.assign(loaderHelpers, { config: globalObjects.module.config, diagnosticTracing: false, diff --git a/src/mono/wasm/runtime/loader/polyfills.ts b/src/mono/wasm/runtime/loader/polyfills.ts index e1436c57fee5cf..dd757148528be9 100644 --- a/src/mono/wasm/runtime/loader/polyfills.ts +++ b/src/mono/wasm/runtime/loader/polyfills.ts @@ -7,7 +7,8 @@ let node_url: any | undefined = undefined; export async function init_polyfills(module: DotnetModuleInternal): Promise { - loaderHelpers.scriptDirectory = detectScriptDirectory(); + loaderHelpers.scriptUrl = normalizeFileUrl(/* webpackIgnore: true */import.meta.url); + loaderHelpers.scriptDirectory = normalizeDirectoryUrl(loaderHelpers.scriptUrl); loaderHelpers.locateFile = (path) => { if (isPathAbsolute(path)) return path; return loaderHelpers.scriptDirectory + path; @@ -21,7 +22,7 @@ export async function init_polyfills(module: DotnetModuleInternal): Promise mod.createRequire(import.meta.url)); + INTERNAL.require = await import(/* webpackIgnore: true */"module").then(mod => mod.createRequire(/* webpackIgnore: true */import.meta.url)); } else { INTERNAL.require = Promise.resolve(() => { throw new Error("require not supported"); }); } @@ -105,11 +106,6 @@ function normalizeDirectoryUrl(dir: string) { return dir.slice(0, dir.lastIndexOf("/")) + "/"; } -export function detectScriptDirectory(): string { - loaderHelpers.scriptUrl = normalizeFileUrl(import.meta.url); - return normalizeDirectoryUrl(loaderHelpers.scriptUrl); -} - const protocolRx = /^[a-zA-Z][a-zA-Z\d+\-.]*?:\/\//; const windowsAbsoluteRx = /[a-zA-Z]:[\\/]/; function isPathAbsolute(path: string): boolean { diff --git a/src/mono/wasm/runtime/loader/run.ts b/src/mono/wasm/runtime/loader/run.ts index 29cca240524818..3c762a01afa799 100644 --- a/src/mono/wasm/runtime/loader/run.ts +++ b/src/mono/wasm/runtime/loader/run.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import type { MonoConfig, DotnetHostBuilder, DotnetModuleConfig, RuntimeAPI, WebAssemblyStartOptions } from "../types"; -import type { MonoConfigInternal, GlobalObjects, EmscriptenModuleInternal, initializeExportsType, initializeReplacementsType, configureEmscriptenStartupType, configureWorkerStartupType, setGlobalObjectsType, passEmscriptenInternalsType, } from "../types/internal"; +import type { MonoConfigInternal, GlobalObjects, EmscriptenModuleInternal, RuntimeModuleExportsInternal, NativeModuleExportsInternal, } from "../types/internal"; import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_WEB, exportedRuntimeAPI, setLoaderGlobals } from "./globals"; import { deep_merge_config, deep_merge_module, mono_wasm_load_config } from "./config"; @@ -12,6 +12,7 @@ import { resolve_asset_path, start_asset_download } from "./assets"; import { init_polyfills } from "./polyfills"; import { runtimeHelpers, loaderHelpers } from "./globals"; import { init_globalization } from "./icu"; +import { setupPreloadChannelToMainThread } from "./worker"; export const globalObjectsRoot: GlobalObjects = { @@ -349,7 +350,7 @@ export class HostBuilder implements DotnetHostBuilder { } } -export async function createEmscripten(moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)): Promise { +export async function createEmscripten(moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)): Promise { // extract ModuleConfig if (typeof moduleFactory === "function") { const extension = moduleFactory(globalObjectsRoot.api) as any; @@ -366,43 +367,24 @@ export async function createEmscripten(moduleFactory: DotnetModuleConfig | ((api throw new Error("MONO_WASM: Can't use moduleFactory callback of createDotnetRuntime function."); } - if (!module.configSrc && (!module.config || Object.keys(module.config).length === 0 || !module.config.assets)) { - // if config file location nor assets are provided - module.configSrc = "./mono-config.json"; - } - - await init_polyfills(module); - - // download config - await mono_wasm_load_config(module); + return module.ENVIRONMENT_IS_PTHREAD + ? createEmscriptenWorker() + : createEmscriptenMain(); +} - const promises = [ +function importModules() { + runtimeHelpers.runtimeModuleUrl = resolve_asset_path("js-module-runtime").resolvedUrl!; + runtimeHelpers.nativeModuleUrl = resolve_asset_path("js-module-native").resolvedUrl!; + return [ // keep js module names dynamic by using config, in the future we can use feature detection to load different flavors - import(resolve_asset_path("js-module-runtime").resolvedUrl!), - import(resolve_asset_path("js-module-native").resolvedUrl!), + import(runtimeHelpers.runtimeModuleUrl), + import(runtimeHelpers.nativeModuleUrl), ]; +} - start_asset_download(resolve_asset_path("dotnetwasm")).then(asset => { - loaderHelpers.wasmDownloadPromise.promise_control.resolve(asset); - }); - - init_globalization(); - - // TODO call mono_download_assets(); here in parallel ? - - const es6Modules = await Promise.all(promises); - const { initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals, passEmscriptenInternals } = es6Modules[0] as { - setRuntimeGlobals: setGlobalObjectsType, - initializeExports: initializeExportsType, - initializeReplacements: initializeReplacementsType, - configureEmscriptenStartup: configureEmscriptenStartupType, - configureWorkerStartup: configureWorkerStartupType, - passEmscriptenInternals: passEmscriptenInternalsType, - }; - const { default: emscriptenFactory } = es6Modules[1] as { - default: (unificator: Function) => EmscriptenModuleInternal - }; - +function initializeModules(es6Modules: [RuntimeModuleExportsInternal, NativeModuleExportsInternal]) { + const { initializeExports, initializeReplacements, configureEmscriptenStartup, configureWorkerStartup, setRuntimeGlobals, passEmscriptenInternals } = es6Modules[0]; + const { default: emscriptenFactory } = es6Modules[1]; setRuntimeGlobals(globalObjectsRoot); initializeExports(globalObjectsRoot); loaderHelpers.runtimeModuleLoaded.promise_control.resolve(); @@ -417,8 +399,46 @@ export async function createEmscripten(moduleFactory: DotnetModuleConfig | ((api return module; }); +} + +async function createEmscriptenMain(): Promise { + if (!module.configSrc && (!module.config || Object.keys(module.config).length === 0 || !module.config.assets)) { + // if config file location nor assets are provided + module.configSrc = "./mono-config.json"; + } + + await init_polyfills(module); + + // download config + await mono_wasm_load_config(module); + + const promises = importModules(); + + const wasmModuleAsset = resolve_asset_path("dotnetwasm"); + start_asset_download(wasmModuleAsset).then(asset => { + loaderHelpers.wasmDownloadPromise.promise_control.resolve(asset); + }); + + init_globalization(); + // TODO call mono_download_assets(); here in parallel ? + const es6Modules = await Promise.all(promises); + initializeModules(es6Modules as any); await runtimeHelpers.dotnetReady.promise; return exportedRuntimeAPI; } + +async function createEmscriptenWorker(): Promise { + await init_polyfills(module); + + setupPreloadChannelToMainThread(); + + await loaderHelpers.afterConfigLoaded.promise; + + const promises = importModules(); + const es6Modules = await Promise.all(promises); + initializeModules(es6Modules as any); + + return module; +} diff --git a/src/mono/wasm/runtime/loader/worker.ts b/src/mono/wasm/runtime/loader/worker.ts new file mode 100644 index 00000000000000..b4d67066fb8a33 --- /dev/null +++ b/src/mono/wasm/runtime/loader/worker.ts @@ -0,0 +1,53 @@ +import { MonoConfig } from "../types"; +import { MonoConfigInternal } from "../types/internal"; +import { deep_merge_config } from "./config"; +import { ENVIRONMENT_IS_WEB, loaderHelpers } from "./globals"; + +export const monoSymbol = "__mono_message_please_dont_collide__"; //Symbol("mono"); + +export function setupPreloadChannelToMainThread() { + const channel = new MessageChannel(); + const workerPort = channel.port1; + const mainPort = channel.port2; + workerPort.addEventListener("message", (event) => { + const config = JSON.parse(event.data.config) as MonoConfig; + onMonoConfigReceived(config); + workerPort.close(); + mainPort.close(); + }, { once: true }); + workerPort.start(); + self.postMessage(makePreloadMonoMessage(mainPort), [mainPort]); +} + +let workerMonoConfigReceived = false; + +// called when the main thread sends us the mono config +function onMonoConfigReceived(config: MonoConfigInternal): void { + if (workerMonoConfigReceived) { + console.debug("MONO_WASM: mono config already received"); + return; + } + + deep_merge_config(loaderHelpers.config, config); + console.debug("MONO_WASM: mono config received"); + workerMonoConfigReceived = true; + loaderHelpers.afterConfigLoaded.promise_control.resolve(loaderHelpers.config); + + if (ENVIRONMENT_IS_WEB && config.forwardConsoleLogsToWS && typeof globalThis.WebSocket != "undefined") { + loaderHelpers.setup_proxy_console("pthread-worker", console, self.location.href); + } +} + +export function makePreloadMonoMessage(port: TPort): any { + return { + [monoSymbol]: { + mono_cmd: WorkerMonoCommandType.preload, + port + } + }; +} + +const enum WorkerMonoCommandType { + channel_created = "channel_created", + preload = "preload", +} diff --git a/src/mono/wasm/runtime/logging.ts b/src/mono/wasm/runtime/logging.ts index 390286b24da923..d0f93c27b0436a 100644 --- a/src/mono/wasm/runtime/logging.ts +++ b/src/mono/wasm/runtime/logging.ts @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -import { INTERNAL, Module, loaderHelpers } from "./globals"; +import { INTERNAL, Module, runtimeHelpers } from "./globals"; import { CharPtr, VoidPtr } from "./types/emscripten"; export const wasm_func_map = new Map(); @@ -117,5 +117,5 @@ export function parseSymbolMapFile(text: string) { wasm_func_map.set(Number(parts[0]), parts[1]); }); - if (loaderHelpers.diagnosticTracing) console.debug(`MONO_WASM: Loaded ${wasm_func_map.size} symbols`); + if (runtimeHelpers.diagnosticTracing) console.debug(`MONO_WASM: Loaded ${wasm_func_map.size} symbols`); } \ No newline at end of file diff --git a/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts b/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts index 5225d2df8cb7ed..fc661b45b9fc28 100644 --- a/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts +++ b/src/mono/wasm/runtime/net6-legacy/exports-legacy.ts @@ -16,7 +16,7 @@ import { mono_wasm_load_runtime } from "../startup"; import { BINDINGType, MONOType } from "./export-types"; import { mono_wasm_load_data_archive } from "../assets"; import { mono_method_resolve } from "./method-binding"; -import { loaderHelpers } from "../globals"; +import { runtimeHelpers } from "../globals"; export function export_mono_api(): MONOType { return { @@ -37,7 +37,7 @@ export function export_mono_api(): MONOType { mono_wasm_add_assembly: null, mono_wasm_load_runtime, - config: loaderHelpers.config, + config: runtimeHelpers.config, loaded_files: [], // memory accessors diff --git a/src/mono/wasm/runtime/polyfills.ts b/src/mono/wasm/runtime/polyfills.ts index 639bd3209d3f94..597821b56768cd 100644 --- a/src/mono/wasm/runtime/polyfills.ts +++ b/src/mono/wasm/runtime/polyfills.ts @@ -23,7 +23,6 @@ export function initializeReplacements(replacements: EmscriptenReplacements): vo // script location replacements.scriptDirectory = loaderHelpers.scriptDirectory; - Module.mainScriptUrlOrBlob = replacements.scriptUrl;// this is needed by worker threads if (Module.locateFile === Module.__locateFile) { Module.locateFile = loaderHelpers.locateFile; } diff --git a/src/mono/wasm/runtime/pthreads/browser/index.ts b/src/mono/wasm/runtime/pthreads/browser/index.ts index 46bb22a5b443f2..0fbefa9cf94433 100644 --- a/src/mono/wasm/runtime/pthreads/browser/index.ts +++ b/src/mono/wasm/runtime/pthreads/browser/index.ts @@ -5,7 +5,7 @@ import { isMonoWorkerMessageChannelCreated, monoSymbol, makeMonoThreadMessageApp import { pthread_ptr } from "../shared/types"; import { MonoThreadMessage } from "../shared"; import Internals from "../shared/emscripten-internals"; -import { createPromiseController, loaderHelpers } from "../../globals"; +import { createPromiseController, runtimeHelpers } from "../../globals"; import { PromiseController } from "../../types/internal"; import { MonoConfig } from "../../types"; @@ -90,7 +90,7 @@ function monoWorkerMessageHandler(worker: Worker, ev: MessageEvent(thread_id: pthread_ptr, por }; } -export function makePreloadMonoMessage(port: TPort): MonoWorkerMessagePreload { - return { - [monoSymbol]: { - mono_cmd: WorkerMonoCommandType.preload, - port - } - }; -} - export function isMonoWorkerMessage(message: unknown): message is MonoWorkerMessage { return message !== undefined && typeof message === "object" && message !== null && monoSymbol in message; } diff --git a/src/mono/wasm/runtime/pthreads/worker/index.ts b/src/mono/wasm/runtime/pthreads/worker/index.ts index bcc333afc7c61d..8d8c7e6d19aa4f 100644 --- a/src/mono/wasm/runtime/pthreads/worker/index.ts +++ b/src/mono/wasm/runtime/pthreads/worker/index.ts @@ -4,10 +4,10 @@ /// import MonoWasmThreads from "consts:monoWasmThreads"; -import { Module, ENVIRONMENT_IS_PTHREAD, ENVIRONMENT_IS_WEB, loaderHelpers } from "../../globals"; -import { makeChannelCreatedMonoMessage, makePreloadMonoMessage } from "../shared"; +import { Module, ENVIRONMENT_IS_PTHREAD, runtimeHelpers } from "../../globals"; +import { makeChannelCreatedMonoMessage } from "../shared"; import type { pthread_ptr } from "../shared/types"; -import { is_nullish, MonoConfigInternal } from "../../types/internal"; +import { is_nullish } from "../../types/internal"; import type { MonoThreadMessage } from "../shared"; import { PThreadSelf, @@ -17,7 +17,6 @@ import { WorkerThreadEventTarget } from "./events"; import { preRunWorker } from "../../startup"; -import { MonoConfig } from "../../types"; // re-export some of the events types export { @@ -63,19 +62,6 @@ function monoDedicatedChannelMessageFromMainToWorker(event: MessageEvent console.debug("MONO_WASM: got message from main on the dedicated channel", event.data); } -export function setupPreloadChannelToMainThread() { - const channel = new MessageChannel(); - const workerPort = channel.port1; - const mainPort = channel.port2; - workerPort.addEventListener("message", (event) => { - const config = JSON.parse(event.data.config) as MonoConfig; - onMonoConfigReceived(config); - workerPort.close(); - mainPort.close(); - }, { once: true }); - workerPort.start(); - self.postMessage(makePreloadMonoMessage(mainPort), [mainPort]); -} function setupChannelToMainThread(pthread_ptr: pthread_ptr): PThreadSelf { console.debug("MONO_WASM: creating a channel", pthread_ptr); @@ -89,32 +75,13 @@ function setupChannelToMainThread(pthread_ptr: pthread_ptr): PThreadSelf { return pthread_self; } -let workerMonoConfigReceived = false; - -// called when the main thread sends us the mono config -function onMonoConfigReceived(config: MonoConfigInternal): void { - if (workerMonoConfigReceived) { - console.debug("MONO_WASM: mono config already received"); - return; - } - - console.debug("MONO_WASM: mono config received"); - config = loaderHelpers.config = Module.config = Object.assign(Module.config || {} as any, config); - workerMonoConfigReceived = true; - - loaderHelpers.afterConfigLoaded.promise_control.resolve(config); - - if (ENVIRONMENT_IS_WEB && config.forwardConsoleLogsToWS && typeof globalThis.WebSocket != "undefined") { - loaderHelpers.setup_proxy_console("pthread-worker", console, self.location.href); - } -} /// This is an implementation detail function. /// Called in the worker thread from mono when a pthread becomes attached to the mono runtime. export function mono_wasm_pthread_on_pthread_attached(pthread_id: pthread_ptr): void { const self = pthread_self; mono_assert(self !== null && self.pthread_id == pthread_id, "expected pthread_self to be set already when attaching"); - if (loaderHelpers.diagnosticTracing) + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: attaching pthread to runtime 0x" + pthread_id.toString(16)); preRunWorker(); currentWorkerThreadEvents.dispatchEvent(makeWorkerThreadEvent(dotnetPthreadAttached, self)); @@ -128,7 +95,7 @@ export function afterThreadInitTLS(): void { if (ENVIRONMENT_IS_PTHREAD) { const pthread_ptr = (Module)["_pthread_self"](); mono_assert(!is_nullish(pthread_ptr), "pthread_self() returned null"); - if (loaderHelpers.diagnosticTracing) + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: after thread init, pthread ptr 0x" + pthread_ptr.toString(16)); const self = setupChannelToMainThread(pthread_ptr); currentWorkerThreadEvents.dispatchEvent(makeWorkerThreadEvent(dotnetPthreadCreated, self)); diff --git a/src/mono/wasm/runtime/snapshot.ts b/src/mono/wasm/runtime/snapshot.ts index 571f6e9880014d..02b9e452e7bda6 100644 --- a/src/mono/wasm/runtime/snapshot.ts +++ b/src/mono/wasm/runtime/snapshot.ts @@ -140,7 +140,7 @@ async function getCacheKey(): Promise { if (!runtimeHelpers.subtle) { return null; } - const inputs = Object.assign({}, loaderHelpers.config) as any; + const inputs = Object.assign({}, runtimeHelpers.config) as any; // above already has env variables, runtime options, etc if (!inputs.assetsHash) { diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index c298a79a24898f..848629bc7639e4 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -53,6 +53,7 @@ export function configureEmscriptenStartup(module: DotnetModuleInternal): void { } loaderHelpers.out = module.out; loaderHelpers.err = module.err; + module.mainScriptUrlOrBlob = loaderHelpers.scriptUrl;// this is needed by worker threads // these all could be overridden on DotnetModuleConfig, we are chaing them to async below, as opposed to emscripten // when user set configSrc or config, we are running our default startup sequence. @@ -141,7 +142,7 @@ function preInit(userPreInit: (() => void)[]) { const mark = startMeasure(); try { mono_wasm_pre_init_essential(false); - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: preInit"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: preInit"); runtimeHelpers.beforePreInit.promise_control.resolve(); // all user Module.preInit callbacks userPreInit.forEach(fn => fn()); @@ -177,7 +178,7 @@ async function preInitWorkerAsync() { console.debug("MONO_WASM: worker initializing essential C exports and APIs"); const mark = startMeasure(); try { - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: preInitWorker"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: preInitWorker"); runtimeHelpers.beforePreInit.promise_control.resolve(); mono_wasm_pre_init_essential(true); await init_polyfills_async(); @@ -209,7 +210,7 @@ async function preRunAsync(userPreRun: (() => void)[]) { try { await runtimeHelpers.afterInstantiateWasm.promise; await runtimeHelpers.afterPreInit.promise; - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: preRunAsync"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: preRunAsync"); const mark = startMeasure(); // all user Module.preRun callbacks userPreRun.map(fn => fn()); @@ -228,7 +229,7 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { try { // wait for previous stage await runtimeHelpers.afterPreRun.promise; - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: onRuntimeInitialized"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: onRuntimeInitialized"); const mark = startMeasure(); // signal this stage, this will allow pending assets to allocate memory runtimeHelpers.beforeOnRuntimeInitialized.promise_control.resolve(); @@ -237,14 +238,14 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { // Diagnostics early are not supported with memory snapshot. See below how we enable them later. // Please disable startupMemoryCache in order to be able to diagnose or pause runtime startup. - if (MonoWasmThreads && !loaderHelpers.config.startupMemoryCache) { + if (MonoWasmThreads && !runtimeHelpers.config.startupMemoryCache) { await mono_wasm_init_diagnostics(); } // load runtime and apply environment settings (if necessary) await mono_wasm_before_memory_snapshot(); - if (loaderHelpers.config.exitAfterSnapshot) { + if (runtimeHelpers.config.exitAfterSnapshot) { const reason = runtimeHelpers.ExitStatus ? new runtimeHelpers.ExitStatus(0) : new Error("Snapshot taken, exiting because exitAfterSnapshot was set."); @@ -255,7 +256,7 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { } if (MonoWasmThreads) { - if (loaderHelpers.config.startupMemoryCache) { + if (runtimeHelpers.config.startupMemoryCache) { // we could enable diagnostics after the snapshot is taken await mono_wasm_init_diagnostics(); } @@ -270,7 +271,7 @@ async function onRuntimeInitializedAsync(userOnRuntimeInitialized: () => void) { string_decoder.init_fields(); }); - if (loaderHelpers.config.startupOptions && INTERNAL.resourceLoader) { + if (runtimeHelpers.config.startupOptions && INTERNAL.resourceLoader) { if (INTERNAL.resourceLoader.bootConfig.debugBuild && INTERNAL.resourceLoader.bootConfig.cacheBootResources) { INTERNAL.resourceLoader.logToConsole(); } @@ -301,7 +302,7 @@ async function postRunAsync(userpostRun: (() => void)[]) { // wait for previous stage try { await runtimeHelpers.afterOnRuntimeInitialized.promise; - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: postRunAsync"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: postRunAsync"); const mark = startMeasure(); // create /usr/share folder which is SpecialFolder.CommonApplicationData @@ -325,7 +326,7 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void { if (!isWorker) Module.addRunDependency("mono_wasm_pre_init_essential"); - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential"); init_c_exports(); cwraps_internal(INTERNAL); @@ -343,20 +344,20 @@ function mono_wasm_pre_init_essential(isWorker: boolean): void { } async function mono_wasm_pre_init_essential_async(): Promise { - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential_async"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_essential_async"); Module.addRunDependency("mono_wasm_pre_init_essential_async"); await init_polyfills_async(); if (MonoWasmThreads) { - preAllocatePThreadWorkerPool(MONO_PTHREAD_POOL_SIZE, loaderHelpers.config); + preAllocatePThreadWorkerPool(MONO_PTHREAD_POOL_SIZE, runtimeHelpers.config); } Module.removeRunDependency("mono_wasm_pre_init_essential_async"); } async function mono_wasm_pre_init_full(): Promise { - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_full"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_pre_init_full"); Module.addRunDependency("mono_wasm_pre_init_full"); await loaderHelpers.mono_download_assets(); @@ -365,7 +366,7 @@ async function mono_wasm_pre_init_full(): Promise { } async function mono_wasm_after_user_runtime_initialized(): Promise { - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_after_user_runtime_initialized"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_after_user_runtime_initialized"); try { if (!Module.disableDotnet6Compatibility && Module.exports) { // Export emscripten defined in module through EXPORTED_RUNTIME_METHODS @@ -385,7 +386,7 @@ async function mono_wasm_after_user_runtime_initialized(): Promise { } } - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: Initializing mono runtime"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: Initializing mono runtime"); if (Module.onDotnetReady) { try { @@ -460,9 +461,9 @@ async function instantiate_wasm_module( try { let memorySize: number | undefined = undefined; await loaderHelpers.afterConfigLoaded; - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module"); - if (loaderHelpers.config.startupMemoryCache) { + if (runtimeHelpers.config.startupMemoryCache) { memorySize = await getMemorySnapshotSize(); runtimeHelpers.loadedMemorySnapshot = !!memorySize; runtimeHelpers.storeMemorySnapshotPending = !runtimeHelpers.loadedMemorySnapshot; @@ -482,7 +483,7 @@ async function instantiate_wasm_module( assetToLoad.pendingDownload = null as any; // GC assetToLoad.buffer = null as any; // GC - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module done"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: instantiate_wasm_module done"); if (runtimeHelpers.loadedMemorySnapshot) { try { @@ -514,36 +515,36 @@ async function mono_wasm_before_memory_snapshot() { const memoryBytes = await getMemorySnapshot(); mono_assert(memoryBytes!.byteLength === Module.HEAP8.byteLength, "MONO_WASM: Loaded memory is not the expected size"); Module.HEAP8.set(new Int8Array(memoryBytes!), 0); - if (loaderHelpers.diagnosticTracing) console.info("MONO_WASM: Loaded WASM linear memory from browser cache"); + if (runtimeHelpers.diagnosticTracing) console.info("MONO_WASM: Loaded WASM linear memory from browser cache"); // all things below are loaded from the snapshot return; } - for (const k in loaderHelpers.config.environmentVariables) { - const v = loaderHelpers.config.environmentVariables![k]; + for (const k in runtimeHelpers.config.environmentVariables) { + const v = runtimeHelpers.config.environmentVariables![k]; if (typeof (v) === "string") mono_wasm_setenv(k, v); else throw new Error(`Expected environment variable '${k}' to be a string but it was ${typeof v}: '${v}'`); } - if (loaderHelpers.config.startupMemoryCache) { + if (runtimeHelpers.config.startupMemoryCache) { // disable the trampoline for now, we will re-enable it after we stored the snapshot cwraps.mono_jiterp_update_jit_call_dispatcher(0); } - if (loaderHelpers.config.runtimeOptions) - mono_wasm_set_runtime_options(loaderHelpers.config.runtimeOptions); + if (runtimeHelpers.config.runtimeOptions) + mono_wasm_set_runtime_options(runtimeHelpers.config.runtimeOptions); - if (loaderHelpers.config.aotProfilerOptions) - mono_wasm_init_aot_profiler(loaderHelpers.config.aotProfilerOptions); + if (runtimeHelpers.config.aotProfilerOptions) + mono_wasm_init_aot_profiler(runtimeHelpers.config.aotProfilerOptions); - if (loaderHelpers.config.browserProfilerOptions) - mono_wasm_init_browser_profiler(loaderHelpers.config.browserProfilerOptions); + if (runtimeHelpers.config.browserProfilerOptions) + mono_wasm_init_browser_profiler(runtimeHelpers.config.browserProfilerOptions); - mono_wasm_load_runtime("unused", loaderHelpers.config.debugLevel); + mono_wasm_load_runtime("unused", runtimeHelpers.config.debugLevel); // we didn't have snapshot yet and the feature is enabled. Take snapshot now. - if (loaderHelpers.config.startupMemoryCache) { + if (runtimeHelpers.config.startupMemoryCache) { // this would install the mono_jiterp_do_jit_call_indirect cwraps.mono_jiterp_update_jit_call_dispatcher(-1); await storeMemorySnapshot(Module.HEAP8.buffer); @@ -554,12 +555,12 @@ async function mono_wasm_before_memory_snapshot() { } export function mono_wasm_load_runtime(unused?: string, debugLevel?: number): void { - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_load_runtime"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: mono_wasm_load_runtime"); try { const mark = startMeasure(); if (debugLevel == undefined) { debugLevel = 0; - if (loaderHelpers.config.debugLevel) { + if (runtimeHelpers.config.debugLevel) { debugLevel = 0 + debugLevel; } } @@ -576,7 +577,7 @@ export function bindings_init(): void { if (runtimeHelpers.mono_wasm_bindings_is_ready) { return; } - if (loaderHelpers.diagnosticTracing) console.debug("MONO_WASM: bindings_init"); + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: bindings_init"); runtimeHelpers.mono_wasm_bindings_is_ready = true; try { const mark = startMeasure(); @@ -639,10 +640,9 @@ export function mono_wasm_set_main_args(name: string, allRuntimeArguments: strin /// 2. Emscripten does not run any event but preInit in the workers. /// 3. At the point when this executes there is no pthread assigned to the worker yet. export async function configureWorkerStartup(module: DotnetModuleInternal): Promise { - pthreads_worker.setupPreloadChannelToMainThread(); // This is a good place for subsystems to attach listeners for pthreads_worker.currentWorkerThreadEvents pthreads_worker.currentWorkerThreadEvents.addEventListener(pthreads_worker.dotnetPthreadCreated, (ev) => { - if (loaderHelpers.diagnosticTracing) + if (runtimeHelpers.diagnosticTracing) console.debug("MONO_WASM: pthread created 0x" + ev.pthread_self.pthread_id.toString(16)); }); diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts index d7c4fb95e275af..f9a16235228ca2 100644 --- a/src/mono/wasm/runtime/types/internal.ts +++ b/src/mono/wasm/runtime/types/internal.ts @@ -133,6 +133,9 @@ export type LoaderHelpers = { getApplicationEnvironment?: (bootConfigResponse: Response) => string | null; } export type RuntimeHelpers = { + config: MonoConfigInternal; + diagnosticTracing: boolean; + runtime_interop_module: MonoAssembly; runtime_interop_namespace: string; runtime_interop_exports_classname: string; @@ -154,6 +157,8 @@ export type RuntimeHelpers = { updateMemoryViews: () => void runtimeReady: boolean, + runtimeModuleUrl: string + nativeModuleUrl: string allAssetsInMemory: PromiseAndController, dotnetReady: PromiseAndController, memorySnapshotSkippedOrDone: PromiseAndController, @@ -255,7 +260,6 @@ export type EmscriptenReplacements = { updateMemoryViews: Function, pthreadReplacements: PThreadReplacements | undefined | null scriptDirectory: string; - scriptUrl: string noExitRuntime?: boolean; } export interface ExitStatusError { @@ -400,6 +404,7 @@ export declare interface EmscriptenModuleInternal { __locateFile?: (path: string, prefix?: string) => string; locateFile?: (path: string, prefix?: string) => string; mainScriptUrlOrBlob?: string; + ENVIRONMENT_IS_PTHREAD?: boolean; wasmModule: WebAssembly.Instance | null; ready: Promise; asm: { memory?: WebAssembly.Memory }; @@ -438,3 +443,16 @@ export type initializeReplacementsType = (replacements: EmscriptenReplacements) export type configureEmscriptenStartupType = (module: DotnetModuleInternal) => void; export type configureWorkerStartupType = (module: DotnetModuleInternal) => Promise + +export type RuntimeModuleExportsInternal = { + setRuntimeGlobals: setGlobalObjectsType, + initializeExports: initializeExportsType, + initializeReplacements: initializeReplacementsType, + configureEmscriptenStartup: configureEmscriptenStartupType, + configureWorkerStartup: configureWorkerStartupType, + passEmscriptenInternals: passEmscriptenInternalsType, +} + +export type NativeModuleExportsInternal = { + default: (unificator: Function) => EmscriptenModuleInternal +} \ No newline at end of file From aa76c0ae540649d5ecca0110b0c9322e1398e6af Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 10 May 2023 18:45:20 +0200 Subject: [PATCH 16/25] fix --- src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs | 4 ++-- .../GenerateWasmBootJson.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs index 931fb97bc92099..9a6e518a83ecbe 100644 --- a/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs @@ -625,11 +625,11 @@ protected void AssertDotNetNativeFiles(NativeFilesType type, string config, bool // find dotnet*js string? dotnetJsPath = Directory.EnumerateFiles(binFrameworkDir) - .Where(p => Path.GetFileName(p).StartsWith("dotnet.", StringComparison.OrdinalIgnoreCase) && + .Where(p => Path.GetFileName(p).StartsWith("dotnet.native", StringComparison.OrdinalIgnoreCase) && Path.GetFileName(p).EndsWith(".js", StringComparison.OrdinalIgnoreCase)) .SingleOrDefault(); - Assert.True(!string.IsNullOrEmpty(dotnetJsPath), $"[{label}] Expected to find dotnet*js in {binFrameworkDir}"); + Assert.True(!string.IsNullOrEmpty(dotnetJsPath), $"[{label}] Expected to find dotnet.native*js in {binFrameworkDir}"); AssertSameFile(Path.Combine(srcDir, "dotnet.native.js"), dotnetJsPath!, label); if (type != NativeFilesType.FromRuntimePack) diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs index 0e8dc24e3e23a4..c5589c9781cea6 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs @@ -196,7 +196,7 @@ public void WriteBootJson(Stream output, string entryAssemblyName) string.Equals(assetTraitValue, "native", StringComparison.OrdinalIgnoreCase)) { Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a native application resource.", resource.ItemSpec); - if (fileName.StartsWith("dotnet", StringComparison.OrdinalIgnoreCase) && string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) + if (fileName.StartsWith("dotnet.native", StringComparison.OrdinalIgnoreCase) && string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) { behavior = "dotnetwasm"; } From 739057a34bdce033ef599efc0a1fa41e76e9ef25 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 10 May 2023 19:00:01 +0200 Subject: [PATCH 17/25] fix wbt --- .../NativeRebuildTests/NativeRebuildTestsBase.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs index b6a44542b8fec7..52e80cd2f4ab77 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs @@ -165,8 +165,6 @@ internal void CompareStat(IDictionary oldStat, IDictionary oldStat, IDictionary Date: Thu, 11 May 2023 10:42:31 +0200 Subject: [PATCH 18/25] fix wbt --- .../build/Microsoft.NET.Sdk.WebAssembly.Browser.targets | 2 +- .../wasm/Wasm.Build.Tests/Blazor/BuildPublishTests.cs | 4 ++-- src/mono/wasm/Wasm.Build.Tests/Blazor/MiscTests2.cs | 2 +- src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 9bb0ffe001c54d..78f63db4c3ef63 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -189,7 +189,7 @@ Copyright (c) .NET Foundation. All rights reserved. + Condition="@(WasmNativeAsset->Count()) > 0 and ( '%(FileName)' == 'dotnet' or '%(FileName)' == 'dotnet.native' ) and ('%(Extension)' == '.wasm' or '%(Extension)' == '.js')" /> kvp.Key == "dotnet.native.wasm").Any(), $"{msgPrefix} Could not find dotnet.native.wasm entry in blazor.boot.json"); + Assert.True(runtimeObj!.Where(kvp => kvp.Key == (isNet7AndBelow ? "dotnet.wasm" : "dotnet.native.wasm")).Any(), $"{msgPrefix} Could not find dotnet.native.wasm entry in blazor.boot.json"); Assert.True(runtimeObj!.Where(kvp => kvp.Key.StartsWith("dotnet.", StringComparison.OrdinalIgnoreCase) && kvp.Key.EndsWith(".js", StringComparison.OrdinalIgnoreCase)).Any(), $"{msgPrefix} Could not find dotnet.*js in {bootJson}"); From 07c8c5c1399375a3b2df351c269f1c0559422dd9 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 11 May 2023 11:58:30 +0200 Subject: [PATCH 19/25] fix --- .../NativeRebuildTests/NativeRebuildTestsBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs index 52e80cd2f4ab77..d31f9906593b3e 100644 --- a/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs +++ b/src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/NativeRebuildTestsBase.cs @@ -186,7 +186,7 @@ internal void CompareStat(IDictionary oldStat, IDictionary Date: Thu, 11 May 2023 16:11:03 +0200 Subject: [PATCH 20/25] fix SelfContained --- src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props | 1 + .../wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props | 1 + src/mono/wasm/build/WasmApp.InTree.props | 1 + src/mono/wasm/build/WasmApp.LocalBuild.targets | 1 + .../wasm/templates/templates/wasi-console/wasi-console.0.csproj | 1 + 5 files changed, 5 insertions(+) diff --git a/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props b/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props index 216bb0ea3f6a24..2d72803623bdad 100644 --- a/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props +++ b/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props @@ -1,5 +1,6 @@ true + true diff --git a/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props b/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props index 2cae1d8ab96805..cd117d6d7eecaa 100644 --- a/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props +++ b/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props @@ -2,5 +2,6 @@ browser-wasm true + true diff --git a/src/mono/wasm/build/WasmApp.InTree.props b/src/mono/wasm/build/WasmApp.InTree.props index df85ed3bbf382a..6ec9d9d7b99cb6 100644 --- a/src/mono/wasm/build/WasmApp.InTree.props +++ b/src/mono/wasm/build/WasmApp.InTree.props @@ -9,6 +9,7 @@ $([MSBuild]::NormalizeDirectory($(MonoProjectRoot), 'wasm', 'emsdk')) false true + true false false diff --git a/src/mono/wasm/build/WasmApp.LocalBuild.targets b/src/mono/wasm/build/WasmApp.LocalBuild.targets index 50a1a409a49bbc..40dcf565f31492 100644 --- a/src/mono/wasm/build/WasmApp.LocalBuild.targets +++ b/src/mono/wasm/build/WasmApp.LocalBuild.targets @@ -26,6 +26,7 @@ true + true diff --git a/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj b/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj index 3b897107f39435..c35a99d55ccfb3 100644 --- a/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj +++ b/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj @@ -4,5 +4,6 @@ wasi-wasm Exe true + true From 71b2e5708b270360f77eb9dc94f11adeaeae80b4 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 11 May 2023 18:09:13 +0200 Subject: [PATCH 21/25] Revert "fix SelfContained" This reverts commit 138be6524065d90400c1b69832272b54b56c6620. --- src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props | 1 - .../wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props | 1 - src/mono/wasm/build/WasmApp.InTree.props | 1 - src/mono/wasm/build/WasmApp.LocalBuild.targets | 1 - .../wasm/templates/templates/wasi-console/wasi-console.0.csproj | 1 - 5 files changed, 5 deletions(-) diff --git a/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props b/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props index 2d72803623bdad..216bb0ea3f6a24 100644 --- a/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props +++ b/src/mono/wasm/Wasm.Build.Tests/data/Local.Directory.Build.props @@ -1,6 +1,5 @@ true - true diff --git a/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props b/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props index cd117d6d7eecaa..2cae1d8ab96805 100644 --- a/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props +++ b/src/mono/wasm/Wasm.Build.Tests/data/Workloads.Directory.Build.props @@ -2,6 +2,5 @@ browser-wasm true - true diff --git a/src/mono/wasm/build/WasmApp.InTree.props b/src/mono/wasm/build/WasmApp.InTree.props index 6ec9d9d7b99cb6..df85ed3bbf382a 100644 --- a/src/mono/wasm/build/WasmApp.InTree.props +++ b/src/mono/wasm/build/WasmApp.InTree.props @@ -9,7 +9,6 @@ $([MSBuild]::NormalizeDirectory($(MonoProjectRoot), 'wasm', 'emsdk')) false true - true false false diff --git a/src/mono/wasm/build/WasmApp.LocalBuild.targets b/src/mono/wasm/build/WasmApp.LocalBuild.targets index 40dcf565f31492..50a1a409a49bbc 100644 --- a/src/mono/wasm/build/WasmApp.LocalBuild.targets +++ b/src/mono/wasm/build/WasmApp.LocalBuild.targets @@ -26,7 +26,6 @@ true - true diff --git a/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj b/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj index c35a99d55ccfb3..3b897107f39435 100644 --- a/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj +++ b/src/mono/wasm/templates/templates/wasi-console/wasi-console.0.csproj @@ -4,6 +4,5 @@ wasi-wasm Exe true - true From 27bb9b660b4c8fe1f8e3f86471a680e2b7956b55 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 11 May 2023 18:09:29 +0200 Subject: [PATCH 22/25] larrys fix --- .../WorkloadManifest.targets.in | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in index e5c4a1e176e317..00d3e8b023f1d2 100644 --- a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in +++ b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in @@ -30,6 +30,7 @@ + true $(WasmNativeWorkload7) $(WasmNativeWorkload8) $(WasmNativeWorkload) From e0f3b485d2f1b31ecba3887dff7f784dc9be9492 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 11 May 2023 18:19:18 +0200 Subject: [PATCH 23/25] feedback --- .../ComputeWasmPublishAssets.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs index 78abbed7286174..55aea4e9aa884f 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -242,7 +242,10 @@ private List ProcessNativeAssets( if (isDotNetWasm) { - var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.native.wasm"); + var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => { + var name= $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}"; + return name == "dotnet.native.wasm" || name == "dotnet.wasm"; + }); ITaskItem newDotNetWasm = null; if (aotDotNetWasm != null) { @@ -263,6 +266,10 @@ private List ProcessNativeAssets( { filesToRemove.Add(resolved); } + else if (resolvedNativeAssetToPublish.TryGetValue("dotnet.wasm", out var resolved)) + { + filesToRemove.Add(resolved); + } continue; } } @@ -281,7 +288,12 @@ static bool IsAnyDotNetJs(string key) return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal); } - static bool IsDotNetWasm(string key) => string.Equals("dotnet.native.wasm", Path.GetFileName(key), StringComparison.Ordinal); + static bool IsDotNetWasm(string key) + { + var name = Path.GetFileName(key); + return string.Equals("dotnet.native.wasm", name, StringComparison.Ordinal) + || string.Equals("dotnet.wasm", name, StringComparison.Ordinal); + } } private List ProcessSymbolAssets( From abc07d8abf8b7d55120e6737ae9c8946d7636139 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 11 May 2023 18:24:28 +0200 Subject: [PATCH 24/25] fix --- .../ComputeWasmPublishAssets.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs index 55aea4e9aa884f..87467d8ef53f90 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -266,9 +266,9 @@ private List ProcessNativeAssets( { filesToRemove.Add(resolved); } - else if (resolvedNativeAssetToPublish.TryGetValue("dotnet.wasm", out var resolved)) + else if (resolvedNativeAssetToPublish.TryGetValue("dotnet.wasm", out var resolved2)) { - filesToRemove.Add(resolved); + filesToRemove.Add(resolved2); } continue; } @@ -291,7 +291,7 @@ static bool IsAnyDotNetJs(string key) static bool IsDotNetWasm(string key) { var name = Path.GetFileName(key); - return string.Equals("dotnet.native.wasm", name, StringComparison.Ordinal) + return string.Equals("dotnet.native.wasm", name, StringComparison.Ordinal) || string.Equals("dotnet.wasm", name, StringComparison.Ordinal); } } From 00040d352d668fc001dae7cf6b9c31a2529ad941 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 11 May 2023 18:29:12 +0200 Subject: [PATCH 25/25] feedback --- .../GenerateWasmBootJson.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs index c5589c9781cea6..0e8dc24e3e23a4 100644 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs @@ -196,7 +196,7 @@ public void WriteBootJson(Stream output, string entryAssemblyName) string.Equals(assetTraitValue, "native", StringComparison.OrdinalIgnoreCase)) { Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a native application resource.", resource.ItemSpec); - if (fileName.StartsWith("dotnet.native", StringComparison.OrdinalIgnoreCase) && string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) + if (fileName.StartsWith("dotnet", StringComparison.OrdinalIgnoreCase) && string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) { behavior = "dotnetwasm"; }