From da0e0f73e24036a88411dde8158df80e5f4bff01 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 17 Nov 2021 06:52:25 +0100 Subject: [PATCH] [wasm] renames and cleanup before modularization (#61596) - no imports from outer scope - move dotnet to -extern-pre-js - re-enable JS minification with ES2018 - rename main javaScript files to main.js and test-main.js - sample and test script cleanup - rename set_exit_code method - rewrite test start as async method - improve script loading via script element on page in test - use BINDING.bind_static_method instead of INTERNAL where possible - better .d.ts exports - formatted html files - renamed modules.ts to imports.ts which makes more sense - improved error propagation - renamed __initializeImportsAndExports - delayed exit and stdout flush --- eng/pipelines/coreclr/templates/perf-job.yml | 2 +- eng/testing/tests.wasm.targets | 6 +- src/libraries/sendtohelixhelp.proj | 4 +- src/mono/sample/mbr/browser/WasmDelta.csproj | 2 +- src/mono/sample/mbr/browser/index.html | 62 ++++---- .../mbr/browser/{runtime.js => main.js} | 1 - src/mono/sample/wasm/Directory.Build.targets | 4 +- .../Console/Wasm.Console.Bench.Sample.csproj | 2 +- .../Wasm.Browser.Bench.Sample.csproj | 2 +- .../wasm/browser-bench/appstart-frame.html | 4 +- src/mono/sample/wasm/browser-bench/index.html | 137 +++++++++--------- .../browser-bench/{runtime.js => main.js} | 9 +- .../sample/wasm/browser-profile/README.md | 4 +- .../Wasm.BrowserProfile.Sample.csproj | 4 +- .../sample/wasm/browser-profile/index.html | 6 +- .../browser-profile/{runtime.js => main.js} | 37 ++--- .../wasm/browser/Wasm.Browser.Sample.csproj | 2 +- src/mono/sample/wasm/browser/index.html | 75 ++++------ .../wasm/browser/{runtime.js => main.js} | 13 +- .../wasm/console/Wasm.Console.Sample.csproj | 2 +- src/mono/sample/wasm/wasm.mk | 2 +- src/mono/wasm/build/README.md | 4 +- src/mono/wasm/build/WasmApp.Native.targets | 5 +- src/mono/wasm/build/WasmApp.targets | 2 +- .../aot-tests/ProxyProjectForAOTOnHelix.proj | 2 +- .../DebuggerTestSuite/BreakpointTests.cs | 20 +-- .../tests/debugger-test/debugger-driver.html | 2 +- .../tests/debugger-test/debugger-main.js | 23 +++ .../tests/debugger-test/debugger-test.csproj | 4 +- .../tests/debugger-test/runtime-debugger.js | 24 --- src/mono/wasm/runtime/CMakeLists.txt | 2 +- src/mono/wasm/runtime/buffers.ts | 2 +- src/mono/wasm/runtime/corebindings.ts | 2 +- src/mono/wasm/runtime/cs-to-js.ts | 2 +- src/mono/wasm/runtime/cwraps.ts | 2 +- src/mono/wasm/runtime/debug.ts | 2 +- src/mono/wasm/runtime/export-types.ts | 7 + src/mono/wasm/runtime/exports.ts | 109 +++++++++----- .../wasm/runtime/{modules.ts => imports.ts} | 28 +++- src/mono/wasm/runtime/js-to-cs.ts | 2 +- src/mono/wasm/runtime/library-dotnet.js | 8 +- src/mono/wasm/runtime/memory.ts | 38 ++--- src/mono/wasm/runtime/method-binding.ts | 8 +- src/mono/wasm/runtime/method-calls.ts | 2 +- src/mono/wasm/runtime/package.json | 2 +- src/mono/wasm/runtime/profiler.ts | 2 +- src/mono/wasm/runtime/rollup.config.js | 27 ++-- src/mono/wasm/runtime/roots.ts | 2 +- src/mono/wasm/runtime/startup.ts | 69 +++++++-- src/mono/wasm/runtime/strings.ts | 4 +- src/mono/wasm/runtime/tsconfig.json | 2 +- src/mono/wasm/runtime/types.ts | 4 +- src/mono/wasm/runtime/types/emscripten.d.ts | 16 +- src/mono/wasm/runtime/web-socket.ts | 1 + .../wasm/{runtime-test.js => test-main.js} | 134 ++++++++++------- src/tasks/WasmAppBuilder/WasmAppBuilder.cs | 4 +- .../Wasm.Build.Tests/BuildTestBase.cs | 8 +- .../SatelliteAssembliesTests.cs | 2 +- .../Wasm.Build.Tests/Wasm.Build.Tests.csproj | 2 +- src/tests/Common/Directory.Build.targets | 2 +- .../wasm-test-runner/WasmTestRunner.proj | 2 +- src/tests/Directory.Build.targets | 2 +- .../WebAssembly.Browser.HotReload.Test.csproj | 4 +- .../WebAssembly/Browser/HotReload/index.html | 75 ++++------ .../Browser/HotReload/{runtime.js => main.js} | 11 +- ...Assembly.Browser.RuntimeConfig.Test.csproj | 2 +- .../Browser/RuntimeConfig/index.html | 75 ++++------ .../RuntimeConfig/{runtime.js => main.js} | 9 +- 68 files changed, 600 insertions(+), 541 deletions(-) rename src/mono/sample/mbr/browser/{runtime.js => main.js} (95%) rename src/mono/sample/wasm/browser-bench/{runtime.js => main.js} (74%) rename src/mono/sample/wasm/browser-profile/{runtime.js => main.js} (66%) rename src/mono/sample/wasm/browser/{runtime.js => main.js} (71%) create mode 100644 src/mono/wasm/debugger/tests/debugger-test/debugger-main.js delete mode 100644 src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js create mode 100644 src/mono/wasm/runtime/export-types.ts rename src/mono/wasm/runtime/{modules.ts => imports.ts} (58%) rename src/mono/wasm/{runtime-test.js => test-main.js} (73%) rename src/tests/FunctionalTests/WebAssembly/Browser/HotReload/{runtime.js => main.js} (72%) rename src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/{runtime.js => main.js} (71%) diff --git a/eng/pipelines/coreclr/templates/perf-job.yml b/eng/pipelines/coreclr/templates/perf-job.yml index 6802056be03..50941e60f1c 100644 --- a/eng/pipelines/coreclr/templates/perf-job.yml +++ b/eng/pipelines/coreclr/templates/perf-job.yml @@ -135,7 +135,7 @@ jobs: artifactName: BrowserWasm displayName: BrowserWasm - - script: "mkdir $(librariesDownloadDir)/bin/wasm;unzip -o $(librariesDownloadDir)/BrowserWasm/artifacts/packages/Release/Shipping/Microsoft.NETCore.App.Runtime.Mono.browser-wasm.7.0.0-ci.nupkg data/* runtimes/* -d $(librariesDownloadDir)/bin/wasm;cp src/mono/wasm/runtime-test.js $(librariesDownloadDir)/bin/wasm/runtime-test.js;find $(librariesDownloadDir)/bin/wasm -type f -exec chmod 664 {} \\;" + - script: "mkdir $(librariesDownloadDir)/bin/wasm;unzip -o $(librariesDownloadDir)/BrowserWasm/artifacts/packages/Release/Shipping/Microsoft.NETCore.App.Runtime.Mono.browser-wasm.7.0.0-ci.nupkg data/* runtimes/* -d $(librariesDownloadDir)/bin/wasm;cp src/mono/wasm/test-main.js $(librariesDownloadDir)/bin/wasm/test-main.js;find $(librariesDownloadDir)/bin/wasm -type f -exec chmod 664 {} \\;" displayName: "Create wasm directory (Linux)" # Download mono AOT diff --git a/eng/testing/tests.wasm.targets b/eng/testing/tests.wasm.targets index 00aa7b19f17..53b0f025414 100644 --- a/eng/testing/tests.wasm.targets +++ b/eng/testing/tests.wasm.targets @@ -23,13 +23,13 @@ <_XHarnessArgs Condition="'$(OS)' != 'Windows_NT'">wasm $XHARNESS_COMMAND --app=. --output-directory=$XHARNESS_OUT <_XHarnessArgs Condition="'$(OS)' == 'Windows_NT'">wasm %XHARNESS_COMMAND% --app=. --output-directory=%XHARNESS_OUT% - <_XHarnessArgs Condition="'$(Scenario)' != 'WasmTestOnBrowser' and '$(Scenario)' != 'BuildWasmApps'">$(_XHarnessArgs) --engine=$(JSEngine) $(JSEngineArgs) --js-file=runtime.js + <_XHarnessArgs Condition="'$(Scenario)' != 'WasmTestOnBrowser' and '$(Scenario)' != 'BuildWasmApps'">$(_XHarnessArgs) --engine=$(JSEngine) $(JSEngineArgs) --js-file=main.js <_XHarnessArgs Condition="'$(BrowserHost)' == 'windows'">$(_XHarnessArgs) --browser=chrome --browser-path=%HELIX_CORRELATION_PAYLOAD%\chrome-win\chrome.exe <_XHarnessArgs Condition="'$(IsFunctionalTest)' == 'true'" >$(_XHarnessArgs) --expected-exit-code=$(ExpectedExitCode) <_XHarnessArgs Condition="'$(WasmXHarnessArgs)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgs) <_AppArgs Condition="'$(IsFunctionalTest)' != 'true' and '$(Scenario)' != 'BuildWasmApps'">--run WasmTestRunner.dll $(AssemblyName).dll - <_AppArgs Condition="'$(IsFunctionalTest)' == 'true'">--run $(AssemblyName).dll --testing + <_AppArgs Condition="'$(IsFunctionalTest)' == 'true'">--run $(AssemblyName).dll <_AppArgs Condition="'$(WasmTestAppArgs)' != ''">$(_AppArgs) $(WasmTestAppArgs) @@ -161,7 +161,7 @@ $(BundleDir) WasmTestRunner.dll - $(MonoProjectRoot)\wasm\runtime-test.js + $(MonoProjectRoot)\wasm\test-main.js $(InvariantGlobalization) true false diff --git a/src/libraries/sendtohelixhelp.proj b/src/libraries/sendtohelixhelp.proj index 3eac0bacd92..83eeca33b06 100644 --- a/src/libraries/sendtohelixhelp.proj +++ b/src/libraries/sendtohelixhelp.proj @@ -491,7 +491,7 @@ %(Identity) - $(ExecXHarnessCmd) wasm $(XHarnessCommand) --app=. --engine=V8 --engine-arg=--stack-trace-limit=1000 --js-file=runtime.js --output-directory=$(XHarnessOutput) -- --run %(FileName).dll + $(ExecXHarnessCmd) wasm $(XHarnessCommand) --app=. --engine=V8 --engine-arg=--stack-trace-limit=1000 --js-file=main.js --output-directory=$(XHarnessOutput) -- --run %(FileName).dll @@ -501,7 +501,7 @@ %(Identity) - $(ExecXHarnessCmd) wasm $(XHarnessCommand) --app=. --browser=Chrome $(XHarnessBrowserPathArg) --html-file=index.html --output-directory=$(XHarnessOutput) -- %(FileName).dll --testing + $(ExecXHarnessCmd) wasm $(XHarnessCommand) --app=. --browser=Chrome $(XHarnessBrowserPathArg) --html-file=index.html --output-directory=$(XHarnessOutput) -- %(FileName).dll diff --git a/src/mono/sample/mbr/browser/WasmDelta.csproj b/src/mono/sample/mbr/browser/WasmDelta.csproj index c150529f753..5cc4b15f095 100644 --- a/src/mono/sample/mbr/browser/WasmDelta.csproj +++ b/src/mono/sample/mbr/browser/WasmDelta.csproj @@ -7,7 +7,7 @@ bin $(MSBuildProjectDirectory)\bin\$(Configuration)\AppBundle\ - runtime.js + main.js false diff --git a/src/mono/sample/mbr/browser/index.html b/src/mono/sample/mbr/browser/index.html index 6122370dd9d..91ccdf9c1e4 100644 --- a/src/mono/sample/mbr/browser/index.html +++ b/src/mono/sample/mbr/browser/index.html @@ -2,37 +2,37 @@ - - TESTS - - - - - - Result from Sample.Test.TestMeaning: -
- Click here (upto 2 times): -
- - - + + Hot Reload Sample + + + + + + Result from Sample.Test.TestMeaning: +
+ Click here (upto 2 times): +
+ + + + - - + \ No newline at end of file diff --git a/src/mono/sample/mbr/browser/runtime.js b/src/mono/sample/mbr/browser/main.js similarity index 95% rename from src/mono/sample/mbr/browser/runtime.js rename to src/mono/sample/mbr/browser/main.js index 36feada2026..6294d62187e 100644 --- a/src/mono/sample/mbr/browser/runtime.js +++ b/src/mono/sample/mbr/browser/main.js @@ -3,7 +3,6 @@ "use strict"; var Module = { - config: null, configSrc: "./mono-config.json", onConfigLoaded: function () { MONO.config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; diff --git a/src/mono/sample/wasm/Directory.Build.targets b/src/mono/sample/wasm/Directory.Build.targets index f0b90a539a9..95415ef67fb 100644 --- a/src/mono/sample/wasm/Directory.Build.targets +++ b/src/mono/sample/wasm/Directory.Build.targets @@ -14,12 +14,12 @@ - + - + diff --git a/src/mono/sample/wasm/browser-bench/Console/Wasm.Console.Bench.Sample.csproj b/src/mono/sample/wasm/browser-bench/Console/Wasm.Console.Bench.Sample.csproj index d60474926aa..ab8a632046f 100644 --- a/src/mono/sample/wasm/browser-bench/Console/Wasm.Console.Bench.Sample.csproj +++ b/src/mono/sample/wasm/browser-bench/Console/Wasm.Console.Bench.Sample.csproj @@ -1,7 +1,7 @@ true - $(MonoProjectRoot)\wasm\runtime-test.js + $(MonoProjectRoot)\wasm\test-main.js true true diff --git a/src/mono/sample/wasm/browser-bench/Wasm.Browser.Bench.Sample.csproj b/src/mono/sample/wasm/browser-bench/Wasm.Browser.Bench.Sample.csproj index 68366a982e9..89c7feed07e 100644 --- a/src/mono/sample/wasm/browser-bench/Wasm.Browser.Bench.Sample.csproj +++ b/src/mono/sample/wasm/browser-bench/Wasm.Browser.Bench.Sample.csproj @@ -2,7 +2,7 @@ false - runtime.js + main.js true diff --git a/src/mono/sample/wasm/browser-bench/appstart-frame.html b/src/mono/sample/wasm/browser-bench/appstart-frame.html index 4e24c6e9663..84f08323305 100644 --- a/src/mono/sample/wasm/browser-bench/appstart-frame.html +++ b/src/mono/sample/wasm/browser-bench/appstart-frame.html @@ -11,7 +11,7 @@ - + diff --git a/src/mono/sample/wasm/browser-bench/index.html b/src/mono/sample/wasm/browser-bench/index.html index b163465aa62..bec077fe532 100644 --- a/src/mono/sample/wasm/browser-bench/index.html +++ b/src/mono/sample/wasm/browser-bench/index.html @@ -2,85 +2,78 @@ - - TESTS - - - - - - - Output:

- - - + }, - + ReachedManaged: async function () { + AppStart.Construct(); + try { + await AppStart.WaitForReached(); + } finally { + AppStart.RemoveFrame(); + } + } + }; + + + + + - - + \ No newline at end of file diff --git a/src/mono/sample/wasm/browser-bench/runtime.js b/src/mono/sample/wasm/browser-bench/main.js similarity index 74% rename from src/mono/sample/wasm/browser-bench/runtime.js rename to src/mono/sample/wasm/browser-bench/main.js index f810b524f6a..40c3e7f6732 100644 --- a/src/mono/sample/wasm/browser-bench/runtime.js +++ b/src/mono/sample/wasm/browser-bench/main.js @@ -3,18 +3,17 @@ "use strict"; var Module = { - config: null, configSrc: "./mono-config.json", - onDotNetReady: function () { + onDotNetReady: () => { try { App.init(); } catch (error) { console.log("exception: " + error); - test_exit(1); + set_exit_code(1, error); throw (error); } }, - onAbort: function (err) { - test_exit(1); + onAbort: (error) => { + set_exit_code(1, error); }, }; diff --git a/src/mono/sample/wasm/browser-profile/README.md b/src/mono/sample/wasm/browser-profile/README.md index 26afb138671..909b296c520 100644 --- a/src/mono/sample/wasm/browser-profile/README.md +++ b/src/mono/sample/wasm/browser-profile/README.md @@ -9,11 +9,11 @@ public static void StopProfile(){} ``` -2. Initialize the profiler in the main javascript (e.g. runtime.js) +2. Initialize the profiler in the main javascript (e.g. main.js) ``` var Module = { - onRuntimeInitialized: function () { + onConfigLoaded: () => { ... if (config.enable_profiler) diff --git a/src/mono/sample/wasm/browser-profile/Wasm.BrowserProfile.Sample.csproj b/src/mono/sample/wasm/browser-profile/Wasm.BrowserProfile.Sample.csproj index 9d14836ecb4..be10935e8bc 100644 --- a/src/mono/sample/wasm/browser-profile/Wasm.BrowserProfile.Sample.csproj +++ b/src/mono/sample/wasm/browser-profile/Wasm.BrowserProfile.Sample.csproj @@ -1,7 +1,7 @@ true - runtime.js + main.js aot; @@ -9,4 +9,6 @@ + + diff --git a/src/mono/sample/wasm/browser-profile/index.html b/src/mono/sample/wasm/browser-profile/index.html index de4a5599e94..db4344793d2 100644 --- a/src/mono/sample/wasm/browser-profile/index.html +++ b/src/mono/sample/wasm/browser-profile/index.html @@ -3,15 +3,15 @@ - TESTS + Profiler Sample - + Result from Sample.Test.TestMeaning: - + diff --git a/src/mono/sample/wasm/browser-profile/runtime.js b/src/mono/sample/wasm/browser-profile/main.js similarity index 66% rename from src/mono/sample/wasm/browser-profile/runtime.js rename to src/mono/sample/wasm/browser-profile/main.js index ebedaba70e2..4f9abe18afd 100644 --- a/src/mono/sample/wasm/browser-profile/runtime.js +++ b/src/mono/sample/wasm/browser-profile/main.js @@ -3,10 +3,8 @@ "use strict"; var Module = { - is_testing: false, - config: null, configSrc: "./mono-config.json", - onConfigLoaded: function () { + onConfigLoaded: () => { if (MONO.config.enable_profiler) { MONO.config.aot_profiler_options = { write_at: "Sample.Test::StopProfile", @@ -14,42 +12,37 @@ var Module = { } } }, - onDotNetReady: function () { + onDotNetReady: () => { try { Module.init(); } catch (error) { - test_exit(1); + set_exit_code(1, error); throw (error); } }, - onAbort: function (err) { - test_exit(1); + onAbort: (error) => { + set_exit_code(1, error); }, - init: function () { + init: () => { console.log("not ready yet") - const ret = INTERNAL.call_static_method("[Wasm.BrowserProfile.Sample] Sample.Test:TestMeaning", []); + const testMeaning = BINDING.bind_static_method("[Wasm.BrowserProfile.Sample] Sample.Test:TestMeaning"); + const stopProfile = BINDING.bind_static_method("[Wasm.BrowserProfile.Sample] Sample.Test:StopProfile"); + const ret = testMeaning(); document.getElementById("out").innerHTML = ret; console.log("ready"); - if (Module.is_testing) { - console.debug(`ret: ${ret}`); - let exit_code = ret == 42 ? 0 : 1; - Module.test_exit(exit_code); - } + console.debug(`ret: ${ret}`); + let exit_code = ret == 42 ? 0 : 1; + Module.set_exit_code(exit_code); if (MONO.config.enable_profiler) { - INTERNAL.call_static_method("[Wasm.BrowserProfile.Sample] Sample.Test:StopProfile", []); + stopProfile(); Module.saveProfile(); } }, - test_exit: function (exit_code) { - if (!Module.is_testing) { - console.log(`test_exit: ${exit_code}`); - return; - } - + set_exit_code: (exit_code, reason) => { /* Set result in a tests_done element, to be read by xharness */ const tests_done_elem = document.createElement("label"); tests_done_elem.id = "tests_done"; @@ -59,7 +52,7 @@ var Module = { console.log(`WASM EXIT ${exit_code}`); }, - saveProfile: function () { + saveProfile: () => { const a = document.createElement('a'); const blob = new Blob([INTERNAL.aot_profile_data]); a.href = URL.createObjectURL(blob); diff --git a/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj b/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj index 15386dece90..eb9934dc662 100644 --- a/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj +++ b/src/mono/sample/wasm/browser/Wasm.Browser.Sample.csproj @@ -2,7 +2,7 @@ Debug true - runtime.js + main.js true embedded 1 diff --git a/src/mono/sample/wasm/browser/index.html b/src/mono/sample/wasm/browser/index.html index cedcae5715a..2fa08c756cb 100644 --- a/src/mono/sample/wasm/browser/index.html +++ b/src/mono/sample/wasm/browser/index.html @@ -2,55 +2,42 @@ - - TESTS - - - - - - Result from Sample.Test.TestMeaning: - - + console.debug(`ret: ${ret}`); + let exit_code = ret == 42 ? 0 : 1; + set_exit_code(exit_code); + }, + }; + + + - + - \ No newline at end of file diff --git a/src/mono/sample/wasm/browser/runtime.js b/src/mono/sample/wasm/browser/main.js similarity index 71% rename from src/mono/sample/wasm/browser/runtime.js rename to src/mono/sample/wasm/browser/main.js index ef84c7108e8..9e347d4d346 100644 --- a/src/mono/sample/wasm/browser/runtime.js +++ b/src/mono/sample/wasm/browser/main.js @@ -2,19 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. "use strict"; + var Module = { - config: null, configSrc: "./mono-config.json", - onDotNetReady: function () { + onDotNetReady: () => { try { App.init(); } catch (error) { - test_exit(1); + set_exit_code(1, error); throw (error); } }, - onAbort: function () { - test_exit(1); - + onAbort: (error) => { + set_exit_code(1, error); }, -}; +}; \ No newline at end of file diff --git a/src/mono/sample/wasm/console/Wasm.Console.Sample.csproj b/src/mono/sample/wasm/console/Wasm.Console.Sample.csproj index 237718ebecb..1dabb4aa0c7 100644 --- a/src/mono/sample/wasm/console/Wasm.Console.Sample.csproj +++ b/src/mono/sample/wasm/console/Wasm.Console.Sample.csproj @@ -1,7 +1,7 @@ true - $(MonoProjectRoot)\wasm\runtime-test.js + $(MonoProjectRoot)\wasm\test-main.js true diff --git a/src/mono/sample/wasm/wasm.mk b/src/mono/sample/wasm/wasm.mk index fb11cf97570..5a1c7013348 100644 --- a/src/mono/sample/wasm/wasm.mk +++ b/src/mono/sample/wasm/wasm.mk @@ -30,4 +30,4 @@ run-browser: fi run-console: - cd bin/$(CONFIG)/AppBundle && ~/.jsvu/v8 --stack-trace-limit=1000 --single-threaded --expose_wasm runtime.js -- $(DOTNET_MONO_LOG_LEVEL) --run $(CONSOLE_DLL) $(ARGS) + cd bin/$(CONFIG)/AppBundle && ~/.jsvu/v8 --stack-trace-limit=1000 --single-threaded --expose_wasm main.js -- $(DOTNET_MONO_LOG_LEVEL) --run $(CONSOLE_DLL) $(ARGS) diff --git a/src/mono/wasm/build/README.md b/src/mono/wasm/build/README.md index 8d4920a7be5..79b9ef30f46 100644 --- a/src/mono/wasm/build/README.md +++ b/src/mono/wasm/build/README.md @@ -10,9 +10,9 @@ Wasm app build can run in two scenarios: A dotnet wasm app has some native wasm files (`dotnet.wasm`, and `dotnet.js`). How these files are obtained, or generated: 1. Build - a. with no native libraries referenced (AOT setting is ignored here) + - a. with no native libraries referenced (AOT setting is ignored here) - files from the runtime pack are used as-is - b. with native libraries referenced + - b. with native libraries referenced - dotnet.wasm is relinked with the native libraries 2. Publish - dotnet.wasm is relinked with the native libraries, and updated pinvoke/icalls from the trimmed assemblies diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index ca1f5041eab..b33b74d1611 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -223,7 +223,7 @@ <_WasmRuntimePackSrcFile ObjectFile="$(_WasmIntermediateOutputPath)%(FileName).o" /> <_DotnetJSSrcFile Include="$(_WasmRuntimePackSrcDir)\*.js" Exclude="$(_WasmRuntimePackSrcDir)\*.iffe.js"/> - <_WasmExtraJSFile Include="$(_WasmRuntimePackSrcDir)\*.iffe.js" Kind="pre-js" /> + <_WasmExtraJSFile Include="$(_WasmRuntimePackSrcDir)\*.iffe.js" Kind="extern-pre-js" /> <_WasmNativeFileForLinking Include="@(NativeFileReference)" /> @@ -353,8 +353,9 @@ <_EmccLinkStepArgs Include="--js-library "%(_WasmExtraJSFile.Identity)"" Condition="'%(_WasmExtraJSFile.Kind)' == 'js-library'" /> <_EmccLinkStepArgs Include="--pre-js "%(_WasmExtraJSFile.Identity)"" Condition="'%(_WasmExtraJSFile.Kind)' == 'pre-js'" /> + <_EmccLinkStepArgs Include="--extern-pre-js "%(_WasmExtraJSFile.Identity)"" Condition="'%(_WasmExtraJSFile.Kind)' == 'extern-pre-js'" /> <_EmccLinkStepArgs Include="--post-js "%(_WasmExtraJSFile.Identity)"" Condition="'%(_WasmExtraJSFile.Kind)' == 'post-js'" /> - <_WasmLinkDependencies Include="@(_WasmExtraJSFile)" Condition="'%(_WasmExtraJSFile.Kind)' == 'js-library' or '%(_WasmExtraJSFile.Kind)' == 'pre-js' or '%(_WasmExtraJSFile.Kind)' == 'post-js'" /> + <_WasmLinkDependencies Include="@(_WasmExtraJSFile)" Condition="'%(_WasmExtraJSFile.Kind)' == 'js-library' or '%(_WasmExtraJSFile.Kind)' == 'pre-js' or '%(_WasmExtraJSFile.Kind)' == 'post-js' or '%(_WasmExtraJSFile.Kind)' == 'extern-post-js'" /> <_EmccLinkStepArgs Include=""%(_WasmNativeFileForLinking.Identity)"" /> <_WasmLinkDependencies Include="@(_WasmNativeFileForLinking)" /> diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index 9c96d759a22..85195c1ae63 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -299,7 +299,7 @@ diff --git a/src/mono/wasm/data/aot-tests/ProxyProjectForAOTOnHelix.proj b/src/mono/wasm/data/aot-tests/ProxyProjectForAOTOnHelix.proj index 65a0df19fb6..51dcde0db6c 100644 --- a/src/mono/wasm/data/aot-tests/ProxyProjectForAOTOnHelix.proj +++ b/src/mono/wasm/data/aot-tests/ProxyProjectForAOTOnHelix.proj @@ -29,7 +29,7 @@ $(TestRootDir)AppBundle\ $(OriginalPublishDir)WasmTestRunner.dll - $(OriginalPublishDir)runtime-test.js + $(OriginalPublishDir)test-main.js true diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs index 398df51a299..0e7f79f7a2a 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/BreakpointTests.cs @@ -27,8 +27,8 @@ public async Task CreateGoodBreakpoint() Assert.NotNull(loc["scriptId"]); Assert.Equal("dotnet://debugger-test.dll/debugger-test.cs", scripts[loc["scriptId"]?.Value()]); - Assert.Equal(10, loc["lineNumber"]); - Assert.Equal(8, loc["columnNumber"]); + Assert.Equal(10, (int)loc["lineNumber"]); + Assert.Equal(8, (int)loc["columnNumber"]); } [Fact] @@ -45,8 +45,8 @@ public async Task CreateJSBreakpoint() var loc = bp1_res.Value["locations"]?.Value()[0]; Assert.NotNull(loc["scriptId"]); - Assert.Equal(13, loc["lineNumber"]); - Assert.Equal(24, loc["columnNumber"]); + Assert.Equal(13, (int)loc["lineNumber"]); + Assert.Equal(24, (int)loc["columnNumber"]); var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 33); @@ -56,8 +56,8 @@ public async Task CreateJSBreakpoint() var loc2 = bp2_res.Value["locations"]?.Value()[0]; Assert.NotNull(loc2["scriptId"]); - Assert.Equal(13, loc2["lineNumber"]); - Assert.Equal(33, loc2["columnNumber"]); + Assert.Equal(13, (int)loc2["lineNumber"]); + Assert.Equal(33, (int)loc2["columnNumber"]); } [Fact] @@ -73,8 +73,8 @@ public async Task CreateJS0Breakpoint() var loc = bp1_res.Value["locations"]?.Value()[0]; Assert.NotNull(loc["scriptId"]); - Assert.Equal(13, loc["lineNumber"]); - Assert.Equal(24, loc["columnNumber"]); + Assert.Equal(13, (int)loc["lineNumber"]); + Assert.Equal(24, (int)loc["columnNumber"]); var bp2_res = await SetBreakpoint("/debugger-driver.html", 13, 33); @@ -84,8 +84,8 @@ public async Task CreateJS0Breakpoint() var loc2 = bp2_res.Value["locations"]?.Value()[0]; Assert.NotNull(loc2["scriptId"]); - Assert.Equal(13, loc2["lineNumber"]); - Assert.Equal(33, loc2["columnNumber"]); + Assert.Equal(13, (int)loc2["lineNumber"]); + Assert.Equal(33, (int)loc2["columnNumber"]); } [Theory] diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html b/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html index 07b06b95fe9..a1cce5ee2b8 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-driver.html @@ -88,7 +88,7 @@ window.location.replace("http://localhost:9400/non-wasm-page.html"); } - + Stuff goes here diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js b/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js new file mode 100644 index 00000000000..c34cdf6bae4 --- /dev/null +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-main.js @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +"use strict"; + +var Module = { + configSrc: "./mono-config.json", + onConfigLoaded: () => { + MONO.config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; + // For custom logging patch the functions below + /* + MONO.config.environment_variables["MONO_LOG_LEVEL"] = "debug"; + MONO.config.environment_variables["MONO_LOG_MASK"] = "all"; + INTERNAL.logging = { + trace: function (domain, log_level, message, isFatal, dataPtr) { }, + debugger: function (level, message) { } + }; + */ + }, + onDotNetReady: () => { + App.init(); + }, +}; diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj index 46bbe3c6d41..c3cc1800aad 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj @@ -12,7 +12,7 @@ - + @@ -28,7 +28,7 @@ false $(AppDir) - $(MonoProjectRoot)wasm\runtime-test.js + $(MonoProjectRoot)wasm\test-main.js -1 diff --git a/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js b/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js deleted file mode 100644 index 7eea4d3c515..00000000000 --- a/src/mono/wasm/debugger/tests/debugger-test/runtime-debugger.js +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -"use strict"; - -var Module = { - config: null, - configSrc: "./mono-config.json", - onConfigLoaded: function () { - MONO.config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; - // For custom logging patch the functions below - /* - MONO.config.environment_variables["MONO_LOG_LEVEL"] = "debug"; - MONO.config.environment_variables["MONO_LOG_MASK"] = "all"; - INTERNAL.logging = { - trace: function (domain, log_level, message, isFatal, dataPtr) { }, - debugger: function (level, message) { } - }; - */ - }, - onDotNetReady: function () { - App.init(); - }, -}; diff --git a/src/mono/wasm/runtime/CMakeLists.txt b/src/mono/wasm/runtime/CMakeLists.txt index 450d8df3918..4a67bcfe1a8 100644 --- a/src/mono/wasm/runtime/CMakeLists.txt +++ b/src/mono/wasm/runtime/CMakeLists.txt @@ -25,7 +25,7 @@ target_link_libraries(dotnet set_target_properties(dotnet PROPERTIES LINK_DEPENDS "${NATIVE_BIN_DIR}/src/emcc-default.rsp;${NATIVE_BIN_DIR}/src/runtime.iffe.js;${SOURCE_DIR}/library-dotnet.js;${SYSTEM_NATIVE_DIR}/pal_random.js" - LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp ${CONFIGURATION_LINK_FLAGS} -DENABLE_NETCORE=1 --pre-js ${NATIVE_BIN_DIR}/src/runtime.iffe.js --js-library ${SOURCE_DIR}/library-dotnet.js --js-library ${SYSTEM_NATIVE_DIR}/pal_random.js" + LINK_FLAGS "@${NATIVE_BIN_DIR}/src/emcc-default.rsp ${CONFIGURATION_LINK_FLAGS} -DENABLE_NETCORE=1 --extern-pre-js ${NATIVE_BIN_DIR}/src/runtime.iffe.js --js-library ${SOURCE_DIR}/library-dotnet.js --js-library ${SYSTEM_NATIVE_DIR}/pal_random.js" RUNTIME_OUTPUT_DIRECTORY "${NATIVE_BIN_DIR}") if(CMAKE_BUILD_TYPE STREQUAL "Release") diff --git a/src/mono/wasm/runtime/buffers.ts b/src/mono/wasm/runtime/buffers.ts index 874de814f22..727ac3e8b59 100644 --- a/src/mono/wasm/runtime/buffers.ts +++ b/src/mono/wasm/runtime/buffers.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import { Int32Ptr, JSHandle, MonoArray, MonoObject, MonoString, VoidPtr } from "./types"; -import { Module } from "./modules"; +import { Module } from "./imports"; import { mono_wasm_get_jsobj_from_js_handle } from "./gc-handles"; import { wrap_error } from "./method-calls"; import { _js_to_mono_obj } from "./js-to-cs"; diff --git a/src/mono/wasm/runtime/corebindings.ts b/src/mono/wasm/runtime/corebindings.ts index 471914a932c..9e12e3f74d8 100644 --- a/src/mono/wasm/runtime/corebindings.ts +++ b/src/mono/wasm/runtime/corebindings.ts @@ -4,7 +4,7 @@ import { JSHandle, GCHandle, MonoObject } from "./types"; import { ArgsMarshalString } from "./method-binding"; import { PromiseControl } from "./cancelable-promise"; -import { runtimeHelpers } from "./modules"; +import { runtimeHelpers } from "./imports"; const fn_signatures: [jsname: string, csname: string, signature: ArgsMarshalString][] = [ ["_get_cs_owned_object_by_js_handle", "GetCSOwnedObjectByJSHandle", "ii!"], diff --git a/src/mono/wasm/runtime/cs-to-js.ts b/src/mono/wasm/runtime/cs-to-js.ts index 1bf4e63e336..a0883815aa8 100644 --- a/src/mono/wasm/runtime/cs-to-js.ts +++ b/src/mono/wasm/runtime/cs-to-js.ts @@ -7,7 +7,7 @@ import { MonoArrayNull, MonoObject, MonoObjectNull, MonoString, MonoType, MonoTypeNull } from "./types"; -import { runtimeHelpers } from "./modules"; +import { runtimeHelpers } from "./imports"; import { conv_string } from "./strings"; import corebindings from "./corebindings"; import cwraps from "./cwraps"; diff --git a/src/mono/wasm/runtime/cwraps.ts b/src/mono/wasm/runtime/cwraps.ts index 5270c13050d..e991bab9a72 100644 --- a/src/mono/wasm/runtime/cwraps.ts +++ b/src/mono/wasm/runtime/cwraps.ts @@ -7,7 +7,7 @@ import { MonoMethod, MonoObject, MonoString, MonoType, VoidPtr } from "./types"; -import { Module } from "./modules"; +import { Module } from "./imports"; const fn_signatures: [ident: string, returnType: string | null, argTypes?: string[], opts?: any][] = [ // MONO diff --git a/src/mono/wasm/runtime/debug.ts b/src/mono/wasm/runtime/debug.ts index a7932ebf728..cc3ee210dcc 100644 --- a/src/mono/wasm/runtime/debug.ts +++ b/src/mono/wasm/runtime/debug.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 { Module, MONO, runtimeHelpers } from "./modules"; +import { Module, MONO, runtimeHelpers } from "./imports"; import { toBase64StringImpl } from "./base64"; import cwraps from "./cwraps"; import { VoidPtr } from "./types"; diff --git a/src/mono/wasm/runtime/export-types.ts b/src/mono/wasm/runtime/export-types.ts new file mode 100644 index 00000000000..f376fb59c90 --- /dev/null +++ b/src/mono/wasm/runtime/export-types.ts @@ -0,0 +1,7 @@ +import { DotNetPublicAPI } from "./exports"; +import { EmscriptenModuleConfig } from "./types"; + +// this is the only public export from the dotnet.js module +declare function createDotnetRuntime(moduleFactory: (api: DotNetPublicAPI) => EmscriptenModuleConfig): Promise; +export default createDotnetRuntime; + diff --git a/src/mono/wasm/runtime/exports.ts b/src/mono/wasm/runtime/exports.ts index 3dd3c123623..ca6994dba70 100644 --- a/src/mono/wasm/runtime/exports.ts +++ b/src/mono/wasm/runtime/exports.ts @@ -20,7 +20,7 @@ import { mono_wasm_raise_debug_event, mono_wasm_fire_debugger_agent_message, } from "./debug"; -import { runtimeHelpers, setLegacyModules } from "./modules"; +import { runtimeHelpers, setImportsAndExports } from "./imports"; import { EmscriptenModuleMono, MonoArray, MonoConfig, MonoConfigError, MonoObject } from "./types"; import { mono_load_runtime_and_bcl_args, mono_wasm_load_config, @@ -63,7 +63,7 @@ import { getU8, getU16, getU32, getF32, getF64, } from "./memory"; -export const MONO: MONO = { +const MONO: MONO = { // current "public" MONO API mono_wasm_setenv, mono_wasm_load_bytes_into_heap, @@ -88,7 +88,7 @@ export const MONO: MONO = { mono_wasm_new_roots, }; -export const BINDING: BINDING = { +const BINDING: BINDING = { //current "public" BINDING API mono_obj_array_new: cwraps.mono_wasm_obj_array_new, mono_obj_array_set: cwraps.mono_wasm_obj_array_set, @@ -115,64 +115,96 @@ export const BINDING: BINDING = { // this is executed early during load of emscripten runtime // it exports methods to global objects MONO, BINDING and Module in backward compatible way // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -function export_to_emscripten(dotnet: any, mono: any, binding: any, internal: any, module: any): void { - const moduleExt = module as EmscriptenModuleMono; +function initializeImportsAndExports( + imports: { isGlobal: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, locateFile: Function }, + exports: { mono: any, binding: any, internal: any, module: any }, +): void { + const module = exports.module as EmscriptenModuleMono; + const globalThisAny = globalThis as any; // we want to have same instance of MONO, BINDING and Module in dotnet iffe - setLegacyModules(dotnet, mono, binding, internal, module); + setImportsAndExports(imports, exports); - // here we merge methods to it from the local objects - Object.assign(dotnet, DOTNET); - Object.assign(mono, MONO); - Object.assign(binding, BINDING); - Object.assign(internal, INTERNAL); + // here we merge methods from the local objects into exported objects + Object.assign(exports.mono, MONO); + Object.assign(exports.binding, BINDING); + Object.assign(exports.internal, INTERNAL); + const api: DotNetPublicAPI = { + MONO: exports.mono, + BINDING: exports.binding, + INTERNAL: exports.internal, + Module: module + }; + + if (module.configSrc) { + // this could be overriden on Module + if (!module.preInit) { + module.preInit = []; + } else if (typeof module.preInit === "function") { + module.preInit = [module.preInit]; + } + module.preInit.unshift(mono_wasm_pre_init); + } // this could be overriden on Module - moduleExt.preInit = mono_wasm_pre_init; - moduleExt.onRuntimeInitialized = mono_wasm_on_runtime_initialized; + if (!module.onRuntimeInitialized) { + module.onRuntimeInitialized = mono_wasm_on_runtime_initialized; + } + if (!module.print) { + module.print = console.log; + } + if (!module.printErr) { + module.printErr = console.error; + } + + if (imports.isGlobal || !module.disableDotNet6Compatibility) { + Object.assign(module, api); - if (!moduleExt.disableDotNet6Compatibility) { // backward compatibility // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - moduleExt.mono_bind_static_method = (fqn: string, signature: ArgsMarshalString): Function => { + module.mono_bind_static_method = (fqn: string, signature: ArgsMarshalString): Function => { console.warn("Module.mono_bind_static_method is obsolete, please use BINDING.bind_static_method instead"); return mono_bind_static_method(fqn, signature); }; // here we expose objects used in tests to global namespace - (globalThis).Module = module; - const warnWrap = (name: string, value: any) => { - if (typeof ((globalThis)[name]) !== "undefined") { + const warnWrap = (name: string, provider: () => any) => { + if (typeof globalThisAny[name] !== "undefined") { // it already exists in the global namespace return; } - let warnOnce = true; + let value: any = undefined; Object.defineProperty(globalThis, name, { get: () => { - if (warnOnce) { + if (!value) { const stack = (new Error()).stack; const nextLine = stack ? stack.substr(stack.indexOf("\n", 8) + 1) : ""; console.warn(`global ${name} is obsolete, please use Module.${name} instead ${nextLine}`); - warnOnce = false; + value = provider(); } return value; } }); }; - warnWrap("MONO", mono); - warnWrap("BINDING", binding); + globalThisAny.MONO = exports.mono; + globalThisAny.BINDING = exports.binding; + globalThisAny.INTERNAL = exports.internal; + if (!imports.isGlobal) { + globalThisAny.Module = module; + } // Blazor back compat - warnWrap("cwrap", Module.cwrap); - warnWrap("addRunDependency", Module.addRunDependency); - warnWrap("removeRunDependency", Module.removeRunDependency); + warnWrap("cwrap", () => module.cwrap); + warnWrap("addRunDependency", () => module.addRunDependency); + warnWrap("removeRunDependency", () => module.removeRunDependency); } } +export const __initializeImportsAndExports: any = initializeImportsAndExports; // don't want to export the type // the methods would be visible to EMCC linker -// --- keep in sync with library-dotnet.js --- -const linker_exports = { +// --- keep in sync with dotnet.lib.js --- +export const __linker_exports: any = { // mini-wasm.c mono_set_timeout, @@ -214,16 +246,10 @@ const linker_exports = { mono_wasm_load_icu_data, mono_wasm_get_icudt_name, }; -export const DOTNET: any = { -}; -export const INTERNAL: any = { +const INTERNAL: any = { // startup BINDING_ASM: "[System.Private.Runtime.InteropServices.JavaScript]System.Runtime.InteropServices.JavaScript.Runtime", - export_to_emscripten, - - // linker - linker_exports: linker_exports, // tests call_static_method, @@ -281,7 +307,7 @@ export const INTERNAL: any = { // this represents visibility in the javascript // like https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web.JS/src/Platform/Mono/MonoTypes.ts -export interface MONO { +interface MONO { mono_wasm_runtime_ready: typeof mono_wasm_runtime_ready mono_wasm_setenv: typeof mono_wasm_setenv mono_wasm_load_data_archive: typeof mono_wasm_load_data_archive; @@ -294,8 +320,8 @@ export interface MONO { mono_wasm_release_roots: typeof mono_wasm_release_roots; // for Blazor's future! - mono_wasm_add_assembly: typeof cwraps.mono_wasm_add_assembly, - mono_wasm_load_runtime: typeof cwraps.mono_wasm_load_runtime, + mono_wasm_add_assembly: (name: string, data: VoidPtr, size: number) => number, + mono_wasm_load_runtime: (unused: string, debug_level: number) => void, loaded_files: string[]; config: MonoConfig | MonoConfigError, @@ -303,7 +329,7 @@ export interface MONO { // this represents visibility in the javascript // like https://github.com/dotnet/aspnetcore/blob/main/src/Components/Web.JS/src/Platform/Mono/MonoTypes.ts -export interface BINDING { +interface BINDING { mono_obj_array_new: (size: number) => MonoArray, mono_obj_array_set: (array: MonoArray, idx: number, obj: MonoObject) => void, js_string_to_mono_string: typeof js_string_to_mono_string, @@ -314,4 +340,9 @@ export interface BINDING { bind_static_method: typeof mono_bind_static_method, call_assembly_entry_point: typeof mono_call_assembly_entry_point, unbox_mono_obj: typeof unbox_mono_obj +} +export interface DotNetPublicAPI { + MONO: MONO, + BINDING: BINDING, + Module: any } \ No newline at end of file diff --git a/src/mono/wasm/runtime/modules.ts b/src/mono/wasm/runtime/imports.ts similarity index 58% rename from src/mono/wasm/runtime/modules.ts rename to src/mono/wasm/runtime/imports.ts index 3dfa3331271..be89b335731 100644 --- a/src/mono/wasm/runtime/modules.ts +++ b/src/mono/wasm/runtime/imports.ts @@ -7,19 +7,33 @@ import { EmscriptenModuleMono, MonoConfig, RuntimeHelpers } from "./types"; +// these are our public API (except internal) export let Module: EmscriptenModule & EmscriptenModuleMono; export let MONO: any; export let BINDING: any; -export let DOTNET: any; export let INTERNAL: any; +// these are imported and re-exported from emscripten internals +export let ENVIRONMENT_IS_GLOBAL: boolean; +export let ENVIRONMENT_IS_NODE: boolean; +export let ENVIRONMENT_IS_SHELL: boolean; +export let ENVIRONMENT_IS_WEB: boolean; +export let locateFile: Function; + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -export function setLegacyModules(dotnet: any, mono: any, binding: any, internal: any, module: EmscriptenModule & EmscriptenModuleMono) { - DOTNET = dotnet; - MONO = mono; - BINDING = binding; - INTERNAL = internal; - Module = module; +export function setImportsAndExports( + imports: { isGlobal: boolean, isNode: boolean, isShell: boolean, isWeb: boolean, locateFile: Function }, + exports: { mono: any, binding: any, internal: any, module: any }, +) { + MONO = exports.mono; + BINDING = exports.binding; + INTERNAL = exports.internal; + Module = exports.module; + ENVIRONMENT_IS_GLOBAL = imports.isGlobal; + ENVIRONMENT_IS_NODE = imports.isNode; + ENVIRONMENT_IS_SHELL = imports.isShell; + ENVIRONMENT_IS_WEB = imports.isWeb; + locateFile = imports.locateFile; } let monoConfig: MonoConfig; diff --git a/src/mono/wasm/runtime/js-to-cs.ts b/src/mono/wasm/runtime/js-to-cs.ts index 6914e6cfbc3..01be716a7b7 100644 --- a/src/mono/wasm/runtime/js-to-cs.ts +++ b/src/mono/wasm/runtime/js-to-cs.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 { Module, runtimeHelpers } from "./modules"; +import { Module, runtimeHelpers } from "./imports"; import { cs_owned_js_handle_symbol, get_cs_owned_object_by_js_handle, get_js_owned_object_by_gc_handle, js_owned_gc_handle_symbol, mono_wasm_get_jsobj_from_js_handle, mono_wasm_get_js_handle, diff --git a/src/mono/wasm/runtime/library-dotnet.js b/src/mono/wasm/runtime/library-dotnet.js index a999659b194..49f3bf58787 100644 --- a/src/mono/wasm/runtime/library-dotnet.js +++ b/src/mono/wasm/runtime/library-dotnet.js @@ -1,6 +1,6 @@ -/* eslint-disable no-undef */ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +/* eslint-disable no-undef */ "use strict"; @@ -9,8 +9,8 @@ const DotNetSupportLib = { $MONO: {}, $BINDING: {}, $INTERNAL: {}, - // this line will be executed on runtime, populating the objects with methods - $DOTNET__postset: "__dotnet_runtime.INTERNAL.export_to_emscripten (DOTNET, MONO, BINDING, INTERNAL, Module);", + // this line will be executed early on runtime, passing import and export objects into __dotnet_runtime IFFE + $DOTNET__postset: "__dotnet_runtime.__initializeImportsAndExports({isGlobal:true, isNode:ENVIRONMENT_IS_NODE, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, locateFile}, {mono:MONO, binding:BINDING, internal:INTERNAL, module:Module});", }; // the methods would be visible to EMCC linker @@ -61,7 +61,7 @@ const linked_functions = [ // -- this javascript file is evaluated by emcc during compilation! -- // we generate simple proxy for each exported function so that emcc will include them in the final output for (let linked_function of linked_functions) { - const fn_template = `return __dotnet_runtime.INTERNAL.linker_exports.${linked_function}.apply(__dotnet_runtime, arguments)`; + const fn_template = `return __dotnet_runtime.__linker_exports.${linked_function}.apply(__dotnet_runtime, arguments)`; DotNetSupportLib[linked_function] = new Function(fn_template); } diff --git a/src/mono/wasm/runtime/memory.ts b/src/mono/wasm/runtime/memory.ts index becf3fe3ff4..55a322637b9 100644 --- a/src/mono/wasm/runtime/memory.ts +++ b/src/mono/wasm/runtime/memory.ts @@ -1,4 +1,4 @@ -import { Module } from "./modules"; +import { Module } from "./imports"; const _temp_mallocs: Array | null> = []; @@ -31,77 +31,77 @@ export function _release_temp_frame(): void { type _MemOffset = number | VoidPtr | NativePointer; -export function setU8 (offset: _MemOffset, value: number) : void { +export function setU8(offset: _MemOffset, value: number): void { Module.HEAPU8[offset] = value; } -export function setU16 (offset: _MemOffset, value: number) : void { +export function setU16(offset: _MemOffset, value: number): void { Module.HEAPU16[offset >>> 1] = value; } -export function setU32 (offset: _MemOffset, value: number) : void { +export function setU32(offset: _MemOffset, value: number): void { Module.HEAPU32[offset >>> 2] = value; } -export function setI8 (offset: _MemOffset, value: number) : void { +export function setI8(offset: _MemOffset, value: number): void { Module.HEAP8[offset] = value; } -export function setI16 (offset: _MemOffset, value: number) : void { +export function setI16(offset: _MemOffset, value: number): void { Module.HEAP16[offset >>> 1] = value; } -export function setI32 (offset: _MemOffset, value: number) : void { +export function setI32(offset: _MemOffset, value: number): void { Module.HEAP32[offset >>> 2] = value; } // NOTE: Accepts a number, not a BigInt, so values over Number.MAX_SAFE_INTEGER will be corrupted -export function setI64 (offset: _MemOffset, value: number) : void { +export function setI64(offset: _MemOffset, value: number): void { Module.setValue(offset, value, "i64"); } -export function setF32 (offset: _MemOffset, value: number) : void { +export function setF32(offset: _MemOffset, value: number): void { Module.HEAPF32[offset >>> 2] = value; } -export function setF64 (offset: _MemOffset, value: number) : void { +export function setF64(offset: _MemOffset, value: number): void { Module.HEAPF64[offset >>> 3] = value; } -export function getU8 (offset: _MemOffset) : number { +export function getU8(offset: _MemOffset): number { return Module.HEAPU8[offset]; } -export function getU16 (offset: _MemOffset) : number { +export function getU16(offset: _MemOffset): number { return Module.HEAPU16[offset >>> 1]; } -export function getU32 (offset: _MemOffset) : number { +export function getU32(offset: _MemOffset): number { return Module.HEAPU32[offset >>> 2]; } -export function getI8 (offset: _MemOffset) : number { +export function getI8(offset: _MemOffset): number { return Module.HEAP8[offset]; } -export function getI16 (offset: _MemOffset) : number { +export function getI16(offset: _MemOffset): number { return Module.HEAP16[offset >>> 1]; } -export function getI32 (offset: _MemOffset) : number { +export function getI32(offset: _MemOffset): number { return Module.HEAP32[offset >>> 2]; } // NOTE: Returns a number, not a BigInt. This means values over Number.MAX_SAFE_INTEGER will be corrupted -export function getI64 (offset: _MemOffset) : number { +export function getI64(offset: _MemOffset): number { return Module.getValue(offset, "i64"); } -export function getF32 (offset: _MemOffset) : number { +export function getF32(offset: _MemOffset): number { return Module.HEAPF32[offset >>> 2]; } -export function getF64 (offset: _MemOffset) : number { +export function getF64(offset: _MemOffset): number { return Module.HEAPF64[offset >>> 3]; } diff --git a/src/mono/wasm/runtime/method-binding.ts b/src/mono/wasm/runtime/method-binding.ts index a9b2ebb00d3..1cd070ae944 100644 --- a/src/mono/wasm/runtime/method-binding.ts +++ b/src/mono/wasm/runtime/method-binding.ts @@ -3,13 +3,13 @@ import { WasmRoot, WasmRootBuffer, mono_wasm_new_root } from "./roots"; import { MonoClass, MonoMethod, MonoObject, coerceNull, VoidPtrNull, VoidPtr, MonoType } from "./types"; -import { BINDING, runtimeHelpers } from "./modules"; +import { BINDING, Module, runtimeHelpers } from "./imports"; import { js_to_mono_enum, _js_to_mono_obj, _js_to_mono_uri } from "./js-to-cs"; import { js_string_to_mono_string, js_string_to_mono_string_interned } from "./strings"; import { MarshalType, _unbox_mono_obj_root_with_known_nonprimitive_type } from "./cs-to-js"; -import { - _create_temp_frame, - getI32, getU32, getF32, getF64, +import { + _create_temp_frame, + getI32, getU32, getF32, getF64, setI32, setU32, setF32, setF64, setI64, } from "./memory"; import { diff --git a/src/mono/wasm/runtime/method-calls.ts b/src/mono/wasm/runtime/method-calls.ts index 3567fc822d0..8d7174e8b48 100644 --- a/src/mono/wasm/runtime/method-calls.ts +++ b/src/mono/wasm/runtime/method-calls.ts @@ -7,7 +7,7 @@ import { MonoObjectNull, MonoString, coerceNull as coerceNull, VoidPtr, VoidPtrNull, Int32Ptr, MonoStringNull } from "./types"; -import { BINDING, INTERNAL, Module, MONO, runtimeHelpers } from "./modules"; +import { BINDING, INTERNAL, Module, MONO, runtimeHelpers } from "./imports"; import { _mono_array_root_to_js_array, _unbox_mono_obj_root } from "./cs-to-js"; import { get_js_obj, mono_wasm_get_jsobj_from_js_handle } from "./gc-handles"; import { js_array_to_mono_array, _box_js_bool, _js_to_mono_obj } from "./js-to-cs"; diff --git a/src/mono/wasm/runtime/package.json b/src/mono/wasm/runtime/package.json index dae87adeaef..2958e9d2f22 100644 --- a/src/mono/wasm/runtime/package.json +++ b/src/mono/wasm/runtime/package.json @@ -8,7 +8,7 @@ "version": "1.0.0", "scripts": { "rollup": "rollup -c", - "lint": "eslint --no-color --max-warnings=0 ./**/*.ts ./**/*.js" + "lint": "eslint --no-color --max-warnings=0 ./**/*.ts ./*.js" }, "keywords": [ "dotnet", diff --git a/src/mono/wasm/runtime/profiler.ts b/src/mono/wasm/runtime/profiler.ts index b4abc9aacdb..07e88acf4f4 100644 --- a/src/mono/wasm/runtime/profiler.ts +++ b/src/mono/wasm/runtime/profiler.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 { Module } from "./modules"; +import { Module } from "./imports"; import { AOTProfilerOptions, CoverageProfilerOptions } from "./types"; // Initialize the AOT profiler with OPTIONS. diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index d3bca849bef..33bbb20e448 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -11,13 +11,15 @@ const isDebug = process.env.Configuration !== "Release"; const nativeBinDir = process.env.NativeBinDir ? process.env.NativeBinDir.replace(/"/g, "") : "bin"; const terserConfig = { compress: { - defaults: false,// to agressive minification breaks subsequent emcc compilation + defaults: false,// too agressive minification breaks subsequent emcc compilation drop_debugger: false,// we invoke debugger drop_console: false,// we log to console unused: false,// this breaks stuff // below are minification features which seems to work fine collapse_vars: true, conditionals: true, + computed_props: true, + properties: true, dead_code: true, if_return: true, inline: true, @@ -32,39 +34,40 @@ const terserConfig = { // because of stack walk at src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs keep_fnames: /(mono_wasm_runtime_ready|mono_wasm_fire_debugger_agent_message)/, }, - // we export ES5 because emcc parser has trouble parsing it otherwise - ecma: 5, }; 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"; +// 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"; export default defineConfig([ { treeshake: !isDebug, input: "exports.ts", output: [{ - 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", - name: "__dotnet_runtime", file: nativeBinDir + "/src/" + outputFileName, - - // emcc doesn't know how to load ES6 module, that's why we need the whole rollup.js - format: "iife", - plugins: plugins + name, + banner, + format, + plugins, }], plugins: [typescript()] }, { - input: "./exports.ts", + input: "./export-types.ts", output: [ + // dotnet.d.ts { format: "es", file: nativeBinDir + "/src/" + "dotnet.d.ts", } ], plugins: [dts()], - }, + } ]); -// this would create .md5 file next to the output file, so that we do not touch datetime of the file if it's same -> faster incremental build. +// this would create .sha256 file next to the output file, so that we do not touch datetime of the file if it's same -> faster incremental build. function writeOnChangePlugin() { return { name: "writeOnChange", diff --git a/src/mono/wasm/runtime/roots.ts b/src/mono/wasm/runtime/roots.ts index baf847dff3b..1eb88b3d7dc 100644 --- a/src/mono/wasm/runtime/roots.ts +++ b/src/mono/wasm/runtime/roots.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import cwraps from "./cwraps"; -import { Module } from "./modules"; +import { Module } from "./imports"; import { VoidPtr, ManagedPointer, NativePointer } from "./types"; const maxScratchRoots = 8192; diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index dcab05fefeb..1f1059135ef 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.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 { INTERNAL, Module, MONO, runtimeHelpers } from "./modules"; import { AllAssetEntryTypes, AssetEntry, CharPtr, CharPtrNull, EmscriptenModuleMono, GlobalizationMode, MonoConfig, VoidPtr, wasm_type_symbol } from "./types"; +import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, INTERNAL, locateFile, Module, MONO, runtimeHelpers } from "./imports"; import cwraps from "./cwraps"; import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug"; import { mono_wasm_globalization_init, mono_wasm_load_icu_data } from "./icu"; @@ -12,11 +12,25 @@ import { mono_wasm_load_bytes_into_heap } from "./buffers"; import { bind_runtime_method, get_method, _create_primitive_converters } from "./method-binding"; import { find_corlib_class } from "./class-loader"; +export let runtime_is_initialized_resolve: Function; +export let runtime_is_initialized_reject: Function; +export const mono_wasm_runtime_is_initialized = new Promise((resolve, reject) => { + runtime_is_initialized_resolve = resolve; + runtime_is_initialized_reject = reject; +}); + + export async function mono_wasm_pre_init(): Promise { const moduleExt = Module as EmscriptenModuleMono; if (moduleExt.configSrc) { - // sets MONO.config implicitly - await mono_wasm_load_config(moduleExt.configSrc); + try { + // sets MONO.config implicitly + await mono_wasm_load_config(moduleExt.configSrc); + } + catch (err: any) { + runtime_is_initialized_reject(err); + throw err; + } if (moduleExt.onConfigLoaded) { try { @@ -26,6 +40,7 @@ export async function mono_wasm_pre_init(): Promise { Module.printErr("MONO_WASM: onConfigLoaded () failed: " + err); Module.printErr("MONO_WASM: Stacktrace: \n"); Module.printErr(err.stack); + runtime_is_initialized_reject(err); throw err; } } @@ -62,10 +77,11 @@ async function _fetch_asset(url: string): Promise { return fetch(url, { credentials: "same-origin" }); } else if (ENVIRONMENT_IS_NODE) { + //const fs = (globalThis).require("fs"); // eslint-disable-next-line @typescript-eslint/no-var-requires const fs = require("fs"); const arrayBuffer = await fs.promises.readFile(url); - return { + return { ok: true, url, arrayBuffer: () => arrayBuffer, @@ -74,7 +90,7 @@ async function _fetch_asset(url: string): Promise { } else if (typeof (read) === "function") { const arrayBuffer = new Uint8Array(read(url, "binary")); - return { + return { ok: true, url, arrayBuffer: () => arrayBuffer, @@ -83,7 +99,7 @@ async function _fetch_asset(url: string): Promise { } } catch (e: any) { - return { + return { ok: false, url, arrayBuffer: () => { throw e; }, @@ -196,11 +212,12 @@ function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { if (ENVIRONMENT_IS_SHELL || ENVIRONMENT_IS_NODE) { try { cwraps.mono_wasm_load_runtime("unused", args.debug_level || 0); - } catch (ex: any) { - Module.printErr("MONO_WASM: mono_wasm_load_runtime () failed: " + ex); + } catch (err: any) { + Module.printErr("MONO_WASM: mono_wasm_load_runtime () failed: " + err); Module.printErr("MONO_WASM: Stacktrace: \n"); - Module.printErr(ex.stack); + Module.printErr(err.stack); + runtime_is_initialized_reject(err); const wasm_exit = cwraps.mono_wasm_exit; wasm_exit(1); } @@ -219,6 +236,21 @@ function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { mono_wasm_setenv("TZ", tz || "UTC"); mono_wasm_runtime_ready(); + //legacy config loading + const argsAny: any = args; + if (argsAny.loaded_cb) { + try { + argsAny.loaded_cb(); + } + catch (err: any) { + Module.printErr("MONO_WASM: loaded_cb () failed: " + err); + Module.printErr("MONO_WASM: Stacktrace: \n"); + Module.printErr(err.stack); + runtime_is_initialized_reject(err); + throw err; + } + } + if (moduleExt.onDotNetReady) { try { moduleExt.onDotNetReady(); @@ -227,9 +259,12 @@ function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { Module.printErr("MONO_WASM: onDotNetReady () failed: " + err); Module.printErr("MONO_WASM: Stacktrace: \n"); Module.printErr(err.stack); + runtime_is_initialized_reject(err); throw err; } } + + runtime_is_initialized_resolve(); } export function bindings_lazy_init(): void { @@ -381,9 +416,10 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< await Promise.all(fetch_promises); _finalize_startup(args, ctx); - } catch (exc: any) { - console.error("MONO_WASM: Error in mono_load_runtime_and_bcl_args:", exc); - throw exc; + } catch (err: any) { + console.error("MONO_WASM: Error in mono_load_runtime_and_bcl_args:", err); + runtime_is_initialized_reject(err); + throw err; } } @@ -462,11 +498,12 @@ export async function mono_wasm_load_config(configFilePath: string): Promisebuffer >>> 1) | 0; for (let i = 0; i < string.length; i++) diff --git a/src/mono/wasm/runtime/tsconfig.json b/src/mono/wasm/runtime/tsconfig.json index a1f0c306021..63d7619e09f 100644 --- a/src/mono/wasm/runtime/tsconfig.json +++ b/src/mono/wasm/runtime/tsconfig.json @@ -4,7 +4,7 @@ "noEmitOnError": true, "removeComments": false, "sourceMap": false, - "target": "ES5", + "target": "ES2018", "moduleResolution": "Node", "lib": [ "esnext", diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index c2db47aae5c..d452649c96b 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -179,7 +179,9 @@ export type CoverageProfilerOptions = { } // how we extended emscripten Module -export type EmscriptenModuleMono = EmscriptenModule & { +export type EmscriptenModuleMono = EmscriptenModule & EmscriptenModuleConfig; + +export type EmscriptenModuleConfig = { disableDotNet6Compatibility?: boolean, // backward compatibility diff --git a/src/mono/wasm/runtime/types/emscripten.d.ts b/src/mono/wasm/runtime/types/emscripten.d.ts index 315b7dc53bf..51dbcbe364c 100644 --- a/src/mono/wasm/runtime/types/emscripten.d.ts +++ b/src/mono/wasm/runtime/types/emscripten.d.ts @@ -22,20 +22,6 @@ declare interface CharPtrPtr extends NativePointer { __brand: "CharPtrPtr" } -declare let ENVIRONMENT_IS_WEB: boolean; -declare let ENVIRONMENT_IS_SHELL: boolean; -declare let ENVIRONMENT_IS_NODE: boolean; -declare let ENVIRONMENT_IS_WORKER: boolean; -declare let LibraryManager: any; - -declare function autoAddDeps(a: object, b: string): void; -declare function mergeInto(a: object, b: object): void; - -// TODO, what's wrong with EXPORTED_RUNTIME_METHODS ? -declare function locateFile(path: string, prefix?: string): string; - -declare let Module: EmscriptenModule; - declare interface EmscriptenModule { HEAP8: Int8Array, HEAP16: Int16Array; @@ -66,7 +52,7 @@ declare interface EmscriptenModule { removeRunDependency(id: string): void; addRunDependency(id: string): void; - preInit?: () => Promise; + preInit?: (() => Promise)[]; onRuntimeInitialized?: () => void; } diff --git a/src/mono/wasm/runtime/web-socket.ts b/src/mono/wasm/runtime/web-socket.ts index 00dac60a7f4..319af2f4650 100644 --- a/src/mono/wasm/runtime/web-socket.ts +++ b/src/mono/wasm/runtime/web-socket.ts @@ -11,6 +11,7 @@ import { _wrap_js_thenable_as_task } from "./js-to-cs"; import { wrap_error } from "./method-calls"; import { conv_string } from "./strings"; import { Int32Ptr, JSHandle, MonoArray, MonoObject, MonoObjectNull, MonoString } from "./types"; +import { Module } from "./imports"; 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-test.js b/src/mono/wasm/test-main.js similarity index 73% rename from src/mono/wasm/runtime-test.js rename to src/mono/wasm/test-main.js index 60ff70d065f..cf7b7e39f34 100644 --- a/src/mono/wasm/runtime-test.js +++ b/src/mono/wasm/test-main.js @@ -8,7 +8,7 @@ //glue code to deal with the differences between chrome, ch, d8, jsc and sm. const is_browser = typeof window != "undefined"; -const is_node = !is_browser && typeof process != 'undefined'; +const is_node = !is_browser && typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string'; // if the engine doesn't provide a console if (typeof (console) === "undefined") { @@ -22,6 +22,8 @@ const originalConsole = { error: console.error }; +let isXUnitDoneCheck = false; + function proxyMethod(prefix, func, asJson) { return function () { const args = [...arguments]; @@ -36,6 +38,9 @@ function proxyMethod(prefix, func, asJson) { payload = payload.toString(); } } + if (payload.indexOf("=== TEST EXECUTION SUMMARY ===") != -1) { + isXUnitDoneCheck = true; + } if (asJson) { func(JSON.stringify({ @@ -65,14 +70,21 @@ if (is_browser) { const consoleUrl = `${window.location.origin}/console`.replace('http://', 'ws://'); let consoleWebSocket = new WebSocket(consoleUrl); - consoleWebSocket.onopen = function (event) { - proxyJson(function (msg) { + // redirect output so that when emscripten starts it's already redirected + proxyJson(function (msg) { + if (consoleWebSocket.readyState === WebSocket.OPEN) { consoleWebSocket.send(msg); - }); - console.log("browser: Console websocket connected."); + } + else { + originalConsole.log(msg); + } + }); + + consoleWebSocket.onopen = function (event) { + originalConsole.log("browser: Console websocket connected."); }; consoleWebSocket.onerror = function (event) { - console.error(`websocket error: ${event}`); + originalConsole.error(`websocket error: ${event}`); }; } @@ -101,18 +113,14 @@ if (typeof globalThis.performance === 'undefined') { } } } - var Module = { - no_global_exports: true, - mainScriptUrlOrBlob: "dotnet.js", config: null, configSrc: "./mono-config.json", - print: console.log, - printErr: console.error, - onConfigLoaded: function () { + onConfigLoaded: () => { if (!Module.config) { - console.error("Could not find ./mono-config.json. Cancelling run"); - fail_exec(1); + const err = new Error("Could not find ./mono-config.json. Cancelling run"); + set_exit_code(1,); + throw err; } // Have to set env vars here to enable setting MONO_LOG_LEVEL etc. for (let variable in processedArguments.setenv) { @@ -123,10 +131,10 @@ var Module = { INTERNAL.mono_wasm_enable_on_demand_gc(0); } }, - onDotNetReady: function () { + onDotNetReady: () => { let wds = Module.FS.stat(processedArguments.working_dir); if (wds === undefined || !Module.FS.isDir(wds.mode)) { - fail_exec(1, `Could not find working directory ${processedArguments.working_dir}`); + set_exit_code(1, `Could not find working directory ${processedArguments.working_dir}`); return; } @@ -134,26 +142,26 @@ var Module = { App.init(); }, - onAbort: function (x) { - console.log("ABORT: " + x); + onAbort: (error) => { + console.log("ABORT: " + error); const err = new Error(); console.log("Stacktrace: \n"); console.error(err.stack); - fail_exec(1); + set_exit_code(1, error); }, }; + const App = { - init: function () { + init: async function () { console.info("Initializing....."); - for (let i = 0; i < processedArguments.profilers.length; ++i) { const init = Module.cwrap('mono_wasm_load_profiler_' + processedArguments.profilers[i], 'void', ['string']); init(""); } if (processedArguments.applicationArgs.length == 0) { - fail_exec(1, "Missing required --run argument"); + set_exit_code(1, "Missing required --run argument"); return; } @@ -171,7 +179,7 @@ const App = { } if (res) - fail_exec(1, "REGRESSION TEST FAILED"); + set_exit_code(1, "REGRESSION TEST FAILED"); return; } @@ -182,31 +190,23 @@ const App = { if (processedArguments.applicationArgs[0] == "--run") { // Run an exe if (processedArguments.applicationArgs.length == 1) { - fail_exec(1, "Error: Missing main executable argument."); + set_exit_code(1, "Error: Missing main executable argument."); return; } + try { - const main_assembly_name = processedArguments.applicationArgs[1]; - const app_args = processedArguments.applicationArgs.slice(2); - INTERNAL.mono_wasm_set_main_args(processedArguments.applicationArgs[1], app_args); - - // Automatic signature isn't working correctly - const result = BINDING.call_assembly_entry_point(main_assembly_name, [app_args], "m"); - const onError = function (error) { - console.error(error); - if (error.stack) - console.error(error.stack); + const main_assembly_name = processedArguments.applicationArgs[1]; + const app_args = processedArguments.applicationArgs.slice(2); + INTERNAL.mono_wasm_set_main_args(processedArguments.applicationArgs[1], app_args); - fail_exec(1); - } - try { - result.then(fail_exec).catch(onError); + // Automatic signature isn't working correctly + const result = await BINDING.call_assembly_entry_point(main_assembly_name, [app_args], "m"); + set_exit_code(result); } catch (error) { - onError(error); + set_exit_code(1, error); } - } else { - fail_exec(1, "Unhandled argument: " + processedArguments.applicationArgs[0]); + set_exit_code(1, "Unhandled argument: " + processedArguments.applicationArgs[0]); } }, @@ -229,19 +229,41 @@ const App = { }; globalThis.App = App; // Necessary as System.Runtime.InteropServices.JavaScript.Tests.MarshalTests (among others) call the App.call_test_method directly -function fail_exec(exit_code, reason) { +function set_exit_code(exit_code, reason) { if (reason) { - console.error(reason); + console.error(reason.toString()); + if (reason.stack) { + console.error(reason.stack); + } } if (is_browser) { + const stack = (new Error()).stack.replace(/\n/g, "").replace(/[ ]*at/g, " at").replace(/https?:\/\/[0-9.:]*/g, "").replace("Error", ""); + const messsage = `Exit called with ${exit_code} when isXUnitDoneCheck=${isXUnitDoneCheck} ${stack}.`; + // Notify the selenium script Module.exit_code = exit_code; - originalConsole.log("WASM EXIT " + exit_code); + + //Tell xharness WasmBrowserTestRunner what was the exit code const tests_done_elem = document.createElement("label"); tests_done_elem.id = "tests_done"; tests_done_elem.innerHTML = exit_code.toString(); document.body.appendChild(tests_done_elem); - } else { // shell or node + + // need to flush streams (stdout/stderr) + for (const stream of Module.FS.streams) { + if (stream && stream.stream_ops && stream.stream_ops.flush) { + stream.stream_ops.flush(stream); + } + } + console.log("Flushed stdout!"); + + console.log('1 ' + messsage); + setTimeout(() => { + originalConsole.log('2 ' + messsage); + // tell xharness WasmTestMessagesProcessor we are done. + console.log("WASM EXIT " + exit_code); + }, 100); + } else if (INTERNAL) { INTERNAL.mono_wasm_exit(exit_code); } } @@ -262,7 +284,7 @@ function processArguments(incomingArguments) { const arg = currentArg.substring("--setenv=".length); const parts = arg.split('='); if (parts.length != 2) - fail_exec(1, "Error: malformed argument: '" + currentArg); + set_exit_code(1, "Error: malformed argument: '" + currentArg); setenv[parts[0]] = parts[1]; } else if (currentArg.startsWith("--runtime-arg=")) { const arg = currentArg.substring("--runtime-arg=".length); @@ -322,8 +344,10 @@ try { async function loadDotnet(file) { let loadScript = undefined; if (typeof WScript !== "undefined") { // Chakra - loadScript = WScript.LoadScriptFile; - return globalThis.Module; + loadScript = function (file) { + WScript.LoadScriptFile(file); + return globalThis.Module; + }; } else if (is_node) { // NodeJS loadScript = async function (file) { return require(file); @@ -333,7 +357,17 @@ async function loadDotnet(file) { const script = document.createElement("script"); script.src = file; document.head.appendChild(script); - return globalThis.Module; + let timeout = 100; + // bysy spin waiting for script to load into global namespace + while (timeout > 0) { + if (globalThis.Module) { + return globalThis.Module; + } + // delay 10ms + await new Promise(resolve => setTimeout(resolve, 10)); + timeout--; + } + throw new Error("Can't load " + file); } } else if (typeof globalThis.load !== 'undefined') { @@ -351,6 +385,6 @@ async function loadDotnet(file) { loadDotnet("./dotnet.js").catch(function (err) { console.error(err); - fail_exec(1, "failed to load the dotnet.js file"); + set_exit_code(1, "failed to load the dotnet.js file"); throw err; }); \ No newline at end of file diff --git a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs index bf6708d4268..f592f488327 100644 --- a/src/tasks/WasmAppBuilder/WasmAppBuilder.cs +++ b/src/tasks/WasmAppBuilder/WasmAppBuilder.cs @@ -174,12 +174,12 @@ private bool ExecuteInternal () if (!FileCopyChecked(item.ItemSpec, dest, "NativeAssets")) return false; } - FileCopyChecked(MainJS!, Path.Combine(AppDir, "runtime.js"), string.Empty); + FileCopyChecked(MainJS!, Path.Combine(AppDir, "main.js"), string.Empty); string indexHtmlPath = Path.Combine(AppDir, "index.html"); if (!File.Exists(indexHtmlPath)) { - var html = @""; + var html = @""; File.WriteAllText(indexHtmlPath, html); } diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs index b6fab5c6c43..cc4aa85a2c3 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/BuildTestBase.cs @@ -147,7 +147,7 @@ public BuildTestBase(ITestOutputHelper output, SharedBuildPerTestClassFixture bu string bundleDir = Path.Combine(GetBinDir(baseDir: buildDir, config: buildArgs.Config), "AppBundle"); (string testCommand, string extraXHarnessArgs) = host switch { - RunHost.V8 => ("wasm test", "--js-file=runtime.js --engine=V8 -v trace"), + RunHost.V8 => ("wasm test", "--js-file=main.js --engine=V8 -v trace"), _ => ("wasm test-browser", $"-v trace -b {host}") }; @@ -254,7 +254,7 @@ protected static void InitProjectDir(string dir) {s_targetFramework} Exe true - runtime-test.js + test-main.js ##EXTRA_PROPERTIES## @@ -310,7 +310,7 @@ protected static BuildArgs ExpandBuildArgs(BuildArgs buildArgs, string extraProp initProject?.Invoke(); File.WriteAllText(Path.Combine(_projectDir, $"{buildArgs.ProjectName}.csproj"), buildArgs.ProjectFileContents); - File.Copy(Path.Combine(AppContext.BaseDirectory, "runtime-test.js"), Path.Combine(_projectDir, "runtime-test.js")); + File.Copy(Path.Combine(AppContext.BaseDirectory, "test-main.js"), Path.Combine(_projectDir, "test-main.js")); } else if (_projectDir is null) { @@ -486,7 +486,7 @@ protected static void AssertBasicAppBundle(string bundleDir, string projectName, AssertFilesExist(bundleDir, new [] { "index.html", - "runtime.js", + "main.js", "dotnet.timezones.blat", "dotnet.wasm", "mono-config.json", diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/SatelliteAssembliesTests.cs b/src/tests/BuildWasmApps/Wasm.Build.Tests/SatelliteAssembliesTests.cs index c3a40b47020..3532028dcc4 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/SatelliteAssembliesTests.cs +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/SatelliteAssembliesTests.cs @@ -148,7 +148,7 @@ private void CreateProgramForCultureTest(string dir, string resourceName, string {s_targetFramework} Exe true - runtime-test.js + test-main.js ##EXTRA_PROPERTIES## diff --git a/src/tests/BuildWasmApps/Wasm.Build.Tests/Wasm.Build.Tests.csproj b/src/tests/BuildWasmApps/Wasm.Build.Tests/Wasm.Build.Tests.csproj index 0b05047a21f..7250c9e029d 100644 --- a/src/tests/BuildWasmApps/Wasm.Build.Tests/Wasm.Build.Tests.csproj +++ b/src/tests/BuildWasmApps/Wasm.Build.Tests/Wasm.Build.Tests.csproj @@ -27,7 +27,7 @@
- + diff --git a/src/tests/Common/Directory.Build.targets b/src/tests/Common/Directory.Build.targets index 009a19e92c7..e003e2dc6ec 100644 --- a/src/tests/Common/Directory.Build.targets +++ b/src/tests/Common/Directory.Build.targets @@ -155,7 +155,7 @@ TargetDir="wasm-test-runner/"/> $(TestAssemblyFileName) $(AppDir) - $(CORE_ROOT)\runtime-test\runtime-test.js + $(CORE_ROOT)\runtime-test\test-main.js true true true diff --git a/src/tests/Directory.Build.targets b/src/tests/Directory.Build.targets index 2866110fb4c..383ec392779 100644 --- a/src/tests/Directory.Build.targets +++ b/src/tests/Directory.Build.targets @@ -387,7 +387,7 @@ TargetDir="wasm-test-runner/"/> true WasmTestOnBrowser 42 - runtime.js + main.js false - + diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/index.html b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/index.html index 7832e37351d..8f85c8d7d8d 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/index.html +++ b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/index.html @@ -2,54 +2,41 @@ - - TESTS - - - - - - Result from Sample.Test.TestMeaning: - - + console.debug(`exit_code: ${exit_code}`); + set_exit_code(exit_code); + }, + }; + + + - + - - + \ No newline at end of file diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/runtime.js b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js similarity index 72% rename from src/tests/FunctionalTests/WebAssembly/Browser/HotReload/runtime.js rename to src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js index 065061d86b2..861ddd263cd 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/runtime.js +++ b/src/tests/FunctionalTests/WebAssembly/Browser/HotReload/main.js @@ -4,20 +4,19 @@ "use strict"; var Module = { - config: null, configSrc: "./mono-config.json", - onConfigLoaded: function () { + onConfigLoaded: () => { MONO.config.environment_variables["DOTNET_MODIFIABLE_ASSEMBLIES"] = "debug"; }, - onDotNetReady: function () { + onDotNetReady: () => { try { App.init(); } catch (error) { - test_exit(1); + set_exit_code(1, error); throw (error); } }, - onAbort: function () { - test_exit(1); + onAbort: (error) => { + set_exit_code(1, error); }, }; diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj index 35e9eec2cae..d9c7984051c 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj +++ b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj @@ -3,7 +3,7 @@ true WasmTestOnBrowser 42 - runtime.js + main.js diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/index.html b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/index.html index 2b618eaf31c..b8640040e73 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/index.html +++ b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/index.html @@ -2,54 +2,41 @@ - - TESTS - - - - - - Result from Sample.Test.TestMeaning: - - + console.debug(`exit_code: ${exit_code}`); + set_exit_code(exit_code); + }, + }; + + + - + - - + \ No newline at end of file diff --git a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/runtime.js b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js similarity index 71% rename from src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/runtime.js rename to src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js index 5c388258c85..88db9c67c1d 100644 --- a/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/runtime.js +++ b/src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/main.js @@ -4,17 +4,16 @@ "use strict"; var Module = { - config: null, configSrc: "./mono-config.json", - onDotNetReady: function () { + onDotNetReady: () => { try { App.init(); } catch (error) { - test_exit(1); + set_exit_code(1, error); throw (error); } }, - onAbort: function () { - test_exit(1); + onAbort: (error) => { + set_exit_code(1, error); }, }; -- GitLab